diff --git a/.github/skills/gfxgraph-development/SKILL.md b/.github/skills/gfxgraph-development/SKILL.md index d3cbde7..566db54 100644 --- a/.github/skills/gfxgraph-development/SKILL.md +++ b/.github/skills/gfxgraph-development/SKILL.md @@ -280,6 +280,26 @@ print(f"Avg replay: {s['avg_replay_us']:.1f} µs") - The monkey-patch itself (`enable`/`disable`): Thread-safe (one-time setup) - HIP Graph capture: Must be done on the thread that owns the CUDA stream +### Process-global capture serialization (multi-session / "2 LLMs in one process") + +On gfx1030/RDNA2, HIP stream-capture bookkeeping is **process-global** even with +`hipStreamCaptureModeThreadLocal`. Two sessions that capture graphs at the same time +corrupt each other's output (NaN) — a ROCm-runtime limitation, not a gfxGRAPH bug. + +gfxGRAPH guards this with one process-wide reader/writer gate in Rust +(`rs_gfxgraph_core::capture_gate`, surfaced as `rs_gfxgraph.CaptureLock` / `ReplayLock`): + +- **Capture → write lock (exclusive):** every capture site (`capture_begin`/`capture_end`, + the standard capture context, `ShapeBucketPool` lazy bucket capture, and each + `ConditionalGraph` branch) holds it, so only one capture runs at a time process-wide. +- **Replay → read lock (shared):** replays run fully concurrently; excluded only during the + brief one-time capture window. + +Net effect: multi-session capture is automatically safe — both models capture (serialized) +and replay (parallel) with no caller action. The gate releases the GIL while blocking and +no-ops on pure-Python installs (native extension absent). This is distinct from, and +complementary to, the per-runner `ReentrancyGuard` in `ConditionalGraphRunner`. + ## Version History - **v0.3.4** — Current. Pure-Python base install (native bridge via the `native/` companion + source Rust crates), per-branch memory pools, accurate structural fallback metrics, RDNA2 DeepSpeed-HIP + Triton kernels, dynamic-shape and adaptive-replay fixes. diff --git a/.jules/reports/benchmark_2026-06-16.json b/.jules/reports/benchmark_2026-06-16.json new file mode 100644 index 0000000..bb41f5e --- /dev/null +++ b/.jules/reports/benchmark_2026-06-16.json @@ -0,0 +1,82 @@ +{ + "timestamp_utc": "2026-06-16T13:30:46Z", + "commit_sha": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "run_count": 3, + "env": { + "torch": "2.13.0a0+git53bbebe", + "device": "AMD Radeon RX 6700 XT", + "rocm": { + "runtime_from_torch": "7.2.26015", + "driver_from_hipconfig": "7.2.26015-fc0010cf6a", + "runtime_from_rocminfo": "Runtime Version: 1.18" + }, + "env": { + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "PYTORCH_ROCM_ARCH": "gfx1030", + "GFXGRAPH": null, + "GFXGRAPH_VRAM_CAP": null, + "SGLANG_RDNA2_KERNELS": null, + "HIP_VISIBLE_DEVICES": null, + "CUDA_VISIBLE_DEVICES": null + } + }, + "results": [ + { + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024", + "iters": 2000, + "run_count": 3, + "eager_ms_per_iter": 0.1454837964993203, + "graph_ms_per_iter": 0.18561912199947983, + "eager_ms_per_iter_runs": [ + 0.14926297799866006, + 0.1454837964993203, + 0.14496194149978692 + ], + "graph_ms_per_iter_runs": [ + 0.18561912199947983, + 0.18482524499995634, + 0.18814137000117626 + ], + "speedup_x": 0.7837759112971562, + "fallback": true + }, + { + "workload": "mlp_bs32_d1024", + "iters": 1500, + "run_count": 3, + "eager_ms_per_iter": 0.10141401733320284, + "graph_ms_per_iter": 0.10106284666593031, + "eager_ms_per_iter_runs": [ + 0.09671573933398274, + 0.10141401733320284, + 0.10166068333152604 + ], + "graph_ms_per_iter_runs": [ + 0.10262902933512426, + 0.10100084866765731, + 0.10106284666593031 + ], + "speedup_x": 1.0034747751409907, + "fallback": true + }, + { + "workload": "mlp_bs128_d2048", + "iters": 300, + "run_count": 3, + "eager_ms_per_iter": 0.6040697966697431, + "graph_ms_per_iter": 0.6013785733375698, + "eager_ms_per_iter_runs": [ + 0.6040697966697431, + 0.6094511733317631, + 0.6013353733336165 + ], + "graph_ms_per_iter_runs": [ + 0.6013785733375698, + 0.6010160533332964, + 0.6156069300050149 + ], + "speedup_x": 1.0044750901536736, + "fallback": true + } + ] +} \ No newline at end of file diff --git a/.jules/verification/rusty/after-benchmark.json b/.jules/verification/rusty/after-benchmark.json new file mode 100644 index 0000000..4dc1e4b --- /dev/null +++ b/.jules/verification/rusty/after-benchmark.json @@ -0,0 +1,10 @@ +{ + "candidate": "python/hipgraph_bridge/conditional.py", + "implementation": "after", + "command": "python benchmarks/bench_conditional_mock.py", + "timestamp": "2026-05-08T00:00:00Z", + "iterations": 200000, + "input_description": "Alternating branch execution (mocked GPU)", + "duration_ms": 8096.94689099706, + "throughput": "24700.67 ops/sec" +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c11ae37..a30c12e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,39 @@ All notable changes to this project are documented in this file. +## [1.1.0] - 2026-06-21 + +### Fixed +- **Concurrent multi-session graph capture corruption on gfx1030/RDNA2**: when two + in-process LLM sessions captured CUDA/HIP graphs at the same time, output could come + back as NaN. Root cause is in the ROCm runtime, not gfxGRAPH: HIP stream-capture + bookkeeping is **process-global** even with `hipStreamCaptureModeThreadLocal`, so + concurrent captures clobber each other. gfxGRAPH now serializes capture process-wide + with a single Rust reader/writer gate (`rs_gfxgraph_core::capture_gate`, exposed as + `rs_gfxgraph.CaptureLock` / `ReplayLock`): **capture takes the write lock (one at a + time, excludes in-flight replay); replay takes the shared read lock (fully concurrent + across sessions).** Both LLMs still capture their graphs — just never simultaneously — + and replay stays parallel, so the high-level-capture value proposition is preserved. + The lock is acquired with the GIL released to avoid deadlock, and degrades to a no-op + when the native extension is absent (pure-Python install). Every capture site + (`capture_begin`/`capture_end`, the standard capture context, shape-bucket lazy capture, + and conditional-branch capture) is serialized; replay sites take the shared lock. + +## [rust-hip-cpp] - 2026-06-16 + +### Added +- **Integrated Rust-C++-HIP Launcher & Interposer**: + - Programmatic `HSA_OVERRIDE_GFX_VERSION=10.3.0` auto-injection on library initialization for AMD RDNA2 devices (gfx1030/gfx1031). + - Dynamically resolved CPU Core Complex (CCX) / L3 cache thread affinity pinning on AMD Zen CPUs (Ryzen 9 3900X) to eliminate Infinity Fabric thread-switching latency. + - Zero-allocation, AVX2-friendly loop contiguity verification and multidimensional offset computation inside `rs_gfxgraph_core` layout modules. + - Thread-safe RAII re-entrancy prevention guard (`ReentrancyGuard`) in `ConditionalGraphRunner` wrapper to cleanly route overlapping streams to safe eager fallbacks. + - Multi-symbol C++ CUDA compatibility interposer (`cuda_intercept.c`) with a native update-and-launch pipeline shortcut bypassing Python overhead. +- **Benchmarking & Testing Hardening**: + - Added new native C++/HIP test executable `test_routing.hip` to verify shape bucket selection and bounds checks directly on the GPU. + - Created `gfxgraph-benchmarking` skill to guide profiling, public benchmarking (`bench_readme_public.py`), and micro-benchmarking on ROCm. + - Authored a comprehensive `benchmarking-guide.md` covering the micro-benchmark suites, public GPU benchmark config, and provenance JSON schema. + - Patched `bench_routing.py` and `bench_conditional_mock.py` to support graceful mock-execution fallbacks on CPU/system environments. + ## [1.0.1] - 2026-06-16 ### Fixed diff --git a/CMakeLists.txt b/CMakeLists.txt index d188053..b01a315 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.21) project(gfxGRAPH VERSION 0.3.4 DESCRIPTION "CUDA Graph → HIP Graph translation layer for gfx1030 RDNA2" - LANGUAGES CXX HIP + LANGUAGES C CXX HIP ) include(CheckIPOSupported) @@ -17,9 +17,12 @@ find_package(hip REQUIRED) # ── Layer 1: Core bridge library ─────────────────────── add_library(hipgraph_bridge SHARED src/init.cpp + src/profiler.cpp + src/runtime_handles.cpp src/conditional_bridge.hip src/launch_pipeline.hip src/shape_manager.hip + src/decode_pool.hip src/capture_compositor.hip src/graph_utils.hip ) @@ -65,8 +68,16 @@ if(BUILD_CUDA_COMPAT) ) target_link_libraries(cudagraph_compat PRIVATE hipgraph_bridge + hip::amdhip64 ${CMAKE_DL_LIBS} ) + target_include_directories(cudagraph_compat PRIVATE + /opt/rocm/include + $ + ) + target_compile_definitions(cudagraph_compat PRIVATE + __HIP_PLATFORM_AMD__=1 + ) set_target_properties(cudagraph_compat PROPERTIES OUTPUT_NAME cudagraph_compat ) @@ -77,12 +88,20 @@ option(BUILD_TESTS "Build test executables" ON) if(BUILD_TESTS) enable_testing() - foreach(gap IN ITEMS conditional pipeline shapes compositor) + foreach(gap IN ITEMS conditional pipeline shapes compositor routing decode) add_executable(test_${gap} tests/test_${gap}.hip) target_link_libraries(test_${gap} PRIVATE hipgraph_bridge) add_test(NAME ${gap} COMMAND test_${gap}) endforeach() + add_executable(test_profiler tests/test_profiler.hip) + target_link_libraries(test_profiler PRIVATE hipgraph_bridge) + add_test(NAME profiler COMMAND test_profiler) + + add_executable(test_runtime_handles tests/test_runtime_handles.hip) + target_link_libraries(test_runtime_handles PRIVATE hipgraph_bridge) + add_test(NAME runtime_handles COMMAND test_runtime_handles) + if(BUILD_CUDA_COMPAT) add_test( NAME compat_smoke diff --git a/Cargo.lock b/Cargo.lock index e442edc..3308854 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,129 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "ar_archive_writer" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4087686b4b0a3427190bae57a1d9a478dbb2d40c5dc1bd6e2b6d797913bdd348" +dependencies = [ + "object 0.37.3", +] + +[[package]] +name = "arwen" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d44cbd9bd79165abe331ebabb9dd4d59a5dc93791be33ff15ebd71baaadc85ba" +dependencies = [ + "clap", + "goblin", + "object 0.38.1", + "scroll", + "thiserror 2.0.18", +] + +[[package]] +name = "arwen-codesign" +version = "0.0.1-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35d7a19757bfe3658d5a95bf25a0492f29ebb21933549bdbfa4075c895510124" +dependencies = [ + "goblin", + "scroll", + "sha2 0.10.9", + "tempfile", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "2.11.1" @@ -9,314 +132,4040 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] -name = "cfg-if" -version = "1.0.4" +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "borrow-or-share" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0b364ead1874514c8c2855ab558056ebfeb775653e7ae45ff72f28f8f3166c" + +[[package]] +name = "boxcar" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f64beae40a84da1b4b26ff2761a5b895c12adc41dc25aaee1c4f2bbfe97a6e" + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "bytesize" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e78e506b9d7633710dab98996f22f95f3d0f488e8f1aa162830556ed9fc14d" + +[[package]] +name = "bzip2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" +dependencies = [ + "libbz2-rs-sys", +] + +[[package]] +name = "cab" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171228650e6721d5acc0868a462cd864f49ac5f64e4a42cde270406e64e404d2" +dependencies = [ + "byteorder", + "flate2", + "lzxd", + "time", +] + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-config2" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ada53f7339c78084fb37d7e17f34e76537541c4fbb02fa3a2baa14b8faad37" +dependencies = [ + "serde", + "serde_derive", + "toml 1.1.2+spec-1.1.0", +] + +[[package]] +name = "cargo-cyclonedx" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d162f67705f0f5038759d73bf546a083bf30e8677c2e944b416bca48d9d69a8" +dependencies = [ + "anyhow", + "cargo-lock", + "cargo_metadata 0.18.1", + "clap", + "cyclonedx-bom", + "env_logger", + "log", + "once_cell", + "pathdiff", + "percent-encoding", + "purl", + "regex", + "serde", + "thiserror 2.0.18", + "time", + "validator", +] + +[[package]] +name = "cargo-lock" +version = "10.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06acb4f71407ba205a07cb453211e0e6a67b21904e47f6ba1f9589e38f2e454" +dependencies = [ + "semver", + "serde", + "toml 0.8.23", + "url", +] + +[[package]] +name = "cargo-options" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89e1d6d6f65fe04d5e21be9de19d31a074e3b7e43aa39ee5b85f4cee16c3188" +dependencies = [ + "anstyle", + "clap", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0061da739915fae12ea00e16397555ed4371a6bb285431aab930f61b0aa4ba" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "cargo-xwin" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c010a0e90e1dc09a90428c8768808bb4ad8cd7523e4df38719418e14579a9e37" +dependencies = [ + "anyhow", + "cargo-config2", + "cargo-options", + "clap", + "dirs", + "fs-err", + "humantime", + "indicatif", + "paste", + "path-slash", + "serde", + "tar", + "tracing-subscriber", + "ureq", + "which", + "xwin", + "xz2", +] + +[[package]] +name = "cargo-zigbuild" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418b19ee36a550c7c34a0bfd04e0b31d0dfb2c92f54aa36189ea3f2f85764845" +dependencies = [ + "anyhow", + "cargo-config2", + "cargo-options", + "cargo_metadata 0.23.1", + "clap", + "crc", + "dirs", + "fs-err", + "goblin", + "path-slash", + "rustc_version", + "rustflags", + "scroll", + "semver", + "serde", + "serde_json", + "shell-words", + "target-lexicon", + "which", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform 0.1.9", + "semver", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "cargo_metadata" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9" +dependencies = [ + "camino", + "cargo-platform 0.3.3", + "semver", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "cbindgen" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ecb53484c9c167ba674026b656d8a27d7657a58e6066aa902bfb1a4aa00ae20" +dependencies = [ + "heck", + "indexmap", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", + "tempfile", + "toml 0.9.12+spec-1.1.0", +] + +[[package]] +name = "cc" +version = "1.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a347dcabdae9c31b0825fd6a8bed285ec9c2acb89c47827126d52fa4f59cece3" +dependencies = [ + "fnv", + "uuid", + "web-time", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "charset" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f927b07c74ba84c7e5fe4db2baeb3e996ab2688992e39ac68ce3220a677c7e" +dependencies = [ + "base64", + "encoding_rs", +] + +[[package]] +name = "chumsky" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d2bfadce76f963d776feff99db6dc33783829539258314776383b33e2a00f8" +dependencies = [ + "hashbrown 0.15.5", + "regex-automata", + "serde", + "stacker", + "unicode-ident", + "unicode-segmentation", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_complete" +version = "4.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7a9bfdb35811f9e59832f0f05975114d2251b415fb534108e6f34060fd772" +dependencies = [ + "clap", +] + +[[package]] +name = "clap_complete_command" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da8e198c052315686d36371e8a3c5778b7852fc75cc313e4e11eeb7a644a1b62" +dependencies = [ + "clap", + "clap_complete", + "clap_complete_nushell", +] + +[[package]] +name = "clap_complete_nushell" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb9e9715d29a754b468591be588f6b926f5b0a1eb6a8b62acabeb66ff84d897" +dependencies = [ + "clap", + "clap_complete", +] + +[[package]] +name = "clap_derive" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "cli-table" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14da8d951cef7cc4f13ccc9b744d736963d57863c7e6fc33c070ea274546082c" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "configparser" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b46dec724fd22199ebde05033a0cbae453bc3b1ecff11eb6a6bb3eec4b90c6a4" + +[[package]] +name = "console" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +dependencies = [ + "encode_unicode", + "libc", + "unicode-width", + "windows-sys 0.61.2", +] + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b2c103cf610ec6cae3da84a766285b42fd16aad564758459e6ecf128c75206" +dependencies = [ + "cookie", + "document-features", + "idna", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "cyclonedx-bom" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3132b69ba8c13808bd2fa5748ac5b9816eb4f4e1f0bff6b7f9254a5940dcdeef" +dependencies = [ + "base64", + "cyclonedx-bom-macros", + "fluent-uri", + "indexmap", + "once_cell", + "ordered-float", + "purl", + "regex", + "serde", + "serde_json", + "spdx", + "strum", + "thiserror 2.0.18", + "time", + "uuid", + "xml-rs", +] + +[[package]] +name = "cyclonedx-bom-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50341f21df64b412b4f917e34b7aa786c092d64f3f905f478cb76950c7e980c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "dialoguer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f104b501bf2364e78d0d3974cbc774f738f5865306ed128e1e0d7499c0ad96" +dependencies = [ + "console", + "shell-words", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid", + "crypto-common 0.2.2", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fat-macho" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bed3960cfd332df43d86b2ae31bfed07a7b727a6170ae65dddc342775e810ca7" +dependencies = [ + "goblin", +] + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "fluent-uri" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc74ac4d8359ae70623506d512209619e5cf8f347124910440dbc221714b328e" +dependencies = [ + "borrow-or-share", + "ref-cast", + "serde", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs-err" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fde052dbfc920003cfd2c8e2c6e6d4cc7c1091538c3a24226cec0665ab08c0" +dependencies = [ + "autocfg", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "globset" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "goblin" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17582616a7718cca54cec18e534a76c7c4aec11a8b9a85695712f262fd15a4c8" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "http" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "ignore" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b915661dd01db3f05050265b2477bcc6527b3792388e2749b41623cc592be67d" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "indicatif" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" +dependencies = [ + "console", + "portable-atomic", + "unicode-width", + "unit-prefix", + "web-time", +] + +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lddtree" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39f71c5bd42adf4ee8e6b24da58c1f00a2817d27f618b169399f5adbf9e74492" +dependencies = [ + "fs-err", + "glob", + "goblin", + "memmap2", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libbz2-rs-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b357333733e8260735ba5894eb928c02ecc69c78715f01a8019e7fa7f2db4c" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libmimalloc-sys" +version = "0.1.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9" +dependencies = [ + "cc", +] + +[[package]] +name = "libredox" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +dependencies = [ + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" + +[[package]] +name = "lzma-rust2" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce716bf1a316f47a280fc76295f6495b5bea4752bca01c3b3885e101b1c23c02" +dependencies = [ + "sha2 0.11.0", +] + +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "lzxd" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b29dffab797218e12e4df08ef5d15ab9efca2504038b1b32b9b32fc844b39c9" + +[[package]] +name = "mailparse" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60819a97ddcb831a5614eb3b0174f3620e793e97e09195a395bfa948fd68ed2f" +dependencies = [ + "charset", + "data-encoding", + "quoted_printable", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "maturin" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758c1a1668f43fba9a2a284660deabeac7edd5c89257f6a1dad8f863d37a7d84" +dependencies = [ + "anyhow", + "arwen", + "arwen-codesign", + "base64", + "bytesize", + "cargo-config2", + "cargo-cyclonedx", + "cargo-options", + "cargo-xwin", + "cargo-zigbuild", + "cargo_metadata 0.23.1", + "cbindgen", + "cc", + "clap", + "clap_complete_command", + "configparser", + "console", + "dialoguer", + "dirs", + "dunce", + "fat-macho", + "flate2", + "fs-err", + "glob", + "goblin", + "ignore", + "indexmap", + "itertools 0.14.0", + "lddtree", + "memmap2", + "minijinja", + "normpath", + "once_cell", + "path-slash", + "pep440_rs", + "pep508_rs", + "platform-info", + "pyo3-introspection", + "pyproject-toml", + "python-pkginfo", + "reflink-copy", + "regex", + "rustc_version", + "rustflags", + "rustls", + "rustls-pki-types", + "same-file", + "semver", + "serde", + "serde_json", + "sha2 0.11.0", + "tar", + "target-lexicon", + "tempfile", + "textwrap", + "thiserror 2.0.18", + "time", + "toml 1.1.2+spec-1.1.0", + "toml_edit 0.25.12+spec-1.1.0", + "tracing", + "tracing-subscriber", + "unicode-xid", + "ureq", + "url", + "walkdir", + "which", + "wild", + "xz2", + "zip 8.6.0", +] + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + +[[package]] +name = "memo-map" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d1115007560874e373613744c6fba374c17688327a71c1476d1a5954cc857b" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mimalloc" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minijinja" +version = "2.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2929e494b2280e1e18959bb2e121da03347ae896896fdfaceaab43c88a02803f" +dependencies = [ + "memo-map", + "serde", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "msi" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0325f8473ef1f5c38ee42345e2cd1678299cbbfa169d1776654a2a682867420" +dependencies = [ + "byteorder", + "cfb", + "encoding_rs", + "uuid", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "normpath" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9985ef7269fa99f3b12437bb698381da2428743ab90f20393f399fa14cab21a" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" +version = "0.38.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271638cd5fa9cca89c4c304675ca658efc4e64a66c716b7cfe1afb4b9611dbbc" +dependencies = [ + "crc32fast", + "flate2", + "hashbrown 0.16.1", + "indexmap", + "memchr", + "ruzstd", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +dependencies = [ + "camino", +] + +[[package]] +name = "pep440_rs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31095ca1f396e3de32745f42b20deef7bc09077f918b085307e8eab6ddd8fb9c" +dependencies = [ + "once_cell", + "serde", + "tracing", + "unicode-width", + "unscanny", + "version-ranges", +] + +[[package]] +name = "pep508_rs" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faee7227064121fcadcd2ff788ea26f0d8f2bd23a0574da11eca23bc935bcc05" +dependencies = [ + "boxcar", + "indexmap", + "itertools 0.13.0", + "once_cell", + "pep440_rs", + "regex", + "rustc-hash", + "serde", + "smallvec", + "thiserror 1.0.69", + "tracing", + "unicode-width", + "url", + "urlencoding", + "version-ranges", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", + "unicase", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", + "unicase", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "platform-info" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9368d62437c8cbb7c31ee37fd8c08a7d390e09a3ff75698a674953f46705ffcb" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761ea" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "purl" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60ebe4262ae91ddd28c8721111a0a6e9e58860e211fc92116c4bb85c98fd96ad" +dependencies = [ + "hex", + "percent-encoding", + "phf", + "thiserror 2.0.18", + "unicase", +] + +[[package]] +name = "pyo3" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5203598f366b11a02b13aa20cab591229ff0a89fd121a308a5df751d5fc9219" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99636d423fa2ca130fa5acde3059308006d46f98caac629418e53f7ebb1e9999" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78f9cf92ba9c409279bc3305b5409d90db2d2c22392d443a87df3a1adad59e33" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-introspection" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96040524552ac54e645ce08146b24023d720ceb0e788fff758c0beb9fe841736" +dependencies = [ + "anyhow", + "goblin", + "serde", + "serde_json", +] + +[[package]] +name = "pyo3-macros" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b999cb1a6ce21f9a6b147dcf1be9ffedf02e0043aec74dc390f3007047cecd9" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "822ece1c7e1012745607d5cf0bcb2874769f0f7cb34c4cde03b9358eb9ef911a" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn", +] + +[[package]] +name = "pyproject-toml" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d755483ad14b49e76713b52285235461a5b4f73f17612353e11a5de36a5fd2" +dependencies = [ + "glob", + "indexmap", + "pep440_rs", + "pep508_rs", + "serde", + "thiserror 2.0.18", + "toml 0.9.12+spec-1.1.0", +] + +[[package]] +name = "python-pkginfo" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229fe47647d6602b9b0934b21fab8aece1c5a5aeb0a934196a14355fec656623" +dependencies = [ + "flate2", + "fs-err", + "mailparse", + "rfc2047-decoder", + "tar", + "thiserror 2.0.18", + "zip 8.6.0", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "quoted_printable" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478e0585659a122aa407eb7e3c0e1fa51b1d8a870038bd29f0cf4a8551eea972" + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "reflink-copy" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13362233b147e57674c37b802d216b7c5e3dcccbed8967c84f0d8d223868ae27" +dependencies = [ + "cfg-if", + "libc", + "rustix", + "windows", +] + +[[package]] +name = "regex" +version = "1.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rfc2047-decoder" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b36447d5e70933adee73cefff22b0851edbc162f2b3951918de43717a22d92de" +dependencies = [ + "base64", + "charset", + "chumsky", + "memchr", + "quoted_printable", + "thiserror 2.0.18", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rs_gfxgraph" +version = "0.1.0" +dependencies = [ + "libc", + "maturin", + "pyo3", + "rs_gfxgraph_core", +] + +[[package]] +name = "rs_gfxgraph_bench" +version = "0.1.0" +dependencies = [ + "clap", + "rs_gfxgraph_core", + "rs_gfxgraph_native", + "serde", + "serde_json", +] + +[[package]] +name = "rs_gfxgraph_core" +version = "0.1.0" +dependencies = [ + "parking_lot", + "serde", + "serde_json", +] + +[[package]] +name = "rs_gfxgraph_native" +version = "0.1.0" +dependencies = [ + "libc", + "serde_json", +] + +[[package]] +name = "rs_gfxgraph_stats" +version = "0.1.0" +dependencies = [ + "dashmap", + "lazy_static", + "maturin", + "pyo3", +] + +[[package]] +name = "rs_gfxgraph_toolbox" +version = "0.1.0" +dependencies = [ + "rs_gfxgraph_core", + "serde", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustflags" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a39e0e9135d7a7208ee80aa4e3e4b88f0f5ad7be92153ed70686c38a03db2e63" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ruzstd" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c1c839d570d835527c9a5e4db7cb2198683a988cb9d7293fc8674e6bd58fc8" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scroll" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "smawk" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8e2fb0f499abb4d162f2bedad68f5ef91a1682b5a03596ddb67efd37768d100" + +[[package]] +name = "socks" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b" +dependencies = [ + "byteorder", + "libc", + "winapi", +] + +[[package]] +name = "spdx" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8da593e30beb790fc9424502eb898320b44e5eb30367dbda1c1edde8e2f32d7" +dependencies = [ + "smallvec", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stacker" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.61.2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" +dependencies = [ + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711a53c2d47bbd818258c498c8dbfe186a2526c631495cfe7e078567f86b8469" +dependencies = [ + "deranged", + "js-sys", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c652a3727a9cbb9a02f707f530b618ce00d0ccd762009c8c23bd191df3c17d" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.3", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.3", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.3", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" + +[[package]] +name = "typed-path" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unindent" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" + +[[package]] +name = "unit-prefix" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" + +[[package]] +name = "unscanny" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9df2af067a7953e9c3831320f35c1cc0600c30d44d9f7a12b01db1cd88d6b47" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" +dependencies = [ + "base64", + "cookie_store", + "flate2", + "getrandom 0.4.2", + "log", + "mime_guess", + "percent-encoding", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "socks", + "ureq-proto", + "utf8-zero", + "webpki-roots", +] + +[[package]] +name = "ureq-proto" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" +dependencies = [ + "base64", + "http", + "httparse", + "log", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "validator" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0b4a29d8709210980a09379f27ee31549b73292c87ab9899beee1c0d3be6303" +dependencies = [ + "idna", + "once_cell", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version-ranges" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e9bd4e9c9ff6a2a9b5969462ba26216af3e010df0377dad8320ab515262ef8" +dependencies = [ + "smallvec", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "versions" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80a7e511ce1795821207a837b7b1c8d8aca0c648810966ad200446ae58f6667f" +dependencies = [ + "itertools 0.14.0", + "nom", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "which" +version = "8.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c789537cf2f7f55be8e6192f92e464174ee55f91af622777f7f1ceb0dbccd03e" +dependencies = [ + "libc", +] + +[[package]] +name = "wild" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3131afc8c575281e1e80f36ed6a092aa502c08b18ed7524e86fbbb12bb410e1" +dependencies = [ + "glob", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] [[package]] -name = "crossbeam-utils" -version = "0.8.21" +name = "windows-strings" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] [[package]] -name = "dashmap" -version = "6.1.0" +name = "windows-sys" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown", - "lock_api", - "once_cell", - "parking_lot_core", + "windows-targets 0.42.2", ] [[package]] -name = "hashbrown" -version = "0.14.5" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] [[package]] -name = "heck" -version = "0.5.0" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] [[package]] -name = "itoa" -version = "1.0.18" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "windows-targets" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] [[package]] -name = "libc" -version = "0.2.186" +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] [[package]] -name = "lock_api" -version = "0.4.14" +name = "windows-threading" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "scopeguard", + "windows-link", ] [[package]] -name = "memchr" -version = "2.8.2" +name = "windows_aarch64_gnullvm" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] -name = "once_cell" -version = "1.21.4" +name = "windows_aarch64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "parking_lot" -version = "0.12.5" +name = "windows_aarch64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] -name = "parking_lot_core" -version = "0.9.12" +name = "windows_aarch64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "portable-atomic" -version = "1.13.1" +name = "windows_i686_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] -name = "proc-macro2" -version = "1.0.106" +name = "windows_i686_gnu" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ - "unicode-ident", + "memchr", ] [[package]] -name = "pyo3" -version = "0.29.0" +name = "winnow" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" dependencies = [ - "libc", - "once_cell", - "portable-atomic", - "pyo3-build-config", - "pyo3-ffi", - "pyo3-macros", + "memchr", ] [[package]] -name = "pyo3-build-config" -version = "0.29.0" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ - "target-lexicon", + "wit-bindgen-rust-macro", ] [[package]] -name = "pyo3-ffi" -version = "0.29.0" +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" dependencies = [ - "libc", - "pyo3-build-config", + "anyhow", + "heck", + "wit-parser", ] [[package]] -name = "pyo3-macros" -version = "0.29.0" +name = "wit-bindgen-rust" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ - "proc-macro2", - "pyo3-macros-backend", - "quote", + "anyhow", + "heck", + "indexmap", + "prettyplease", "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", ] [[package]] -name = "pyo3-macros-backend" -version = "0.29.0" +name = "wit-bindgen-rust-macro" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" dependencies = [ - "heck", + "anyhow", + "prettyplease", "proc-macro2", "quote", "syn", + "wit-bindgen-core", + "wit-bindgen-rust", ] [[package]] -name = "quote" -version = "1.0.45" +name = "wit-component" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ - "proc-macro2", + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", ] [[package]] -name = "redox_syscall" -version = "0.5.18" +name = "wit-parser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ - "bitflags", + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", ] [[package]] -name = "rs_gfxgraph" -version = "0.1.0" +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ - "pyo3", + "libc", + "rustix", ] [[package]] -name = "rs_gfxgraph_core" -version = "0.1.0" +name = "xml-rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" + +[[package]] +name = "xwin" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c337699251ad0c38cf87ee63944de38c2201d017cfbb768e5a3897ae835aacc7" dependencies = [ + "anyhow", + "bytes", + "cab", + "camino", + "clap", + "cli-table", + "crossbeam-channel", + "indicatif", + "memchr", + "mimalloc", + "msi", "parking_lot", + "rayon", + "regex", "serde", "serde_json", + "sha2 0.11.0", + "tempfile", + "toml 1.1.2+spec-1.1.0", + "tracing", + "tracing-subscriber", + "twox-hash", + "ureq", + "versions", + "walkdir", + "zip 7.2.0", ] [[package]] -name = "rs_gfxgraph_stats" -version = "0.1.0" +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" dependencies = [ - "dashmap", - "lazy_static", - "pyo3", + "lzma-sys", ] [[package]] -name = "rs_gfxgraph_toolbox" -version = "0.1.0" +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ - "rs_gfxgraph_core", - "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", ] [[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "serde" -version = "1.0.228" +name = "yoke-derive" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ - "serde_core", - "serde_derive", + "proc-macro2", + "quote", + "syn", + "synstructure", ] [[package]] -name = "serde_core" -version = "1.0.228" +name = "zerofrom" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ - "serde_derive", + "zerofrom-derive", ] [[package]] -name = "serde_derive" -version = "1.0.228" +name = "zerofrom-derive" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", "syn", + "synstructure", ] [[package]] -name = "serde_json" -version = "1.0.150" +name = "zeroize" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", + "displaydoc", + "yoke", + "zerofrom", ] [[package]] -name = "smallvec" -version = "1.15.1" +name = "zerovec" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] [[package]] -name = "syn" -version = "2.0.117" +name = "zerovec-derive" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "unicode-ident", + "syn", ] [[package]] -name = "target-lexicon" -version = "0.13.5" +name = "zip" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" +checksum = "c42e33efc22a0650c311c2ef19115ce232583abbe80850bc8b66509ebef02de0" +dependencies = [ + "crc32fast", + "flate2", + "indexmap", + "memchr", + "typed-path", +] [[package]] -name = "unicode-ident" -version = "1.0.24" +name = "zip" +version = "8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" +dependencies = [ + "bzip2", + "crc32fast", + "flate2", + "indexmap", + "lzma-rust2", + "memchr", + "time", + "typed-path", + "zopfli", + "zstd", +] [[package]] -name = "windows-link" -version = "0.2.1" +name = "zlib-rs" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" [[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index b4537da..b1f5aee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,9 @@ resolver = "2" members = [ "rust/rs_gfxgraph", + "rust/rs_gfxgraph_bench", "rust/rs_gfxgraph_core", + "rust/rs_gfxgraph_native", "rust/rs_gfxgraph_stats", "rust/rs_gfxgraph_toolbox", ] diff --git a/README.md b/README.md index 1c83b1d..d02862d 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,18 @@ gfxgraph.torch_rocm_status() # {is_rocm, torch_version, hip_version, message} gfxgraph.should_convert(block_threads, grid_blocks) # (apply, reason) — collision-safe gate ``` +## Concurrent multi-session (two LLMs in one process) + +On gfx1030/RDNA2, HIP stream-capture bookkeeping is **process-global** even with +`hipStreamCaptureModeThreadLocal` — so if two in-process sessions capture graphs at the +same time, output can come back as NaN. That's a ROCm-runtime limitation, not a gfxGRAPH +bug. gfxGRAPH handles it transparently: capture is **serialized process-wide** by a Rust +lock (`CaptureLock`, write-exclusive), while replay stays **fully concurrent** +(`ReplayLock`, shared). Both models capture their graphs — just never simultaneously — and +replay in parallel, so you keep high-level capture for every session with **no code +changes**. The lock releases the GIL while waiting and no-ops on pure-Python (Tier 1) +installs. + ## CLI (`gfxgraph …`) The diagnostics are framework-agnostic, so the CLI helps users of **any** engine: diff --git a/benchmarks/bench_conditional_mock.py b/benchmarks/bench_conditional_mock.py index adb79da..0781b29 100644 --- a/benchmarks/bench_conditional_mock.py +++ b/benchmarks/bench_conditional_mock.py @@ -20,8 +20,9 @@ def is_contiguous(self): return True mock_torch.Tensor = MockTensor -mock_torch.__mock__ = True sys.modules['torch'] = mock_torch +import hipgraph_bridge.capture_safety +hipgraph_bridge.capture_safety.torch_cuda_execution_probe = lambda: (True, "mocked") from hipgraph_bridge.conditional import ConditionalGraph diff --git a/benchmarks/bench_routing.py b/benchmarks/bench_routing.py index acf8c53..4801eba 100644 --- a/benchmarks/bench_routing.py +++ b/benchmarks/bench_routing.py @@ -9,9 +9,12 @@ sys.modules["torch"] = mock_torch sys.modules["torch.cuda"] = mock_torch.cuda -import rs_gfxgraph -_HAS_RUST_EXT = False -sys.modules["rs_gfxgraph"] = MagicMock() +try: + import rs_gfxgraph + _HAS_RUST_EXT = True +except ImportError: + _HAS_RUST_EXT = False + sys.modules["rs_gfxgraph"] = MagicMock() from hipgraph_bridge.shape_bucketing import ShapeBucketPool diff --git a/benchmarks/benchmark_pipeline.hip b/benchmarks/benchmark_pipeline.hip index 239dad2..70d0581 100644 --- a/benchmarks/benchmark_pipeline.hip +++ b/benchmarks/benchmark_pipeline.hip @@ -6,12 +6,25 @@ #include #include #include +#include __global__ void inc_kernel(float* data, int n) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < n) data[idx] += 1.0f; } +__global__ void clock_probe_kernel(unsigned long long* out) { + unsigned long long start = clock64(); + float acc = 0.0f; + for (int i = 0; i < 256; ++i) { + acc += (float)i * 0.0001f; + } + unsigned long long end = clock64(); + if (threadIdx.x == 0 && blockIdx.x == 0) { + out[0] = end - start + (unsigned long long)acc; + } +} + int main() { constexpr int N = 1024; constexpr int WARMUP = 100; @@ -77,10 +90,33 @@ int main() { double total_us = std::chrono::duration_cast(end - start).count(); double avg_us = total_us / ITERS; + unsigned long long* d_cycles = nullptr; + unsigned long long h_cycles = 0; + hipMalloc(&d_cycles, sizeof(unsigned long long)); + clock_probe_kernel<<<1, 64>>>(d_cycles); + hipMemcpy(&h_cycles, d_cycles, sizeof(unsigned long long), hipMemcpyDeviceToHost); + hipFree(d_cycles); + hgb_profiler_record( + HGB_PROFILE_EVENT_DEVICE_CLOCK_PROBE, + 0, + (uint64_t)h_cycles, + 256 + ); + + hgb_profile_counters_t counters{}; + hgb_profile_sample_t samples[16]; + size_t sample_count = hgb_profiler_snapshot(samples, 16, &counters); + std::printf("=== benchmark_pipeline ===\n"); std::printf("Warmup launches: %d\n", WARMUP); std::printf("Measured launches: %d\n", ITERS); std::printf("Average pipeline launch latency: %.2f us\n", avg_us); + std::printf("Device clock64 probe cycles: %llu\n", h_cycles); + std::printf("Profiler samples copied: %zu\n", sample_count); + std::printf("Profiler events written: %llu\n", + (unsigned long long)counters.written); + std::printf("Profiler events dropped: %llu\n", + (unsigned long long)counters.dropped); hgb_pipeline_destroy(&pipe); hipGraphDestroy(graph); diff --git a/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-clean-candidate-main-python-baseline-rust-hip-cpp-20260616.json b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-clean-candidate-main-python-baseline-rust-hip-cpp-20260616.json new file mode 100644 index 0000000..96edbab --- /dev/null +++ b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-clean-candidate-main-python-baseline-rust-hip-cpp-20260616.json @@ -0,0 +1,459 @@ +{ + "schema_version": "gfxgraph-benchmark-v1", + "report_kind": "benchmark_gate_phase_report", + "run_id": "main-python-baseline-rust-hip-cpp-20260616", + "phase": "clean-candidate", + "timestamp_utc": "2026-06-16T14:32:53Z", + "report_date": "2026-06-16", + "schema_path": "benchmarks/schemas/gfxgraph-benchmark-v1.schema.json", + "repo": { + "root": "/home/local/ai/projects/gfxGRAPH", + "branch": "rust-hip-cpp", + "commit": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "tracked_dirty": true + }, + "environment": { + "os": "Linux FRACTAL 6.8.0-90-generic #91-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 18 14:14:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux", + "rocm_path": "/opt/rocm", + "hipcc_version": "HIP version: 7.2.26015-fc0010cf6a\nAMD clang version 22.0.0git (https://github.com/RadeonOpenCompute/llvm-project roc-7.2.0 26014 7b800a19466229b8479a78de19143dc33c3ab9b5)\nTarget: x86_64-unknown-linux-gnu\nThread model: posix\nInstalledDir: /opt/rocm-7.2.0/lib/llvm/bin\nConfiguration file: /opt/rocm-7.2.0/lib/llvm/bin/clang++.cfg", + "env": { + "GFXGRAPH": null, + "GFXGRAPH_VALIDATE": null, + "GFXGRAPH_VRAM_CAP": null, + "HIP_VISIBLE_DEVICES": null, + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "ROCM_PATH": "/opt/rocm" + } + }, + "python": { + "executable": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python", + "imports": [ + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH" + }, + "distribution": "gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/python/gfxgraph/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/python/gfxgraph" + ], + "version": "1.0.1" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH" + }, + "distribution": "gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "hipgraph_bridge", + "origin": "/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge" + ], + "version": "1.0.1" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH/native" + }, + "distribution": "gfxgraph-native", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "gfxgraph_native", + "origin": "/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native" + ], + "version": "0.3.3" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph" + }, + "distribution": "rs-gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "rs_gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph" + ], + "version": "0.1.0" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph_stats" + }, + "distribution": "rs-gfxgraph-stats", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "rs_gfxgraph_stats", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats" + ], + "version": "0.1.0" + } + ], + "prefix": "/home/local/ai/projects/gfxGRAPH/.venv", + "version": "3.12.7 (main, Oct 16 2024, 04:37:19) [Clang 18.1.8 ]" + }, + "package_state": { + "target_import_policy": "repo", + "graph_enabled": false, + "allow_package_changes": true, + "package_actions": [ + { + "name": "uv-uninstall-installed-python-packages", + "command": "uv pip uninstall --python /home/local/ai/projects/gfxGRAPH/.venv/bin/python gfxgraph gfxgraph-native rs-gfxgraph rs-gfxgraph-stats", + "status": "passed", + "duration_ms": 17.757520999999997, + "exit_code": 0, + "stdout_tail": "", + "stderr_tail": "warning: Skipping rs-gfxgraph as it is not installed\nwarning: Skipping rs-gfxgraph-stats as it is not installed\nUninstalled 2 packages in 2ms\n - gfxgraph==1.0.1 (from file:///home/local/ai/projects/gfxGRAPH/dist/gfxgraph-1.0.1-py3-none-any.whl)\n - gfxgraph-native==0.3.3 (from file:///home/local/ai/projects/gfxGRAPH/native)\n" + }, + { + "name": "uv-install-candidate-gfxgraph", + "command": "uv pip install --python /home/local/ai/projects/gfxGRAPH/.venv/bin/python --no-deps -e /home/local/ai/projects/gfxGRAPH", + "status": "passed", + "duration_ms": 1284.075794, + "exit_code": 0, + "stdout_tail": "", + "stderr_tail": "Resolved 1 package in 1ms\n Building gfxgraph @ file:///home/local/ai/projects/gfxGRAPH\n Built gfxgraph @ file:///home/local/ai/projects/gfxGRAPH\nPrepared 1 package in 1.18s\nwarning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.\n If the cache and target directories are on different filesystems, hardlinking may not be supported.\n If this is intentional, set `export UV_LINK_MODE=copy` or use `--link-mode=copy` to suppress this warning.\nInstalled 1 package in 5ms\n + gfxgraph==1.0.1 (from file:///home/local/ai/projects/gfxGRAPH)\n" + }, + { + "name": "uv-install-candidate-gfxgraph-native", + "command": "uv pip install --python /home/local/ai/projects/gfxGRAPH/.venv/bin/python --no-deps -e /home/local/ai/projects/gfxGRAPH/native", + "status": "passed", + "duration_ms": 4483.694794, + "exit_code": 0, + "stdout_tail": "", + "stderr_tail": "Resolved 1 package in 1ms\n Building gfxgraph-native @ file:///home/local/ai/projects/gfxGRAPH/native\n Built gfxgraph-native @ file:///home/local/ai/projects/gfxGRAPH/native\nPrepared 1 package in 4.34s\nwarning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.\n If the cache and target directories are on different filesystems, hardlinking may not be supported.\n If this is intentional, set `export UV_LINK_MODE=copy` or use `--link-mode=copy` to suppress this warning.\nInstalled 1 package in 3ms\n + gfxgraph-native==0.3.3 (from file:///home/local/ai/projects/gfxGRAPH/native)\n" + }, + { + "name": "maturin-develop-rs-gfxgraph-uv", + "command": "maturin develop --uv --release", + "status": "passed", + "duration_ms": 1112.690589, + "exit_code": 0, + "stdout_tail": "✏️ Setting installed package as editable\n", + "stderr_tail": "🐍 Found CPython 3.12 at /home/local/ai/projects/gfxGRAPH/.venv/bin/python\n🔗 Found pyo3 bindings\n Finished `release` profile [optimized] target(s) in 0.13s\n📦 Built wheel for CPython 3.12 to /tmp/.tmpWZEQa6/rs_gfxgraph-0.1.0-cp312-cp312-linux_x86_64.whl\n🛠 Installed rs_gfxgraph-0.1.0\n" + }, + { + "name": "maturin-develop-rs-gfxgraph-stats-uv", + "command": "maturin develop --uv --release", + "status": "passed", + "duration_ms": 1066.202192, + "exit_code": 0, + "stdout_tail": "✏️ Setting installed package as editable\n", + "stderr_tail": "🐍 Found CPython 3.12 at /home/local/ai/projects/gfxGRAPH/.venv/bin/python\n🔗 Found pyo3 bindings\n Finished `release` profile [optimized] target(s) in 0.13s\n📦 Built wheel for CPython 3.12 to /tmp/.tmpGAAb0U/rs_gfxgraph_stats-0.1.0-cp312-cp312-linux_x86_64.whl\n🛠 Installed rs_gfxgraph_stats-0.1.0\n" + } + ] + }, + "gate_checks": [ + { + "name": "candidate-package-transition", + "status": "passed", + "message": "UV package uninstall/install transition completed", + "details": { + "actions": [ + { + "exit_code": 0, + "name": "uv-uninstall-installed-python-packages", + "status": "passed" + }, + { + "exit_code": 0, + "name": "uv-install-candidate-gfxgraph", + "status": "passed" + }, + { + "exit_code": 0, + "name": "uv-install-candidate-gfxgraph-native", + "status": "passed" + }, + { + "exit_code": 0, + "name": "maturin-develop-rs-gfxgraph-uv", + "status": "passed" + }, + { + "exit_code": 0, + "name": "maturin-develop-rs-gfxgraph-stats-uv", + "status": "passed" + } + ] + } + }, + { + "name": "python-import-isolation", + "status": "passed", + "message": "clean-candidate imports match repo policy", + "details": { + "checked": [ + { + "importable": true, + "in_repo": true, + "module": "gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/python/gfxgraph/__init__.py" + }, + { + "importable": true, + "in_repo": true, + "module": "hipgraph_bridge", + "origin": "/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge/__init__.py" + }, + { + "importable": true, + "in_repo": true, + "module": "gfxgraph_native", + "origin": "/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native/__init__.py" + } + ] + } + } + ], + "benchmarks": [ + { + "name": "python-import-provenance", + "kind": "package-provenance", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python -c ", + "iterations": null, + "duration_ms": 75.50449400000001, + "throughput_ops_per_sec": null, + "stdout_tail": "{\"executable\": \"/home/local/ai/projects/gfxGRAPH/.venv/bin/python\", \"imports\": [{\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH\"}, \"distribution\": \"gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"gfxgraph\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/python/gfxgraph/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/python/gfxgraph\"], \"version\": \"1.0.1\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH\"}, \"distribution\": \"gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"hipgraph_bridge\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge\"], \"version\": \"1.0.1\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/native\"}, \"distribution\": \"gfxgraph-native\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"gfxgraph_native\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native\"], \"version\": \"0.3.3\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph\"}, \"distribution\": \"rs-gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"rs_gfxgraph\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph\"], \"version\": \"0.1.0\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph_stats\"}, \"distribution\": \"rs-gfxgraph-stats\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"rs_gfxgraph_stats\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats\"], \"version\": \"0.1.0\"}], \"prefix\": \"/home/local/ai/projects/gfxGRAPH/.venv\", \"version\": \"3.12.7 (main, Oct 16 2024, 04:37:19) [Clang 18.1.8 ]\"}\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "torch-capture-policy", + "kind": "capture-policy", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python -c ", + "iterations": null, + "duration_ms": 17950.455119000002, + "throughput_ops_per_sec": null, + "stdout_tail": "{\"GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE\": null, \"cuda_available\": true, \"cuda_execution_error\": \"CUDA execution probe passed\", \"cuda_execution_usable\": true, \"device\": \"AMD Radeon RX 6700 XT\", \"torch\": \"2.13.0a0+git53bbebe\", \"torch_graph_capture_block_reason\": \"high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in\", \"torch_hip\": \"7.2.26015\", \"unsafe_torch_graph_capture_enabled\": false}\n", + "stderr_tail": "", + "metrics": { + "probe": { + "GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE": null, + "cuda_available": true, + "cuda_execution_error": "CUDA execution probe passed", + "cuda_execution_usable": true, + "device": "AMD Radeon RX 6700 XT", + "torch": "2.13.0a0+git53bbebe", + "torch_graph_capture_block_reason": "high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in", + "torch_hip": "7.2.26015", + "unsafe_torch_graph_capture_enabled": false + } + } + }, + { + "name": "rust-bucket-router-core", + "kind": "rust-micro", + "status": "passed", + "command": "in-process BucketRouterCore::route loop", + "iterations": 200000, + "duration_ms": 55.930146, + "throughput_ops_per_sec": 3575889.1099622734, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "bucket_count": 10, + "ready_routes": 200000 + } + }, + { + "name": "rust-stats-sample-update", + "kind": "rust-micro", + "status": "passed", + "command": "in-process GfxGraphStatsSample update loop", + "iterations": 200000, + "duration_ms": 1.354011, + "throughput_ops_per_sec": 147709287.4430119, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "failures": 196, + "samples": 200000 + } + }, + { + "name": "native-hip-benchmark", + "kind": "hip-native", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/build/benchmark_pipeline", + "iterations": null, + "duration_ms": 405.834045, + "throughput_ops_per_sec": null, + "stdout_tail": "=== benchmark_pipeline ===\nWarmup launches: 100\nMeasured launches: 10000\nAverage pipeline launch latency: 26.14 us\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "native-hip-tests", + "kind": "hip-native", + "status": "passed", + "command": "ctest --test-dir /home/local/ai/projects/gfxGRAPH/build --output-on-failure", + "iterations": null, + "duration_ms": 1297.467784, + "throughput_ops_per_sec": null, + "stdout_tail": "Test project /home/local/ai/projects/gfxGRAPH/build\n Start 1: conditional\n1/5 Test #1: conditional ...................... Passed 0.17 sec\n Start 2: pipeline\n2/5 Test #2: pipeline ......................... Passed 0.16 sec\n Start 3: shapes\n3/5 Test #3: shapes ........................... Passed 0.30 sec\n Start 4: compositor\n4/5 Test #4: compositor ....................... Passed 0.32 sec\n Start 5: routing\n5/5 Test #5: routing .......................... Passed 0.23 sec\n\n100% tests passed, 0 tests failed out of 5\n\nTotal Test time (real) = 1.18 sec\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "readme-public-benchmark", + "kind": "python-public", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python benchmarks/bench_readme_public.py --output benchmarks/results/2026-06-16/readme-public-clean-candidate-main-python-baseline-rust-hip-cpp-20260616.json --run-count 3", + "iterations": null, + "duration_ms": 13850.113422, + "throughput_ops_per_sec": null, + "stdout_tail": "{\n \"timestamp_utc\": \"2026-06-16T14:34:49Z\",\n \"commit_sha\": \"fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e\",\n \"run_count\": 3,\n \"env\": {\n \"torch\": \"2.13.0a0+git53bbebe\",\n \"device\": \"AMD Radeon RX 6700 XT\",\n \"rocm\": {\n \"runtime_from_torch\": \"7.2.26015\",\n \"driver_from_hipconfig\": \"7.2.26015-fc0010cf6a\",\n \"runtime_from_rocminfo\": \"Runtime Version: 1.18\"\n },\n \"env\": {\n \"HSA_OVERRIDE_GFX_VERSION\": \"10.3.0\",\n \"PYTORCH_ROCM_ARCH\": null,\n \"GFXGRAPH\": null,\n \"GFXGRAPH_VRAM_CAP\": null,\n \"SGLANG_RDNA2_KERNELS\": null,\n \"HIP_VISIBLE_DEVICES\": null,\n \"CUDA_VISIBLE_DEVICES\": null\n }\n },\n \"results\": [\n {\n \"workload\": \"decode_like_layernorm_gelu_chain_bs1_d1024\",\n \"iters\": 2000,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.15820250050092,\n \"graph_ms_per_iter\": 0.19302421149950533,\n \"eager_ms_per_iter_runs\": [\n 0.15823810899928503,\n 0.15820250050092,\n 0.1576413214988861\n ],\n \"graph_ms_per_iter_runs\": [\n 0.19224454849972972,\n 0.19346232400130248,\n 0.19302421149950533\n ],\n \"speedup_x\": 0.819599257895818,\n \"fallback\": true\n },\n {\n \"workload\": \"mlp_bs32_d1024\",\n \"iters\": 1500,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.10682662866505173,\n \"graph_ms_per_iter\": 0.10702674200001638,\n \"eager_ms_per_iter_runs\": [\n 0.10682662866505173,\n 0.10648085199985265,\n 0.10685669400118059\n ],\n \"graph_ms_per_iter_runs\": [\n 0.10702674200001638,\n 0.10526757266537363,\n 0.1072387293340095\n ],\n \"speedup_x\": 0.9981302492141205,\n \"fallback\": true\n },\n {\n \"workload\": \"mlp_bs128_d2048\",\n \"iters\": 300,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.6399757700031236,\n \"graph_ms_per_iter\": 0.6383206166598635,\n \"eager_ms_per_iter_runs\": [\n 0.6399757700031236,\n 0.6404388566685763,\n 0.6358656200003073\n ],\n \"graph_ms_per_iter_runs\": [\n 0.6370942166662038,\n 0.6383206166598635,\n 0.6383977166721403\n ],\n \"speedup_x\": 1.002592981176013,\n \"fallback\": true\n }\n ]\n}\n", + "stderr_tail": "[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n", + "metrics": { + "all_workloads_fallback": true, + "fallback_workload_count": 3, + "fallback_workloads": [ + { + "eager_ms_per_iter": 0.15820250050092, + "graph_ms_per_iter": 0.19302421149950533, + "speedup_x": 0.819599257895818, + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024" + }, + { + "eager_ms_per_iter": 0.10682662866505171, + "graph_ms_per_iter": 0.10702674200001638, + "speedup_x": 0.9981302492141204, + "workload": "mlp_bs32_d1024" + }, + { + "eager_ms_per_iter": 0.6399757700031236, + "graph_ms_per_iter": 0.6383206166598635, + "speedup_x": 1.002592981176013, + "workload": "mlp_bs128_d2048" + } + ], + "payload": { + "commit_sha": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "env": { + "device": "AMD Radeon RX 6700 XT", + "env": { + "CUDA_VISIBLE_DEVICES": null, + "GFXGRAPH": null, + "GFXGRAPH_VRAM_CAP": null, + "HIP_VISIBLE_DEVICES": null, + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "PYTORCH_ROCM_ARCH": null, + "SGLANG_RDNA2_KERNELS": null + }, + "rocm": { + "driver_from_hipconfig": "7.2.26015-fc0010cf6a", + "runtime_from_rocminfo": "Runtime Version: 1.18", + "runtime_from_torch": "7.2.26015" + }, + "torch": "2.13.0a0+git53bbebe" + }, + "results": [ + { + "eager_ms_per_iter": 0.15820250050092, + "eager_ms_per_iter_runs": [ + 0.15823810899928503, + 0.15820250050092, + 0.1576413214988861 + ], + "fallback": true, + "graph_ms_per_iter": 0.19302421149950533, + "graph_ms_per_iter_runs": [ + 0.19224454849972972, + 0.19346232400130248, + 0.19302421149950533 + ], + "iters": 2000, + "run_count": 3, + "speedup_x": 0.819599257895818, + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024" + }, + { + "eager_ms_per_iter": 0.10682662866505171, + "eager_ms_per_iter_runs": [ + 0.10682662866505171, + 0.10648085199985265, + 0.1068566940011806 + ], + "fallback": true, + "graph_ms_per_iter": 0.10702674200001638, + "graph_ms_per_iter_runs": [ + 0.10702674200001638, + 0.10526757266537363, + 0.1072387293340095 + ], + "iters": 1500, + "run_count": 3, + "speedup_x": 0.9981302492141204, + "workload": "mlp_bs32_d1024" + }, + { + "eager_ms_per_iter": 0.6399757700031236, + "eager_ms_per_iter_runs": [ + 0.6399757700031236, + 0.6404388566685763, + 0.6358656200003073 + ], + "fallback": true, + "graph_ms_per_iter": 0.6383206166598635, + "graph_ms_per_iter_runs": [ + 0.6370942166662038, + 0.6383206166598635, + 0.6383977166721403 + ], + "iters": 300, + "run_count": 3, + "speedup_x": 1.002592981176013, + "workload": "mlp_bs128_d2048" + } + ], + "run_count": 3, + "timestamp_utc": "2026-06-16T14:34:49Z" + }, + "workload_count": 3 + } + }, + { + "name": "legacy-python-microbenchmarks", + "kind": "python-micro", + "status": "skipped", + "command": "", + "iterations": null, + "duration_ms": null, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "skip_reason": "skipped; pass --include-python-micro to run legacy Python microbenchmarks" + } + } + ] +} diff --git a/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-clean-candidate-native-only-runtime-20260616.json b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-clean-candidate-native-only-runtime-20260616.json new file mode 100644 index 0000000..7fb72a3 --- /dev/null +++ b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-clean-candidate-native-only-runtime-20260616.json @@ -0,0 +1,274 @@ +{ + "schema_version": "gfxgraph-benchmark-v1", + "report_kind": "benchmark_gate_phase_report", + "run_id": "native-only-runtime-20260616", + "phase": "clean-candidate", + "timestamp_utc": "2026-06-16T23:33:26Z", + "report_date": "2026-06-16", + "schema_path": "benchmarks/schemas/gfxgraph-benchmark-v1.schema.json", + "repo": { + "root": "/home/local/ai/projects/gfxGRAPH", + "branch": "rust-hip-cpp", + "commit": "47d293471636d041a4c58e39e55e9e0e9bd5bf66", + "tracked_dirty": true + }, + "environment": { + "os": "Linux FRACTAL 6.8.0-90-generic #91-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 18 14:14:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux", + "rocm_path": "/opt/rocm", + "hipcc_version": "HIP version: 7.2.26015-fc0010cf6a\nAMD clang version 22.0.0git (https://github.com/RadeonOpenCompute/llvm-project roc-7.2.0 26014 7b800a19466229b8479a78de19143dc33c3ab9b5)\nTarget: x86_64-unknown-linux-gnu\nThread model: posix\nInstalledDir: /opt/rocm-7.2.0/lib/llvm/bin\nConfiguration file: /opt/rocm-7.2.0/lib/llvm/bin/clang++.cfg", + "env": { + "GFXGRAPH": null, + "GFXGRAPH_VALIDATE": null, + "GFXGRAPH_VRAM_CAP": null, + "HIP_VISIBLE_DEVICES": null, + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "ROCM_PATH": "/opt/rocm" + } + }, + "python": null, + "package_state": { + "target_import_policy": "native-only", + "graph_enabled": false, + "allow_package_changes": false, + "package_actions": [] + }, + "gate_checks": [ + { + "name": "native-runtime-only", + "status": "passed", + "message": "native-only gate skips Python package transition and import provenance", + "details": { + "phase": "clean-candidate", + "python": null + } + } + ], + "benchmarks": [ + { + "name": "python-import-provenance", + "kind": "package-provenance", + "status": "skipped", + "command": "", + "iterations": null, + "duration_ms": null, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "skip_reason": "skipped by --native-only" + } + }, + { + "name": "torch-capture-policy", + "kind": "capture-policy", + "status": "skipped", + "command": "", + "iterations": null, + "duration_ms": null, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "skip_reason": "skipped by --native-only" + } + }, + { + "name": "rust-bucket-router-core", + "kind": "rust-micro", + "status": "passed", + "command": "in-process BucketRouterCore::route loop", + "iterations": 200000, + "duration_ms": 59.107106, + "throughput_ops_per_sec": 3383687.9105534283, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "bucket_count": 10, + "ready_routes": 200000 + } + }, + { + "name": "rust-stats-sample-update", + "kind": "rust-micro", + "status": "passed", + "command": "in-process GfxGraphStatsSample update loop", + "iterations": 200000, + "duration_ms": 1.3916849999999998, + "throughput_ops_per_sec": 143710681.65569076, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "failures": 196, + "samples": 200000 + } + }, + { + "name": "rust-native-runtime-cli", + "kind": "rust-native", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/target/debug/gfxgraph-native-probe --repo-root /home/local/ai/projects/gfxGRAPH --event-count 3 --sample-count 8", + "iterations": null, + "duration_ms": 48.82197600000001, + "throughput_ops_per_sec": null, + "stdout_tail": "{\"candidate_libraries\":[\"/home/local/ai/projects/gfxGRAPH/build/libhipgraph_bridge.so\",\"/home/local/ai/projects/gfxGRAPH/build/lib/libhipgraph_bridge.so\",\"/usr/local/lib/libhipgraph_bridge.so\"],\"duration_ms\":40.475153,\"event_count\":3,\"init_error\":null,\"init_ok\":true,\"initialized\":true,\"kind\":\"gfxgraph-native-probe-v1\",\"library_path\":\"/home/local/ai/projects/gfxGRAPH/build/libhipgraph_bridge.so\",\"native_contracts\":[\"lifecycle\",\"profiler\",\"pipeline_handles\",\"composed_handles\"],\"profiler_counters\":{\"capacity\":4096,\"dropped\":0,\"written\":3},\"python_used\":false,\"recorded_sequences\":[1,2,3],\"repo_root\":\"/home/local/ai/projects/gfxGRAPH\",\"snapshot_sample_count\":3,\"status\":\"passed\",\"version\":{\"gfx_target\":\"gfx1030\",\"major\":0,\"minor\":3,\"patch\":4,\"rocm_version\":\"7.2.26015\"}}\n", + "stderr_tail": "", + "metrics": { + "event_count": 3, + "init_ok": true, + "initialized": true, + "library_path": "/home/local/ai/projects/gfxGRAPH/build/libhipgraph_bridge.so", + "native_contracts": [ + "lifecycle", + "profiler", + "pipeline_handles", + "composed_handles" + ], + "payload": { + "candidate_libraries": [ + "/home/local/ai/projects/gfxGRAPH/build/libhipgraph_bridge.so", + "/home/local/ai/projects/gfxGRAPH/build/lib/libhipgraph_bridge.so", + "/usr/local/lib/libhipgraph_bridge.so" + ], + "duration_ms": 40.475153, + "event_count": 3, + "init_error": null, + "init_ok": true, + "initialized": true, + "kind": "gfxgraph-native-probe-v1", + "library_path": "/home/local/ai/projects/gfxGRAPH/build/libhipgraph_bridge.so", + "native_contracts": [ + "lifecycle", + "profiler", + "pipeline_handles", + "composed_handles" + ], + "profiler_counters": { + "capacity": 4096, + "dropped": 0, + "written": 3 + }, + "python_used": false, + "recorded_sequences": [ + 1, + 2, + 3 + ], + "repo_root": "/home/local/ai/projects/gfxGRAPH", + "snapshot_sample_count": 3, + "status": "passed", + "version": { + "gfx_target": "gfx1030", + "major": 0, + "minor": 3, + "patch": 4, + "rocm_version": "7.2.26015" + } + }, + "profiler_counters": { + "capacity": 4096, + "dropped": 0, + "written": 3 + }, + "python_used": false, + "snapshot_sample_count": 3, + "version": { + "gfx_target": "gfx1030", + "major": 0, + "minor": 3, + "patch": 4, + "rocm_version": "7.2.26015" + } + } + }, + { + "name": "rust-native-runtime-ffi", + "kind": "rust-native", + "status": "passed", + "command": "NativeBridge::open_default(/home/local/ai/projects/gfxGRAPH)", + "iterations": null, + "duration_ms": 64.377537, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "init_error": null, + "initialized": true, + "library_path": "/home/local/ai/projects/gfxGRAPH/build/libhipgraph_bridge.so", + "profiler_counters": { + "capacity": 4096, + "dropped": 0, + "written": 1 + }, + "recorded_seq": 1, + "sample_count": 1, + "version": { + "gfx_target": "gfx1030", + "major": 0, + "minor": 3, + "patch": 4, + "rocm_version": "7.2.26015" + } + } + }, + { + "name": "native-hip-benchmark", + "kind": "hip-native", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/build/benchmark_pipeline", + "iterations": 10000, + "duration_ms": 409.449752, + "throughput_ops_per_sec": null, + "stdout_tail": "=== benchmark_pipeline ===\nWarmup launches: 100\nMeasured launches: 10000\nAverage pipeline launch latency: 25.62 us\nDevice clock64 probe cycles: 352037\nProfiler samples copied: 16\nProfiler events written: 10103\nProfiler events dropped: 6007\n", + "stderr_tail": "", + "metrics": { + "average_pipeline_launch_latency_us": 25.62, + "device_clock64_probe_cycles": 352037, + "measured_launches": 10000, + "profiler_events_dropped": 6007, + "profiler_events_written": 10103, + "profiler_samples_copied": 16, + "warmup_launches": 100 + } + }, + { + "name": "native-hip-tests", + "kind": "hip-native", + "status": "passed", + "command": "ctest --test-dir /home/local/ai/projects/gfxGRAPH/build --output-on-failure", + "iterations": null, + "duration_ms": 1555.469048, + "throughput_ops_per_sec": null, + "stdout_tail": "Test project /home/local/ai/projects/gfxGRAPH/build\n Start 1: conditional\n1/7 Test #1: conditional ...................... Passed 0.16 sec\n Start 2: pipeline\n2/7 Test #2: pipeline ......................... Passed 0.17 sec\n Start 3: shapes\n3/7 Test #3: shapes ........................... Passed 0.30 sec\n Start 4: compositor\n4/7 Test #4: compositor ....................... Passed 0.32 sec\n Start 5: routing\n5/7 Test #5: routing .......................... Passed 0.23 sec\n Start 6: profiler\n6/7 Test #6: profiler ......................... Passed 0.06 sec\n Start 7: runtime_handles\n7/7 Test #7: runtime_handles .................. Passed 0.20 sec\n\n100% tests passed, 0 tests failed out of 7\n\nTotal Test time (real) = 1.44 sec\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "readme-public-benchmark", + "kind": "python-public", + "status": "skipped", + "command": "", + "iterations": null, + "duration_ms": null, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "skip_reason": "skipped by --native-only" + } + }, + { + "name": "legacy-python-microbenchmarks", + "kind": "python-micro", + "status": "skipped", + "command": "", + "iterations": null, + "duration_ms": null, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "skip_reason": "skipped by --native-only" + } + } + ] +} diff --git a/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-clean-candidate-native-runtime-refactor-20260616.json b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-clean-candidate-native-runtime-refactor-20260616.json new file mode 100644 index 0000000..9ad9ea8 --- /dev/null +++ b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-clean-candidate-native-runtime-refactor-20260616.json @@ -0,0 +1,393 @@ +{ + "schema_version": "gfxgraph-benchmark-v1", + "report_kind": "benchmark_gate_phase_report", + "run_id": "native-runtime-refactor-20260616", + "phase": "clean-candidate", + "timestamp_utc": "2026-06-16T14:59:31Z", + "report_date": "2026-06-16", + "schema_path": "benchmarks/schemas/gfxgraph-benchmark-v1.schema.json", + "repo": { + "root": "/home/local/ai/projects/gfxGRAPH", + "branch": "rust-hip-cpp", + "commit": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "tracked_dirty": true + }, + "environment": { + "os": "Linux FRACTAL 6.8.0-90-generic #91-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 18 14:14:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux", + "rocm_path": "/opt/rocm", + "hipcc_version": "HIP version: 7.2.26015-fc0010cf6a\nAMD clang version 22.0.0git (https://github.com/RadeonOpenCompute/llvm-project roc-7.2.0 26014 7b800a19466229b8479a78de19143dc33c3ab9b5)\nTarget: x86_64-unknown-linux-gnu\nThread model: posix\nInstalledDir: /opt/rocm-7.2.0/lib/llvm/bin\nConfiguration file: /opt/rocm-7.2.0/lib/llvm/bin/clang++.cfg", + "env": { + "GFXGRAPH": null, + "GFXGRAPH_VALIDATE": null, + "GFXGRAPH_VRAM_CAP": null, + "HIP_VISIBLE_DEVICES": null, + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "ROCM_PATH": "/opt/rocm" + } + }, + "python": { + "executable": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python", + "imports": [ + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH" + }, + "distribution": "gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/python/gfxgraph/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/python/gfxgraph" + ], + "version": "1.0.1" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH" + }, + "distribution": "gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "hipgraph_bridge", + "origin": "/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge" + ], + "version": "1.0.1" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH/native" + }, + "distribution": "gfxgraph-native", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "gfxgraph_native", + "origin": "/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native" + ], + "version": "0.3.3" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph" + }, + "distribution": "rs-gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "rs_gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph" + ], + "version": "0.1.0" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph_stats" + }, + "distribution": "rs-gfxgraph-stats", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "rs_gfxgraph_stats", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats" + ], + "version": "0.1.0" + } + ], + "prefix": "/home/local/ai/projects/gfxGRAPH/.venv", + "version": "3.12.7 (main, Oct 16 2024, 04:37:19) [Clang 18.1.8 ]" + }, + "package_state": { + "target_import_policy": "repo", + "graph_enabled": false, + "allow_package_changes": true, + "package_actions": [ + { + "name": "uv-uninstall-installed-python-packages", + "command": "uv pip uninstall --python /home/local/ai/projects/gfxGRAPH/.venv/bin/python gfxgraph gfxgraph-native rs-gfxgraph rs-gfxgraph-stats", + "status": "passed", + "duration_ms": 13.364291, + "exit_code": 0, + "stdout_tail": "", + "stderr_tail": "Uninstalled 4 packages in 3ms\n - gfxgraph==1.0.1 (from file:///home/local/ai/projects/gfxGRAPH)\n - gfxgraph-native==0.3.3 (from file:///home/local/ai/projects/gfxGRAPH/native)\n - rs-gfxgraph==0.1.0 (from file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph)\n - rs-gfxgraph-stats==0.1.0 (from file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph_stats)\n" + }, + { + "name": "uv-install-candidate-gfxgraph", + "command": "uv pip install --python /home/local/ai/projects/gfxGRAPH/.venv/bin/python --no-deps -e /home/local/ai/projects/gfxGRAPH", + "status": "passed", + "duration_ms": 1211.933081, + "exit_code": 0, + "stdout_tail": "", + "stderr_tail": "Resolved 1 package in 1ms\n Building gfxgraph @ file:///home/local/ai/projects/gfxGRAPH\n Built gfxgraph @ file:///home/local/ai/projects/gfxGRAPH\nPrepared 1 package in 1.11s\nwarning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.\n If the cache and target directories are on different filesystems, hardlinking may not be supported.\n If this is intentional, set `export UV_LINK_MODE=copy` or use `--link-mode=copy` to suppress this warning.\nInstalled 1 package in 4ms\n + gfxgraph==1.0.1 (from file:///home/local/ai/projects/gfxGRAPH)\n" + }, + { + "name": "uv-install-candidate-gfxgraph-native", + "command": "uv pip install --python /home/local/ai/projects/gfxGRAPH/.venv/bin/python --no-deps -e /home/local/ai/projects/gfxGRAPH/native", + "status": "passed", + "duration_ms": 4458.308616, + "exit_code": 0, + "stdout_tail": "", + "stderr_tail": "Resolved 1 package in 1ms\n Building gfxgraph-native @ file:///home/local/ai/projects/gfxGRAPH/native\n Built gfxgraph-native @ file:///home/local/ai/projects/gfxGRAPH/native\nPrepared 1 package in 4.31s\nwarning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.\n If the cache and target directories are on different filesystems, hardlinking may not be supported.\n If this is intentional, set `export UV_LINK_MODE=copy` or use `--link-mode=copy` to suppress this warning.\nInstalled 1 package in 9ms\n + gfxgraph-native==0.3.3 (from file:///home/local/ai/projects/gfxGRAPH/native)\n" + }, + { + "name": "maturin-develop-rs-gfxgraph-uv", + "command": "maturin develop --uv --release", + "status": "passed", + "duration_ms": 1142.837892, + "exit_code": 0, + "stdout_tail": "✏️ Setting installed package as editable\n", + "stderr_tail": "🐍 Found CPython 3.12 at /home/local/ai/projects/gfxGRAPH/.venv/bin/python\n🔗 Found pyo3 bindings\n Finished `release` profile [optimized] target(s) in 0.13s\n📦 Built wheel for CPython 3.12 to /tmp/.tmpGypcrL/rs_gfxgraph-0.1.0-cp312-cp312-linux_x86_64.whl\n🛠 Installed rs_gfxgraph-0.1.0\n" + }, + { + "name": "maturin-develop-rs-gfxgraph-stats-uv", + "command": "maturin develop --uv --release", + "status": "passed", + "duration_ms": 1108.280516, + "exit_code": 0, + "stdout_tail": "✏️ Setting installed package as editable\n", + "stderr_tail": "🐍 Found CPython 3.12 at /home/local/ai/projects/gfxGRAPH/.venv/bin/python\n🔗 Found pyo3 bindings\n Finished `release` profile [optimized] target(s) in 0.13s\n📦 Built wheel for CPython 3.12 to /tmp/.tmphsOY3X/rs_gfxgraph_stats-0.1.0-cp312-cp312-linux_x86_64.whl\n🛠 Installed rs_gfxgraph_stats-0.1.0\n" + } + ] + }, + "gate_checks": [ + { + "name": "candidate-package-transition", + "status": "passed", + "message": "UV package uninstall/install transition completed", + "details": { + "actions": [ + { + "exit_code": 0, + "name": "uv-uninstall-installed-python-packages", + "status": "passed" + }, + { + "exit_code": 0, + "name": "uv-install-candidate-gfxgraph", + "status": "passed" + }, + { + "exit_code": 0, + "name": "uv-install-candidate-gfxgraph-native", + "status": "passed" + }, + { + "exit_code": 0, + "name": "maturin-develop-rs-gfxgraph-uv", + "status": "passed" + }, + { + "exit_code": 0, + "name": "maturin-develop-rs-gfxgraph-stats-uv", + "status": "passed" + } + ] + } + }, + { + "name": "python-import-isolation", + "status": "passed", + "message": "clean-candidate imports match repo policy", + "details": { + "checked": [ + { + "importable": true, + "in_repo": true, + "module": "gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/python/gfxgraph/__init__.py" + }, + { + "importable": true, + "in_repo": true, + "module": "hipgraph_bridge", + "origin": "/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge/__init__.py" + }, + { + "importable": true, + "in_repo": true, + "module": "gfxgraph_native", + "origin": "/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native/__init__.py" + } + ] + } + } + ], + "benchmarks": [ + { + "name": "python-import-provenance", + "kind": "package-provenance", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python -c ", + "iterations": null, + "duration_ms": 70.988598, + "throughput_ops_per_sec": null, + "stdout_tail": "{\"executable\": \"/home/local/ai/projects/gfxGRAPH/.venv/bin/python\", \"imports\": [{\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH\"}, \"distribution\": \"gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"gfxgraph\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/python/gfxgraph/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/python/gfxgraph\"], \"version\": \"1.0.1\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH\"}, \"distribution\": \"gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"hipgraph_bridge\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge\"], \"version\": \"1.0.1\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/native\"}, \"distribution\": \"gfxgraph-native\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"gfxgraph_native\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native\"], \"version\": \"0.3.3\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph\"}, \"distribution\": \"rs-gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"rs_gfxgraph\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph\"], \"version\": \"0.1.0\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph_stats\"}, \"distribution\": \"rs-gfxgraph-stats\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"rs_gfxgraph_stats\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats\"], \"version\": \"0.1.0\"}], \"prefix\": \"/home/local/ai/projects/gfxGRAPH/.venv\", \"version\": \"3.12.7 (main, Oct 16 2024, 04:37:19) [Clang 18.1.8 ]\"}\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "torch-capture-policy", + "kind": "capture-policy", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python -c ", + "iterations": null, + "duration_ms": 17906.115315000003, + "throughput_ops_per_sec": null, + "stdout_tail": "{\"GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE\": null, \"cuda_available\": true, \"cuda_execution_error\": \"CUDA execution probe passed\", \"cuda_execution_usable\": true, \"device\": \"AMD Radeon RX 6700 XT\", \"torch\": \"2.13.0a0+git53bbebe\", \"torch_graph_capture_block_reason\": \"high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in\", \"torch_hip\": \"7.2.26015\", \"unsafe_torch_graph_capture_enabled\": false}\n", + "stderr_tail": "", + "metrics": { + "probe": { + "GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE": null, + "cuda_available": true, + "cuda_execution_error": "CUDA execution probe passed", + "cuda_execution_usable": true, + "device": "AMD Radeon RX 6700 XT", + "torch": "2.13.0a0+git53bbebe", + "torch_graph_capture_block_reason": "high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in", + "torch_hip": "7.2.26015", + "unsafe_torch_graph_capture_enabled": false + } + } + }, + { + "name": "rust-bucket-router-core", + "kind": "rust-micro", + "status": "passed", + "command": "in-process BucketRouterCore::route loop", + "iterations": 200000, + "duration_ms": 93.68010100000001, + "throughput_ops_per_sec": 2134925.110723354, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "bucket_count": 10, + "ready_routes": 200000 + } + }, + { + "name": "rust-stats-sample-update", + "kind": "rust-micro", + "status": "passed", + "command": "in-process GfxGraphStatsSample update loop", + "iterations": 200000, + "duration_ms": 1.35333, + "throughput_ops_per_sec": 147783615.23057938, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "failures": 196, + "samples": 200000 + } + }, + { + "name": "rust-native-runtime-ffi", + "kind": "rust-native", + "status": "passed", + "command": "NativeBridge::open_default(/home/local/ai/projects/gfxGRAPH)", + "iterations": null, + "duration_ms": 35.615806, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "init_error": null, + "initialized": true, + "library_path": "/home/local/ai/projects/gfxGRAPH/build/libhipgraph_bridge.so", + "profiler_counters": { + "capacity": 4096, + "dropped": 0, + "written": 1 + }, + "recorded_seq": 1, + "sample_count": 1, + "version": { + "gfx_target": "gfx1030", + "major": 0, + "minor": 3, + "patch": 4, + "rocm_version": "7.2.26015" + } + } + }, + { + "name": "native-hip-benchmark", + "kind": "hip-native", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/build/benchmark_pipeline", + "iterations": 10000, + "duration_ms": 395.006101, + "throughput_ops_per_sec": null, + "stdout_tail": "=== benchmark_pipeline ===\nWarmup launches: 100\nMeasured launches: 10000\nAverage pipeline launch latency: 25.67 us\nDevice clock64 probe cycles: 358390\nProfiler samples copied: 16\nProfiler events written: 10103\nProfiler events dropped: 6007\n", + "stderr_tail": "", + "metrics": { + "average_pipeline_launch_latency_us": 25.67, + "device_clock64_probe_cycles": 358390, + "measured_launches": 10000, + "profiler_events_dropped": 6007, + "profiler_events_written": 10103, + "profiler_samples_copied": 16, + "warmup_launches": 100 + } + }, + { + "name": "native-hip-tests", + "kind": "hip-native", + "status": "passed", + "command": "ctest --test-dir /home/local/ai/projects/gfxGRAPH/build --output-on-failure", + "iterations": null, + "duration_ms": 1503.293347, + "throughput_ops_per_sec": null, + "stdout_tail": "Test project /home/local/ai/projects/gfxGRAPH/build\n Start 1: conditional\n1/7 Test #1: conditional ...................... Passed 0.16 sec\n Start 2: pipeline\n2/7 Test #2: pipeline ......................... Passed 0.16 sec\n Start 3: shapes\n3/7 Test #3: shapes ........................... Passed 0.29 sec\n Start 4: compositor\n4/7 Test #4: compositor ....................... Passed 0.31 sec\n Start 5: routing\n5/7 Test #5: routing .......................... Passed 0.23 sec\n Start 6: profiler\n6/7 Test #6: profiler ......................... Passed 0.04 sec\n Start 7: runtime_handles\n7/7 Test #7: runtime_handles .................. Passed 0.18 sec\n\n100% tests passed, 0 tests failed out of 7\n\nTotal Test time (real) = 1.39 sec\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "readme-public-benchmark", + "kind": "python-public", + "status": "skipped", + "command": "", + "iterations": null, + "duration_ms": null, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "skip_reason": "skipped by --skip-public" + } + }, + { + "name": "legacy-python-microbenchmarks", + "kind": "python-micro", + "status": "skipped", + "command": "", + "iterations": null, + "duration_ms": null, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "skip_reason": "skipped; pass --include-python-micro to run legacy Python microbenchmarks" + } + } + ] +} diff --git a/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-graph-candidate-main-python-baseline-rust-hip-cpp-20260616.json b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-graph-candidate-main-python-baseline-rust-hip-cpp-20260616.json new file mode 100644 index 0000000..e9d2ab0 --- /dev/null +++ b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-graph-candidate-main-python-baseline-rust-hip-cpp-20260616.json @@ -0,0 +1,459 @@ +{ + "schema_version": "gfxgraph-benchmark-v1", + "report_kind": "benchmark_gate_phase_report", + "run_id": "main-python-baseline-rust-hip-cpp-20260616", + "phase": "graph-candidate", + "timestamp_utc": "2026-06-16T14:32:53Z", + "report_date": "2026-06-16", + "schema_path": "benchmarks/schemas/gfxgraph-benchmark-v1.schema.json", + "repo": { + "root": "/home/local/ai/projects/gfxGRAPH", + "branch": "rust-hip-cpp", + "commit": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "tracked_dirty": true + }, + "environment": { + "os": "Linux FRACTAL 6.8.0-90-generic #91-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 18 14:14:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux", + "rocm_path": "/opt/rocm", + "hipcc_version": "HIP version: 7.2.26015-fc0010cf6a\nAMD clang version 22.0.0git (https://github.com/RadeonOpenCompute/llvm-project roc-7.2.0 26014 7b800a19466229b8479a78de19143dc33c3ab9b5)\nTarget: x86_64-unknown-linux-gnu\nThread model: posix\nInstalledDir: /opt/rocm-7.2.0/lib/llvm/bin\nConfiguration file: /opt/rocm-7.2.0/lib/llvm/bin/clang++.cfg", + "env": { + "GFXGRAPH": null, + "GFXGRAPH_VALIDATE": null, + "GFXGRAPH_VRAM_CAP": null, + "HIP_VISIBLE_DEVICES": null, + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "ROCM_PATH": "/opt/rocm" + } + }, + "python": { + "executable": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python", + "imports": [ + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH" + }, + "distribution": "gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/python/gfxgraph/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/python/gfxgraph" + ], + "version": "1.0.1" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH" + }, + "distribution": "gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "hipgraph_bridge", + "origin": "/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge" + ], + "version": "1.0.1" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH/native" + }, + "distribution": "gfxgraph-native", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "gfxgraph_native", + "origin": "/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native" + ], + "version": "0.3.3" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph" + }, + "distribution": "rs-gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "rs_gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph" + ], + "version": "0.1.0" + }, + { + "direct_url": { + "dir_info": { + "editable": true + }, + "url": "file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph_stats" + }, + "distribution": "rs-gfxgraph-stats", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "rs_gfxgraph_stats", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats" + ], + "version": "0.1.0" + } + ], + "prefix": "/home/local/ai/projects/gfxGRAPH/.venv", + "version": "3.12.7 (main, Oct 16 2024, 04:37:19) [Clang 18.1.8 ]" + }, + "package_state": { + "target_import_policy": "repo", + "graph_enabled": true, + "allow_package_changes": true, + "package_actions": [ + { + "name": "uv-uninstall-installed-python-packages", + "command": "uv pip uninstall --python /home/local/ai/projects/gfxGRAPH/.venv/bin/python gfxgraph gfxgraph-native rs-gfxgraph rs-gfxgraph-stats", + "status": "passed", + "duration_ms": 17.651993, + "exit_code": 0, + "stdout_tail": "", + "stderr_tail": "Uninstalled 4 packages in 4ms\n - gfxgraph==1.0.1 (from file:///home/local/ai/projects/gfxGRAPH)\n - gfxgraph-native==0.3.3 (from file:///home/local/ai/projects/gfxGRAPH/native)\n - rs-gfxgraph==0.1.0 (from file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph)\n - rs-gfxgraph-stats==0.1.0 (from file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph_stats)\n" + }, + { + "name": "uv-install-candidate-gfxgraph", + "command": "uv pip install --python /home/local/ai/projects/gfxGRAPH/.venv/bin/python --no-deps -e /home/local/ai/projects/gfxGRAPH", + "status": "passed", + "duration_ms": 917.6247589999999, + "exit_code": 0, + "stdout_tail": "", + "stderr_tail": "Resolved 1 package in 1ms\n Building gfxgraph @ file:///home/local/ai/projects/gfxGRAPH\n Built gfxgraph @ file:///home/local/ai/projects/gfxGRAPH\nPrepared 1 package in 830ms\nwarning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.\n If the cache and target directories are on different filesystems, hardlinking may not be supported.\n If this is intentional, set `export UV_LINK_MODE=copy` or use `--link-mode=copy` to suppress this warning.\nInstalled 1 package in 4ms\n + gfxgraph==1.0.1 (from file:///home/local/ai/projects/gfxGRAPH)\n" + }, + { + "name": "uv-install-candidate-gfxgraph-native", + "command": "uv pip install --python /home/local/ai/projects/gfxGRAPH/.venv/bin/python --no-deps -e /home/local/ai/projects/gfxGRAPH/native", + "status": "passed", + "duration_ms": 4587.51494, + "exit_code": 0, + "stdout_tail": "", + "stderr_tail": "Resolved 1 package in 1ms\n Building gfxgraph-native @ file:///home/local/ai/projects/gfxGRAPH/native\n Built gfxgraph-native @ file:///home/local/ai/projects/gfxGRAPH/native\nPrepared 1 package in 4.44s\nwarning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.\n If the cache and target directories are on different filesystems, hardlinking may not be supported.\n If this is intentional, set `export UV_LINK_MODE=copy` or use `--link-mode=copy` to suppress this warning.\nInstalled 1 package in 3ms\n + gfxgraph-native==0.3.3 (from file:///home/local/ai/projects/gfxGRAPH/native)\n" + }, + { + "name": "maturin-develop-rs-gfxgraph-uv", + "command": "maturin develop --uv --release", + "status": "passed", + "duration_ms": 1130.81167, + "exit_code": 0, + "stdout_tail": "✏️ Setting installed package as editable\n", + "stderr_tail": "🐍 Found CPython 3.12 at /home/local/ai/projects/gfxGRAPH/.venv/bin/python\n🔗 Found pyo3 bindings\n Finished `release` profile [optimized] target(s) in 0.13s\n📦 Built wheel for CPython 3.12 to /tmp/.tmpFSitVF/rs_gfxgraph-0.1.0-cp312-cp312-linux_x86_64.whl\n🛠 Installed rs_gfxgraph-0.1.0\n" + }, + { + "name": "maturin-develop-rs-gfxgraph-stats-uv", + "command": "maturin develop --uv --release", + "status": "passed", + "duration_ms": 1117.0616440000001, + "exit_code": 0, + "stdout_tail": "✏️ Setting installed package as editable\n", + "stderr_tail": "🐍 Found CPython 3.12 at /home/local/ai/projects/gfxGRAPH/.venv/bin/python\n🔗 Found pyo3 bindings\n Finished `release` profile [optimized] target(s) in 0.13s\n📦 Built wheel for CPython 3.12 to /tmp/.tmpuutZmt/rs_gfxgraph_stats-0.1.0-cp312-cp312-linux_x86_64.whl\n🛠 Installed rs_gfxgraph_stats-0.1.0\n" + } + ] + }, + "gate_checks": [ + { + "name": "candidate-package-transition", + "status": "passed", + "message": "UV package uninstall/install transition completed", + "details": { + "actions": [ + { + "exit_code": 0, + "name": "uv-uninstall-installed-python-packages", + "status": "passed" + }, + { + "exit_code": 0, + "name": "uv-install-candidate-gfxgraph", + "status": "passed" + }, + { + "exit_code": 0, + "name": "uv-install-candidate-gfxgraph-native", + "status": "passed" + }, + { + "exit_code": 0, + "name": "maturin-develop-rs-gfxgraph-uv", + "status": "passed" + }, + { + "exit_code": 0, + "name": "maturin-develop-rs-gfxgraph-stats-uv", + "status": "passed" + } + ] + } + }, + { + "name": "python-import-isolation", + "status": "passed", + "message": "graph-candidate imports match repo policy", + "details": { + "checked": [ + { + "importable": true, + "in_repo": true, + "module": "gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/python/gfxgraph/__init__.py" + }, + { + "importable": true, + "in_repo": true, + "module": "hipgraph_bridge", + "origin": "/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge/__init__.py" + }, + { + "importable": true, + "in_repo": true, + "module": "gfxgraph_native", + "origin": "/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native/__init__.py" + } + ] + } + } + ], + "benchmarks": [ + { + "name": "python-import-provenance", + "kind": "package-provenance", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python -c ", + "iterations": null, + "duration_ms": 65.217509, + "throughput_ops_per_sec": null, + "stdout_tail": "{\"executable\": \"/home/local/ai/projects/gfxGRAPH/.venv/bin/python\", \"imports\": [{\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH\"}, \"distribution\": \"gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"gfxgraph\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/python/gfxgraph/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/python/gfxgraph\"], \"version\": \"1.0.1\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH\"}, \"distribution\": \"gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"hipgraph_bridge\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/python/hipgraph_bridge\"], \"version\": \"1.0.1\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/native\"}, \"distribution\": \"gfxgraph-native\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"gfxgraph_native\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/native/gfxgraph_native\"], \"version\": \"0.3.3\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph\"}, \"distribution\": \"rs-gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"rs_gfxgraph\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph\"], \"version\": \"0.1.0\"}, {\"direct_url\": {\"dir_info\": {\"editable\": true}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/rust/rs_gfxgraph_stats\"}, \"distribution\": \"rs-gfxgraph-stats\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"rs_gfxgraph_stats\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/rs_gfxgraph_stats\"], \"version\": \"0.1.0\"}], \"prefix\": \"/home/local/ai/projects/gfxGRAPH/.venv\", \"version\": \"3.12.7 (main, Oct 16 2024, 04:37:19) [Clang 18.1.8 ]\"}\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "torch-capture-policy", + "kind": "capture-policy", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python -c ", + "iterations": null, + "duration_ms": 19436.686417, + "throughput_ops_per_sec": null, + "stdout_tail": "{\"GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE\": null, \"cuda_available\": true, \"cuda_execution_error\": \"CUDA execution probe passed\", \"cuda_execution_usable\": true, \"device\": \"AMD Radeon RX 6700 XT\", \"torch\": \"2.13.0a0+git53bbebe\", \"torch_graph_capture_block_reason\": \"high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in\", \"torch_hip\": \"7.2.26015\", \"unsafe_torch_graph_capture_enabled\": false}\n", + "stderr_tail": "", + "metrics": { + "probe": { + "GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE": null, + "cuda_available": true, + "cuda_execution_error": "CUDA execution probe passed", + "cuda_execution_usable": true, + "device": "AMD Radeon RX 6700 XT", + "torch": "2.13.0a0+git53bbebe", + "torch_graph_capture_block_reason": "high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in", + "torch_hip": "7.2.26015", + "unsafe_torch_graph_capture_enabled": false + } + } + }, + { + "name": "rust-bucket-router-core", + "kind": "rust-micro", + "status": "passed", + "command": "in-process BucketRouterCore::route loop", + "iterations": 200000, + "duration_ms": 94.490518, + "throughput_ops_per_sec": 2116614.494588759, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "bucket_count": 10, + "ready_routes": 200000 + } + }, + { + "name": "rust-stats-sample-update", + "kind": "rust-micro", + "status": "passed", + "command": "in-process GfxGraphStatsSample update loop", + "iterations": 200000, + "duration_ms": 1.317372, + "throughput_ops_per_sec": 151817406.16925213, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "failures": 196, + "samples": 200000 + } + }, + { + "name": "native-hip-benchmark", + "kind": "hip-native", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/build/benchmark_pipeline", + "iterations": null, + "duration_ms": 421.39535700000005, + "throughput_ops_per_sec": null, + "stdout_tail": "=== benchmark_pipeline ===\nWarmup launches: 100\nMeasured launches: 10000\nAverage pipeline launch latency: 26.77 us\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "native-hip-tests", + "kind": "hip-native", + "status": "passed", + "command": "ctest --test-dir /home/local/ai/projects/gfxGRAPH/build --output-on-failure", + "iterations": null, + "duration_ms": 1307.128235, + "throughput_ops_per_sec": null, + "stdout_tail": "Test project /home/local/ai/projects/gfxGRAPH/build\n Start 1: conditional\n1/5 Test #1: conditional ...................... Passed 0.16 sec\n Start 2: pipeline\n2/5 Test #2: pipeline ......................... Passed 0.17 sec\n Start 3: shapes\n3/5 Test #3: shapes ........................... Passed 0.30 sec\n Start 4: compositor\n4/5 Test #4: compositor ....................... Passed 0.33 sec\n Start 5: routing\n5/5 Test #5: routing .......................... Passed 0.23 sec\n\n100% tests passed, 0 tests failed out of 5\n\nTotal Test time (real) = 1.18 sec\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "readme-public-benchmark", + "kind": "python-public", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python benchmarks/bench_readme_public.py --output benchmarks/results/2026-06-16/readme-public-graph-candidate-main-python-baseline-rust-hip-cpp-20260616.json --run-count 3", + "iterations": null, + "duration_ms": 15728.520731, + "throughput_ops_per_sec": null, + "stdout_tail": "{\n \"timestamp_utc\": \"2026-06-16T14:35:34Z\",\n \"commit_sha\": \"fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e\",\n \"run_count\": 3,\n \"env\": {\n \"torch\": \"2.13.0a0+git53bbebe\",\n \"device\": \"AMD Radeon RX 6700 XT\",\n \"rocm\": {\n \"runtime_from_torch\": \"7.2.26015\",\n \"driver_from_hipconfig\": \"7.2.26015-fc0010cf6a\",\n \"runtime_from_rocminfo\": \"Runtime Version: 1.18\"\n },\n \"env\": {\n \"HSA_OVERRIDE_GFX_VERSION\": \"10.3.0\",\n \"PYTORCH_ROCM_ARCH\": null,\n \"GFXGRAPH\": \"1\",\n \"GFXGRAPH_VRAM_CAP\": null,\n \"SGLANG_RDNA2_KERNELS\": null,\n \"HIP_VISIBLE_DEVICES\": null,\n \"CUDA_VISIBLE_DEVICES\": null\n }\n },\n \"results\": [\n {\n \"workload\": \"decode_like_layernorm_gelu_chain_bs1_d1024\",\n \"iters\": 2000,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.1549857965001138,\n \"graph_ms_per_iter\": 0.1998931324997102,\n \"eager_ms_per_iter_runs\": [\n 0.1549857965001138,\n 0.1640711010004452,\n 0.15311025049959426\n ],\n \"graph_ms_per_iter_runs\": [\n 0.2069285454999772,\n 0.1998931324997102,\n 0.19416238700068789\n ],\n \"speedup_x\": 0.7753432774902284,\n \"fallback\": true\n },\n {\n \"workload\": \"mlp_bs32_d1024\",\n \"iters\": 1500,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.10666938533540815,\n \"graph_ms_per_iter\": 0.10732519333153807,\n \"eager_ms_per_iter_runs\": [\n 0.1069274439990598,\n 0.10666938533540815,\n 0.10644478533261766\n ],\n \"graph_ms_per_iter_runs\": [\n 0.10726372133406888,\n 0.10732519333153807,\n 0.10742609666582818\n ],\n \"speedup_x\": 0.9938895242042186,\n \"fallback\": true\n },\n {\n \"workload\": \"mlp_bs128_d2048\",\n \"iters\": 300,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.6379927899979521,\n \"graph_ms_per_iter\": 0.6386857666681559,\n \"eager_ms_per_iter_runs\": [\n 0.6359247166619753,\n 0.6391914200018315,\n 0.6379927899979521\n ],\n \"graph_ms_per_iter_runs\": [\n 0.6386857666681559,\n 0.6370811466695159,\n 0.640937836675827\n ],\n \"speedup_x\": 0.9989149959082086,\n \"fallback\": true\n }\n ]\n}\n", + "stderr_tail": "[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n", + "metrics": { + "all_workloads_fallback": true, + "fallback_workload_count": 3, + "fallback_workloads": [ + { + "eager_ms_per_iter": 0.1549857965001138, + "graph_ms_per_iter": 0.1998931324997102, + "speedup_x": 0.7753432774902284, + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024" + }, + { + "eager_ms_per_iter": 0.10666938533540817, + "graph_ms_per_iter": 0.10732519333153807, + "speedup_x": 0.9938895242042186, + "workload": "mlp_bs32_d1024" + }, + { + "eager_ms_per_iter": 0.6379927899979521, + "graph_ms_per_iter": 0.6386857666681559, + "speedup_x": 0.9989149959082086, + "workload": "mlp_bs128_d2048" + } + ], + "payload": { + "commit_sha": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "env": { + "device": "AMD Radeon RX 6700 XT", + "env": { + "CUDA_VISIBLE_DEVICES": null, + "GFXGRAPH": "1", + "GFXGRAPH_VRAM_CAP": null, + "HIP_VISIBLE_DEVICES": null, + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "PYTORCH_ROCM_ARCH": null, + "SGLANG_RDNA2_KERNELS": null + }, + "rocm": { + "driver_from_hipconfig": "7.2.26015-fc0010cf6a", + "runtime_from_rocminfo": "Runtime Version: 1.18", + "runtime_from_torch": "7.2.26015" + }, + "torch": "2.13.0a0+git53bbebe" + }, + "results": [ + { + "eager_ms_per_iter": 0.1549857965001138, + "eager_ms_per_iter_runs": [ + 0.1549857965001138, + 0.1640711010004452, + 0.15311025049959426 + ], + "fallback": true, + "graph_ms_per_iter": 0.1998931324997102, + "graph_ms_per_iter_runs": [ + 0.2069285454999772, + 0.1998931324997102, + 0.19416238700068789 + ], + "iters": 2000, + "run_count": 3, + "speedup_x": 0.7753432774902284, + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024" + }, + { + "eager_ms_per_iter": 0.10666938533540817, + "eager_ms_per_iter_runs": [ + 0.1069274439990598, + 0.10666938533540817, + 0.10644478533261766 + ], + "fallback": true, + "graph_ms_per_iter": 0.10732519333153807, + "graph_ms_per_iter_runs": [ + 0.10726372133406888, + 0.10732519333153807, + 0.10742609666582818 + ], + "iters": 1500, + "run_count": 3, + "speedup_x": 0.9938895242042186, + "workload": "mlp_bs32_d1024" + }, + { + "eager_ms_per_iter": 0.6379927899979521, + "eager_ms_per_iter_runs": [ + 0.6359247166619753, + 0.6391914200018315, + 0.6379927899979521 + ], + "fallback": true, + "graph_ms_per_iter": 0.6386857666681559, + "graph_ms_per_iter_runs": [ + 0.6386857666681559, + 0.6370811466695159, + 0.640937836675827 + ], + "iters": 300, + "run_count": 3, + "speedup_x": 0.9989149959082086, + "workload": "mlp_bs128_d2048" + } + ], + "run_count": 3, + "timestamp_utc": "2026-06-16T14:35:34Z" + }, + "workload_count": 3 + } + }, + { + "name": "legacy-python-microbenchmarks", + "kind": "python-micro", + "status": "skipped", + "command": "", + "iterations": null, + "duration_ms": null, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "skip_reason": "skipped; pass --include-python-micro to run legacy Python microbenchmarks" + } + } + ] +} diff --git a/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-installed-baseline-main-python-baseline-rust-hip-cpp-20260616.json b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-installed-baseline-main-python-baseline-rust-hip-cpp-20260616.json new file mode 100644 index 0000000..2fa17ee --- /dev/null +++ b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-installed-baseline-main-python-baseline-rust-hip-cpp-20260616.json @@ -0,0 +1,355 @@ +{ + "schema_version": "gfxgraph-benchmark-v1", + "report_kind": "benchmark_gate_phase_report", + "run_id": "main-python-baseline-rust-hip-cpp-20260616", + "phase": "installed-baseline", + "timestamp_utc": "2026-06-16T14:32:53Z", + "report_date": "2026-06-16", + "schema_path": "benchmarks/schemas/gfxgraph-benchmark-v1.schema.json", + "repo": { + "root": "/home/local/ai/projects/gfxGRAPH", + "branch": "rust-hip-cpp", + "commit": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "tracked_dirty": true + }, + "environment": { + "os": "Linux FRACTAL 6.8.0-90-generic #91-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 18 14:14:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux", + "rocm_path": "/opt/rocm", + "hipcc_version": "HIP version: 7.2.26015-fc0010cf6a\nAMD clang version 22.0.0git (https://github.com/RadeonOpenCompute/llvm-project roc-7.2.0 26014 7b800a19466229b8479a78de19143dc33c3ab9b5)\nTarget: x86_64-unknown-linux-gnu\nThread model: posix\nInstalledDir: /opt/rocm-7.2.0/lib/llvm/bin\nConfiguration file: /opt/rocm-7.2.0/lib/llvm/bin/clang++.cfg", + "env": { + "GFXGRAPH": null, + "GFXGRAPH_VALIDATE": null, + "GFXGRAPH_VRAM_CAP": null, + "HIP_VISIBLE_DEVICES": null, + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "ROCM_PATH": "/opt/rocm" + } + }, + "python": { + "executable": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python", + "imports": [ + { + "direct_url": { + "archive_info": {}, + "url": "file:///home/local/ai/projects/gfxGRAPH/dist/gfxgraph-1.0.1-py3-none-any.whl" + }, + "distribution": "gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph" + ], + "version": "1.0.1" + }, + { + "direct_url": { + "archive_info": {}, + "url": "file:///home/local/ai/projects/gfxGRAPH/dist/gfxgraph-1.0.1-py3-none-any.whl" + }, + "distribution": "gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "hipgraph_bridge", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/hipgraph_bridge/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/hipgraph_bridge" + ], + "version": "1.0.1" + }, + { + "direct_url": { + "dir_info": {}, + "url": "file:///home/local/ai/projects/gfxGRAPH/native" + }, + "distribution": "gfxgraph-native", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "gfxgraph_native", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph_native/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph_native" + ], + "version": "0.3.3" + }, + { + "distribution": "rs-gfxgraph", + "importable": false, + "name": "rs_gfxgraph", + "origin": null, + "search_locations": null, + "version_error": "PackageNotFoundError('rs-gfxgraph')" + }, + { + "distribution": "rs-gfxgraph-stats", + "importable": false, + "name": "rs_gfxgraph_stats", + "origin": null, + "search_locations": null, + "version_error": "PackageNotFoundError('rs-gfxgraph-stats')" + } + ], + "prefix": "/home/local/ai/projects/gfxGRAPH/.venv", + "version": "3.12.7 (main, Oct 16 2024, 04:37:19) [Clang 18.1.8 ]" + }, + "package_state": { + "target_import_policy": "site-packages", + "graph_enabled": false, + "allow_package_changes": true, + "package_actions": [] + }, + "gate_checks": [ + { + "name": "python-import-isolation", + "status": "passed", + "message": "installed-baseline imports match site-packages policy", + "details": { + "checked": [ + { + "importable": true, + "in_repo": false, + "module": "gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph/__init__.py" + }, + { + "importable": true, + "in_repo": false, + "module": "hipgraph_bridge", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/hipgraph_bridge/__init__.py" + }, + { + "importable": true, + "in_repo": false, + "module": "gfxgraph_native", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph_native/__init__.py" + } + ] + } + } + ], + "benchmarks": [ + { + "name": "python-import-provenance", + "kind": "package-provenance", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python -c ", + "iterations": null, + "duration_ms": 68.106157, + "throughput_ops_per_sec": null, + "stdout_tail": "{\"executable\": \"/home/local/ai/projects/gfxGRAPH/.venv/bin/python\", \"imports\": [{\"direct_url\": {\"archive_info\": {}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/dist/gfxgraph-1.0.1-py3-none-any.whl\"}, \"distribution\": \"gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"gfxgraph\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph\"], \"version\": \"1.0.1\"}, {\"direct_url\": {\"archive_info\": {}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/dist/gfxgraph-1.0.1-py3-none-any.whl\"}, \"distribution\": \"gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"hipgraph_bridge\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/hipgraph_bridge/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/hipgraph_bridge\"], \"version\": \"1.0.1\"}, {\"direct_url\": {\"dir_info\": {}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/native\"}, \"distribution\": \"gfxgraph-native\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"gfxgraph_native\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph_native/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph_native\"], \"version\": \"0.3.3\"}, {\"distribution\": \"rs-gfxgraph\", \"importable\": false, \"name\": \"rs_gfxgraph\", \"origin\": null, \"search_locations\": null, \"version_error\": \"PackageNotFoundError('rs-gfxgraph')\"}, {\"distribution\": \"rs-gfxgraph-stats\", \"importable\": false, \"name\": \"rs_gfxgraph_stats\", \"origin\": null, \"search_locations\": null, \"version_error\": \"PackageNotFoundError('rs-gfxgraph-stats')\"}], \"prefix\": \"/home/local/ai/projects/gfxGRAPH/.venv\", \"version\": \"3.12.7 (main, Oct 16 2024, 04:37:19) [Clang 18.1.8 ]\"}\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "torch-capture-policy", + "kind": "capture-policy", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python -c ", + "iterations": null, + "duration_ms": 21640.553087, + "throughput_ops_per_sec": null, + "stdout_tail": "{\"GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE\": null, \"cuda_available\": true, \"cuda_execution_error\": \"CUDA execution probe passed\", \"cuda_execution_usable\": true, \"device\": \"AMD Radeon RX 6700 XT\", \"torch\": \"2.13.0a0+git53bbebe\", \"torch_graph_capture_block_reason\": \"high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in\", \"torch_hip\": \"7.2.26015\", \"unsafe_torch_graph_capture_enabled\": false}\n", + "stderr_tail": "", + "metrics": { + "probe": { + "GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE": null, + "cuda_available": true, + "cuda_execution_error": "CUDA execution probe passed", + "cuda_execution_usable": true, + "device": "AMD Radeon RX 6700 XT", + "torch": "2.13.0a0+git53bbebe", + "torch_graph_capture_block_reason": "high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in", + "torch_hip": "7.2.26015", + "unsafe_torch_graph_capture_enabled": false + } + } + }, + { + "name": "rust-bucket-router-core", + "kind": "rust-micro", + "status": "passed", + "command": "in-process BucketRouterCore::route loop", + "iterations": 200000, + "duration_ms": 56.899409, + "throughput_ops_per_sec": 3514974.9973677234, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "bucket_count": 10, + "ready_routes": 200000 + } + }, + { + "name": "rust-stats-sample-update", + "kind": "rust-micro", + "status": "passed", + "command": "in-process GfxGraphStatsSample update loop", + "iterations": 200000, + "duration_ms": 1.3558109999999999, + "throughput_ops_per_sec": 147513185.83489883, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "failures": 196, + "samples": 200000 + } + }, + { + "name": "native-hip-benchmark", + "kind": "hip-native", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/build/benchmark_pipeline", + "iterations": null, + "duration_ms": 400.380518, + "throughput_ops_per_sec": null, + "stdout_tail": "=== benchmark_pipeline ===\nWarmup launches: 100\nMeasured launches: 10000\nAverage pipeline launch latency: 26.40 us\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "native-hip-tests", + "kind": "hip-native", + "status": "passed", + "command": "ctest --test-dir /home/local/ai/projects/gfxGRAPH/build --output-on-failure", + "iterations": null, + "duration_ms": 1310.670206, + "throughput_ops_per_sec": null, + "stdout_tail": "Test project /home/local/ai/projects/gfxGRAPH/build\n Start 1: conditional\n1/5 Test #1: conditional ...................... Passed 0.16 sec\n Start 2: pipeline\n2/5 Test #2: pipeline ......................... Passed 0.17 sec\n Start 3: shapes\n3/5 Test #3: shapes ........................... Passed 0.30 sec\n Start 4: compositor\n4/5 Test #4: compositor ....................... Passed 0.33 sec\n Start 5: routing\n5/5 Test #5: routing .......................... Passed 0.23 sec\n\n100% tests passed, 0 tests failed out of 5\n\nTotal Test time (real) = 1.19 sec\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "readme-public-benchmark", + "kind": "python-public", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python benchmarks/bench_readme_public.py --output benchmarks/results/2026-06-16/readme-public-installed-baseline-main-python-baseline-rust-hip-cpp-20260616.json --run-count 3", + "iterations": null, + "duration_ms": 14230.535404, + "throughput_ops_per_sec": null, + "stdout_tail": "{\n \"timestamp_utc\": \"2026-06-16T14:33:30Z\",\n \"commit_sha\": \"fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e\",\n \"run_count\": 3,\n \"env\": {\n \"torch\": \"2.13.0a0+git53bbebe\",\n \"device\": \"AMD Radeon RX 6700 XT\",\n \"rocm\": {\n \"runtime_from_torch\": \"7.2.26015\",\n \"driver_from_hipconfig\": \"7.2.26015-fc0010cf6a\",\n \"runtime_from_rocminfo\": \"Runtime Version: 1.18\"\n },\n \"env\": {\n \"HSA_OVERRIDE_GFX_VERSION\": \"10.3.0\",\n \"PYTORCH_ROCM_ARCH\": null,\n \"GFXGRAPH\": null,\n \"GFXGRAPH_VRAM_CAP\": null,\n \"SGLANG_RDNA2_KERNELS\": null,\n \"HIP_VISIBLE_DEVICES\": null,\n \"CUDA_VISIBLE_DEVICES\": null\n }\n },\n \"results\": [\n {\n \"workload\": \"decode_like_layernorm_gelu_chain_bs1_d1024\",\n \"iters\": 2000,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.16348431649930717,\n \"graph_ms_per_iter\": 0.20575329900020733,\n \"eager_ms_per_iter_runs\": [\n 0.16643990649936313,\n 0.16348431649930717,\n 0.16239262800081633\n ],\n \"graph_ms_per_iter_runs\": [\n 0.21657518900065043,\n 0.20296334449994902,\n 0.20575329900020733\n ],\n \"speedup_x\": 0.794564739878812,\n \"fallback\": true\n },\n {\n \"workload\": \"mlp_bs32_d1024\",\n \"iters\": 1500,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.10626193933421746,\n \"graph_ms_per_iter\": 0.10674115866519666,\n \"eager_ms_per_iter_runs\": [\n 0.10626193933421746,\n 0.10758362066796205,\n 0.10621896066732006\n ],\n \"graph_ms_per_iter_runs\": [\n 0.10652992466687768,\n 0.10690318066675293,\n 0.10674115866519666\n ],\n \"speedup_x\": 0.9955104541025049,\n \"fallback\": true\n },\n {\n \"workload\": \"mlp_bs128_d2048\",\n \"iters\": 300,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.6403489033255028,\n \"graph_ms_per_iter\": 0.6404162000035285,\n \"eager_ms_per_iter_runs\": [\n 0.6403489033255028,\n 0.6421439200009141,\n 0.6369884666613265\n ],\n \"graph_ms_per_iter_runs\": [\n 0.6404162000035285,\n 0.6404631666737259,\n 0.6363502833240394\n ],\n \"speedup_x\": 0.9998949172771935,\n \"fallback\": true\n }\n ]\n}\n", + "stderr_tail": "[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n", + "metrics": { + "all_workloads_fallback": true, + "fallback_workload_count": 3, + "fallback_workloads": [ + { + "eager_ms_per_iter": 0.16348431649930717, + "graph_ms_per_iter": 0.2057532990002073, + "speedup_x": 0.794564739878812, + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024" + }, + { + "eager_ms_per_iter": 0.10626193933421746, + "graph_ms_per_iter": 0.10674115866519666, + "speedup_x": 0.9955104541025048, + "workload": "mlp_bs32_d1024" + }, + { + "eager_ms_per_iter": 0.6403489033255028, + "graph_ms_per_iter": 0.6404162000035285, + "speedup_x": 0.9998949172771936, + "workload": "mlp_bs128_d2048" + } + ], + "payload": { + "commit_sha": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "env": { + "device": "AMD Radeon RX 6700 XT", + "env": { + "CUDA_VISIBLE_DEVICES": null, + "GFXGRAPH": null, + "GFXGRAPH_VRAM_CAP": null, + "HIP_VISIBLE_DEVICES": null, + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "PYTORCH_ROCM_ARCH": null, + "SGLANG_RDNA2_KERNELS": null + }, + "rocm": { + "driver_from_hipconfig": "7.2.26015-fc0010cf6a", + "runtime_from_rocminfo": "Runtime Version: 1.18", + "runtime_from_torch": "7.2.26015" + }, + "torch": "2.13.0a0+git53bbebe" + }, + "results": [ + { + "eager_ms_per_iter": 0.16348431649930717, + "eager_ms_per_iter_runs": [ + 0.16643990649936313, + 0.16348431649930717, + 0.16239262800081633 + ], + "fallback": true, + "graph_ms_per_iter": 0.2057532990002073, + "graph_ms_per_iter_runs": [ + 0.21657518900065045, + 0.20296334449994904, + 0.2057532990002073 + ], + "iters": 2000, + "run_count": 3, + "speedup_x": 0.794564739878812, + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024" + }, + { + "eager_ms_per_iter": 0.10626193933421746, + "eager_ms_per_iter_runs": [ + 0.10626193933421746, + 0.10758362066796204, + 0.10621896066732006 + ], + "fallback": true, + "graph_ms_per_iter": 0.10674115866519666, + "graph_ms_per_iter_runs": [ + 0.10652992466687768, + 0.10690318066675292, + 0.10674115866519666 + ], + "iters": 1500, + "run_count": 3, + "speedup_x": 0.9955104541025048, + "workload": "mlp_bs32_d1024" + }, + { + "eager_ms_per_iter": 0.6403489033255028, + "eager_ms_per_iter_runs": [ + 0.6403489033255028, + 0.6421439200009141, + 0.6369884666613265 + ], + "fallback": true, + "graph_ms_per_iter": 0.6404162000035285, + "graph_ms_per_iter_runs": [ + 0.6404162000035285, + 0.6404631666737259, + 0.6363502833240394 + ], + "iters": 300, + "run_count": 3, + "speedup_x": 0.9998949172771936, + "workload": "mlp_bs128_d2048" + } + ], + "run_count": 3, + "timestamp_utc": "2026-06-16T14:33:30Z" + }, + "workload_count": 3 + } + }, + { + "name": "legacy-python-microbenchmarks", + "kind": "python-micro", + "status": "skipped", + "command": "", + "iterations": null, + "duration_ms": null, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "skip_reason": "skipped; pass --include-python-micro to run legacy Python microbenchmarks" + } + } + ] +} diff --git a/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-installed-graph-enabled-main-python-baseline-rust-hip-cpp-20260616.json b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-installed-graph-enabled-main-python-baseline-rust-hip-cpp-20260616.json new file mode 100644 index 0000000..06e3b19 --- /dev/null +++ b/benchmarks/results/2026-06-16/gfxgraph-benchmark-v1-installed-graph-enabled-main-python-baseline-rust-hip-cpp-20260616.json @@ -0,0 +1,355 @@ +{ + "schema_version": "gfxgraph-benchmark-v1", + "report_kind": "benchmark_gate_phase_report", + "run_id": "main-python-baseline-rust-hip-cpp-20260616", + "phase": "installed-graph-enabled", + "timestamp_utc": "2026-06-16T14:32:53Z", + "report_date": "2026-06-16", + "schema_path": "benchmarks/schemas/gfxgraph-benchmark-v1.schema.json", + "repo": { + "root": "/home/local/ai/projects/gfxGRAPH", + "branch": "rust-hip-cpp", + "commit": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "tracked_dirty": true + }, + "environment": { + "os": "Linux FRACTAL 6.8.0-90-generic #91-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 18 14:14:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux", + "rocm_path": "/opt/rocm", + "hipcc_version": "HIP version: 7.2.26015-fc0010cf6a\nAMD clang version 22.0.0git (https://github.com/RadeonOpenCompute/llvm-project roc-7.2.0 26014 7b800a19466229b8479a78de19143dc33c3ab9b5)\nTarget: x86_64-unknown-linux-gnu\nThread model: posix\nInstalledDir: /opt/rocm-7.2.0/lib/llvm/bin\nConfiguration file: /opt/rocm-7.2.0/lib/llvm/bin/clang++.cfg", + "env": { + "GFXGRAPH": null, + "GFXGRAPH_VALIDATE": null, + "GFXGRAPH_VRAM_CAP": null, + "HIP_VISIBLE_DEVICES": null, + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "ROCM_PATH": "/opt/rocm" + } + }, + "python": { + "executable": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python", + "imports": [ + { + "direct_url": { + "archive_info": {}, + "url": "file:///home/local/ai/projects/gfxGRAPH/dist/gfxgraph-1.0.1-py3-none-any.whl" + }, + "distribution": "gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph" + ], + "version": "1.0.1" + }, + { + "direct_url": { + "archive_info": {}, + "url": "file:///home/local/ai/projects/gfxGRAPH/dist/gfxgraph-1.0.1-py3-none-any.whl" + }, + "distribution": "gfxgraph", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "hipgraph_bridge", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/hipgraph_bridge/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/hipgraph_bridge" + ], + "version": "1.0.1" + }, + { + "direct_url": { + "dir_info": {}, + "url": "file:///home/local/ai/projects/gfxGRAPH/native" + }, + "distribution": "gfxgraph-native", + "distribution_location": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages", + "importable": true, + "name": "gfxgraph_native", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph_native/__init__.py", + "search_locations": [ + "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph_native" + ], + "version": "0.3.3" + }, + { + "distribution": "rs-gfxgraph", + "importable": false, + "name": "rs_gfxgraph", + "origin": null, + "search_locations": null, + "version_error": "PackageNotFoundError('rs-gfxgraph')" + }, + { + "distribution": "rs-gfxgraph-stats", + "importable": false, + "name": "rs_gfxgraph_stats", + "origin": null, + "search_locations": null, + "version_error": "PackageNotFoundError('rs-gfxgraph-stats')" + } + ], + "prefix": "/home/local/ai/projects/gfxGRAPH/.venv", + "version": "3.12.7 (main, Oct 16 2024, 04:37:19) [Clang 18.1.8 ]" + }, + "package_state": { + "target_import_policy": "site-packages", + "graph_enabled": true, + "allow_package_changes": true, + "package_actions": [] + }, + "gate_checks": [ + { + "name": "python-import-isolation", + "status": "passed", + "message": "installed-graph-enabled imports match site-packages policy", + "details": { + "checked": [ + { + "importable": true, + "in_repo": false, + "module": "gfxgraph", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph/__init__.py" + }, + { + "importable": true, + "in_repo": false, + "module": "hipgraph_bridge", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/hipgraph_bridge/__init__.py" + }, + { + "importable": true, + "in_repo": false, + "module": "gfxgraph_native", + "origin": "/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph_native/__init__.py" + } + ] + } + } + ], + "benchmarks": [ + { + "name": "python-import-provenance", + "kind": "package-provenance", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python -c ", + "iterations": null, + "duration_ms": 71.888368, + "throughput_ops_per_sec": null, + "stdout_tail": "{\"executable\": \"/home/local/ai/projects/gfxGRAPH/.venv/bin/python\", \"imports\": [{\"direct_url\": {\"archive_info\": {}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/dist/gfxgraph-1.0.1-py3-none-any.whl\"}, \"distribution\": \"gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"gfxgraph\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph\"], \"version\": \"1.0.1\"}, {\"direct_url\": {\"archive_info\": {}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/dist/gfxgraph-1.0.1-py3-none-any.whl\"}, \"distribution\": \"gfxgraph\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"hipgraph_bridge\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/hipgraph_bridge/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/hipgraph_bridge\"], \"version\": \"1.0.1\"}, {\"direct_url\": {\"dir_info\": {}, \"url\": \"file:///home/local/ai/projects/gfxGRAPH/native\"}, \"distribution\": \"gfxgraph-native\", \"distribution_location\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages\", \"importable\": true, \"name\": \"gfxgraph_native\", \"origin\": \"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph_native/__init__.py\", \"search_locations\": [\"/home/local/ai/projects/gfxGRAPH/.venv/lib/python3.12/site-packages/gfxgraph_native\"], \"version\": \"0.3.3\"}, {\"distribution\": \"rs-gfxgraph\", \"importable\": false, \"name\": \"rs_gfxgraph\", \"origin\": null, \"search_locations\": null, \"version_error\": \"PackageNotFoundError('rs-gfxgraph')\"}, {\"distribution\": \"rs-gfxgraph-stats\", \"importable\": false, \"name\": \"rs_gfxgraph_stats\", \"origin\": null, \"search_locations\": null, \"version_error\": \"PackageNotFoundError('rs-gfxgraph-stats')\"}], \"prefix\": \"/home/local/ai/projects/gfxGRAPH/.venv\", \"version\": \"3.12.7 (main, Oct 16 2024, 04:37:19) [Clang 18.1.8 ]\"}\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "torch-capture-policy", + "kind": "capture-policy", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python -c ", + "iterations": null, + "duration_ms": 19437.703744, + "throughput_ops_per_sec": null, + "stdout_tail": "{\"GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE\": null, \"cuda_available\": true, \"cuda_execution_error\": \"CUDA execution probe passed\", \"cuda_execution_usable\": true, \"device\": \"AMD Radeon RX 6700 XT\", \"torch\": \"2.13.0a0+git53bbebe\", \"torch_graph_capture_block_reason\": \"high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in\", \"torch_hip\": \"7.2.26015\", \"unsafe_torch_graph_capture_enabled\": false}\n", + "stderr_tail": "", + "metrics": { + "probe": { + "GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE": null, + "cuda_available": true, + "cuda_execution_error": "CUDA execution probe passed", + "cuda_execution_usable": true, + "device": "AMD Radeon RX 6700 XT", + "torch": "2.13.0a0+git53bbebe", + "torch_graph_capture_block_reason": "high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in", + "torch_hip": "7.2.26015", + "unsafe_torch_graph_capture_enabled": false + } + } + }, + { + "name": "rust-bucket-router-core", + "kind": "rust-micro", + "status": "passed", + "command": "in-process BucketRouterCore::route loop", + "iterations": 200000, + "duration_ms": 56.51204, + "throughput_ops_per_sec": 3539068.8426749413, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "bucket_count": 10, + "ready_routes": 200000 + } + }, + { + "name": "rust-stats-sample-update", + "kind": "rust-micro", + "status": "passed", + "command": "in-process GfxGraphStatsSample update loop", + "iterations": 200000, + "duration_ms": 1.335102, + "throughput_ops_per_sec": 149801288.59068447, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "failures": 196, + "samples": 200000 + } + }, + { + "name": "native-hip-benchmark", + "kind": "hip-native", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/build/benchmark_pipeline", + "iterations": null, + "duration_ms": 399.79535300000003, + "throughput_ops_per_sec": null, + "stdout_tail": "=== benchmark_pipeline ===\nWarmup launches: 100\nMeasured launches: 10000\nAverage pipeline launch latency: 25.68 us\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "native-hip-tests", + "kind": "hip-native", + "status": "passed", + "command": "ctest --test-dir /home/local/ai/projects/gfxGRAPH/build --output-on-failure", + "iterations": null, + "duration_ms": 1286.360503, + "throughput_ops_per_sec": null, + "stdout_tail": "Test project /home/local/ai/projects/gfxGRAPH/build\n Start 1: conditional\n1/5 Test #1: conditional ...................... Passed 0.16 sec\n Start 2: pipeline\n2/5 Test #2: pipeline ......................... Passed 0.16 sec\n Start 3: shapes\n3/5 Test #3: shapes ........................... Passed 0.30 sec\n Start 4: compositor\n4/5 Test #4: compositor ....................... Passed 0.31 sec\n Start 5: routing\n5/5 Test #5: routing .......................... Passed 0.22 sec\n\n100% tests passed, 0 tests failed out of 5\n\nTotal Test time (real) = 1.16 sec\n", + "stderr_tail": "", + "metrics": {} + }, + { + "name": "readme-public-benchmark", + "kind": "python-public", + "status": "passed", + "command": "/home/local/ai/projects/gfxGRAPH/.venv/bin/python benchmarks/bench_readme_public.py --output benchmarks/results/2026-06-16/readme-public-installed-graph-enabled-main-python-baseline-rust-hip-cpp-20260616.json --run-count 3", + "iterations": null, + "duration_ms": 15795.552422, + "throughput_ops_per_sec": null, + "stdout_tail": "{\n \"timestamp_utc\": \"2026-06-16T14:34:07Z\",\n \"commit_sha\": \"fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e\",\n \"run_count\": 3,\n \"env\": {\n \"torch\": \"2.13.0a0+git53bbebe\",\n \"device\": \"AMD Radeon RX 6700 XT\",\n \"rocm\": {\n \"runtime_from_torch\": \"7.2.26015\",\n \"driver_from_hipconfig\": \"7.2.26015-fc0010cf6a\",\n \"runtime_from_rocminfo\": \"Runtime Version: 1.18\"\n },\n \"env\": {\n \"HSA_OVERRIDE_GFX_VERSION\": \"10.3.0\",\n \"PYTORCH_ROCM_ARCH\": null,\n \"GFXGRAPH\": \"1\",\n \"GFXGRAPH_VRAM_CAP\": null,\n \"SGLANG_RDNA2_KERNELS\": null,\n \"HIP_VISIBLE_DEVICES\": null,\n \"CUDA_VISIBLE_DEVICES\": null\n }\n },\n \"results\": [\n {\n \"workload\": \"decode_like_layernorm_gelu_chain_bs1_d1024\",\n \"iters\": 2000,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.16572348100089584,\n \"graph_ms_per_iter\": 0.21004998950047593,\n \"eager_ms_per_iter_runs\": [\n 0.16572348100089584,\n 0.1741914234989963,\n 0.1650394204989425\n ],\n \"graph_ms_per_iter_runs\": [\n 0.21257842700106266,\n 0.21004998950047593,\n 0.19883593099984864\n ],\n \"speedup_x\": 0.788971622398107,\n \"fallback\": true\n },\n {\n \"workload\": \"mlp_bs32_d1024\",\n \"iters\": 1500,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.1065557226659924,\n \"graph_ms_per_iter\": 0.10684876866677466,\n \"eager_ms_per_iter_runs\": [\n 0.10651393800071673,\n 0.10730442200050068,\n 0.1065557226659924\n ],\n \"graph_ms_per_iter_runs\": [\n 0.10686785466774988,\n 0.10647171933427065,\n 0.10684876866677466\n ],\n \"speedup_x\": 0.9972573759675587,\n \"fallback\": true\n },\n {\n \"workload\": \"mlp_bs128_d2048\",\n \"iters\": 300,\n \"run_count\": 3,\n \"eager_ms_per_iter\": 0.634038509997481,\n \"graph_ms_per_iter\": 0.6388252400089792,\n \"eager_ms_per_iter_runs\": [\n 0.634038509997481,\n 0.6393794599959316,\n 0.6335876566663501\n ],\n \"graph_ms_per_iter_runs\": [\n 0.6385631166631356,\n 0.6388252400089792,\n 0.6396404866609373\n ],\n \"speedup_x\": 0.992506980451444,\n \"fallback\": true\n }\n ]\n}\n", + "stderr_tail": "[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n[gfxgRAPH] WARNING: Graph capture_begin failed: high-level torch.cuda.graph capture is disabled by default on ROCm/HIP 7.2.26015; set GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE=1 to opt in — using eager fallback\n", + "metrics": { + "all_workloads_fallback": true, + "fallback_workload_count": 3, + "fallback_workloads": [ + { + "eager_ms_per_iter": 0.16572348100089584, + "graph_ms_per_iter": 0.21004998950047593, + "speedup_x": 0.788971622398107, + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024" + }, + { + "eager_ms_per_iter": 0.1065557226659924, + "graph_ms_per_iter": 0.10684876866677466, + "speedup_x": 0.9972573759675588, + "workload": "mlp_bs32_d1024" + }, + { + "eager_ms_per_iter": 0.634038509997481, + "graph_ms_per_iter": 0.6388252400089792, + "speedup_x": 0.992506980451444, + "workload": "mlp_bs128_d2048" + } + ], + "payload": { + "commit_sha": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "env": { + "device": "AMD Radeon RX 6700 XT", + "env": { + "CUDA_VISIBLE_DEVICES": null, + "GFXGRAPH": "1", + "GFXGRAPH_VRAM_CAP": null, + "HIP_VISIBLE_DEVICES": null, + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "PYTORCH_ROCM_ARCH": null, + "SGLANG_RDNA2_KERNELS": null + }, + "rocm": { + "driver_from_hipconfig": "7.2.26015-fc0010cf6a", + "runtime_from_rocminfo": "Runtime Version: 1.18", + "runtime_from_torch": "7.2.26015" + }, + "torch": "2.13.0a0+git53bbebe" + }, + "results": [ + { + "eager_ms_per_iter": 0.16572348100089584, + "eager_ms_per_iter_runs": [ + 0.16572348100089584, + 0.1741914234989963, + 0.1650394204989425 + ], + "fallback": true, + "graph_ms_per_iter": 0.21004998950047593, + "graph_ms_per_iter_runs": [ + 0.21257842700106264, + 0.21004998950047593, + 0.19883593099984864 + ], + "iters": 2000, + "run_count": 3, + "speedup_x": 0.788971622398107, + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024" + }, + { + "eager_ms_per_iter": 0.1065557226659924, + "eager_ms_per_iter_runs": [ + 0.10651393800071672, + 0.10730442200050068, + 0.1065557226659924 + ], + "fallback": true, + "graph_ms_per_iter": 0.10684876866677466, + "graph_ms_per_iter_runs": [ + 0.10686785466774988, + 0.10647171933427065, + 0.10684876866677466 + ], + "iters": 1500, + "run_count": 3, + "speedup_x": 0.9972573759675588, + "workload": "mlp_bs32_d1024" + }, + { + "eager_ms_per_iter": 0.634038509997481, + "eager_ms_per_iter_runs": [ + 0.634038509997481, + 0.6393794599959316, + 0.6335876566663501 + ], + "fallback": true, + "graph_ms_per_iter": 0.6388252400089792, + "graph_ms_per_iter_runs": [ + 0.6385631166631356, + 0.6388252400089792, + 0.6396404866609373 + ], + "iters": 300, + "run_count": 3, + "speedup_x": 0.992506980451444, + "workload": "mlp_bs128_d2048" + } + ], + "run_count": 3, + "timestamp_utc": "2026-06-16T14:34:07Z" + }, + "workload_count": 3 + } + }, + { + "name": "legacy-python-microbenchmarks", + "kind": "python-micro", + "status": "skipped", + "command": "", + "iterations": null, + "duration_ms": null, + "throughput_ops_per_sec": null, + "stdout_tail": "", + "stderr_tail": "", + "metrics": { + "skip_reason": "skipped; pass --include-python-micro to run legacy Python microbenchmarks" + } + } + ] +} diff --git a/benchmarks/results/2026-06-16/readme-public-clean-candidate-main-python-baseline-rust-hip-cpp-20260616.json b/benchmarks/results/2026-06-16/readme-public-clean-candidate-main-python-baseline-rust-hip-cpp-20260616.json new file mode 100644 index 0000000..6cb8b8f --- /dev/null +++ b/benchmarks/results/2026-06-16/readme-public-clean-candidate-main-python-baseline-rust-hip-cpp-20260616.json @@ -0,0 +1,82 @@ +{ + "timestamp_utc": "2026-06-16T14:34:49Z", + "commit_sha": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "run_count": 3, + "env": { + "torch": "2.13.0a0+git53bbebe", + "device": "AMD Radeon RX 6700 XT", + "rocm": { + "runtime_from_torch": "7.2.26015", + "driver_from_hipconfig": "7.2.26015-fc0010cf6a", + "runtime_from_rocminfo": "Runtime Version: 1.18" + }, + "env": { + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "PYTORCH_ROCM_ARCH": null, + "GFXGRAPH": null, + "GFXGRAPH_VRAM_CAP": null, + "SGLANG_RDNA2_KERNELS": null, + "HIP_VISIBLE_DEVICES": null, + "CUDA_VISIBLE_DEVICES": null + } + }, + "results": [ + { + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024", + "iters": 2000, + "run_count": 3, + "eager_ms_per_iter": 0.15820250050092, + "graph_ms_per_iter": 0.19302421149950533, + "eager_ms_per_iter_runs": [ + 0.15823810899928503, + 0.15820250050092, + 0.1576413214988861 + ], + "graph_ms_per_iter_runs": [ + 0.19224454849972972, + 0.19346232400130248, + 0.19302421149950533 + ], + "speedup_x": 0.819599257895818, + "fallback": true + }, + { + "workload": "mlp_bs32_d1024", + "iters": 1500, + "run_count": 3, + "eager_ms_per_iter": 0.10682662866505173, + "graph_ms_per_iter": 0.10702674200001638, + "eager_ms_per_iter_runs": [ + 0.10682662866505173, + 0.10648085199985265, + 0.10685669400118059 + ], + "graph_ms_per_iter_runs": [ + 0.10702674200001638, + 0.10526757266537363, + 0.1072387293340095 + ], + "speedup_x": 0.9981302492141205, + "fallback": true + }, + { + "workload": "mlp_bs128_d2048", + "iters": 300, + "run_count": 3, + "eager_ms_per_iter": 0.6399757700031236, + "graph_ms_per_iter": 0.6383206166598635, + "eager_ms_per_iter_runs": [ + 0.6399757700031236, + 0.6404388566685763, + 0.6358656200003073 + ], + "graph_ms_per_iter_runs": [ + 0.6370942166662038, + 0.6383206166598635, + 0.6383977166721403 + ], + "speedup_x": 1.002592981176013, + "fallback": true + } + ] +} \ No newline at end of file diff --git a/benchmarks/results/2026-06-16/readme-public-graph-candidate-main-python-baseline-rust-hip-cpp-20260616.json b/benchmarks/results/2026-06-16/readme-public-graph-candidate-main-python-baseline-rust-hip-cpp-20260616.json new file mode 100644 index 0000000..5b4b5b4 --- /dev/null +++ b/benchmarks/results/2026-06-16/readme-public-graph-candidate-main-python-baseline-rust-hip-cpp-20260616.json @@ -0,0 +1,82 @@ +{ + "timestamp_utc": "2026-06-16T14:35:34Z", + "commit_sha": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "run_count": 3, + "env": { + "torch": "2.13.0a0+git53bbebe", + "device": "AMD Radeon RX 6700 XT", + "rocm": { + "runtime_from_torch": "7.2.26015", + "driver_from_hipconfig": "7.2.26015-fc0010cf6a", + "runtime_from_rocminfo": "Runtime Version: 1.18" + }, + "env": { + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "PYTORCH_ROCM_ARCH": null, + "GFXGRAPH": "1", + "GFXGRAPH_VRAM_CAP": null, + "SGLANG_RDNA2_KERNELS": null, + "HIP_VISIBLE_DEVICES": null, + "CUDA_VISIBLE_DEVICES": null + } + }, + "results": [ + { + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024", + "iters": 2000, + "run_count": 3, + "eager_ms_per_iter": 0.1549857965001138, + "graph_ms_per_iter": 0.1998931324997102, + "eager_ms_per_iter_runs": [ + 0.1549857965001138, + 0.1640711010004452, + 0.15311025049959426 + ], + "graph_ms_per_iter_runs": [ + 0.2069285454999772, + 0.1998931324997102, + 0.19416238700068789 + ], + "speedup_x": 0.7753432774902284, + "fallback": true + }, + { + "workload": "mlp_bs32_d1024", + "iters": 1500, + "run_count": 3, + "eager_ms_per_iter": 0.10666938533540815, + "graph_ms_per_iter": 0.10732519333153807, + "eager_ms_per_iter_runs": [ + 0.1069274439990598, + 0.10666938533540815, + 0.10644478533261766 + ], + "graph_ms_per_iter_runs": [ + 0.10726372133406888, + 0.10732519333153807, + 0.10742609666582818 + ], + "speedup_x": 0.9938895242042186, + "fallback": true + }, + { + "workload": "mlp_bs128_d2048", + "iters": 300, + "run_count": 3, + "eager_ms_per_iter": 0.6379927899979521, + "graph_ms_per_iter": 0.6386857666681559, + "eager_ms_per_iter_runs": [ + 0.6359247166619753, + 0.6391914200018315, + 0.6379927899979521 + ], + "graph_ms_per_iter_runs": [ + 0.6386857666681559, + 0.6370811466695159, + 0.640937836675827 + ], + "speedup_x": 0.9989149959082086, + "fallback": true + } + ] +} \ No newline at end of file diff --git a/benchmarks/results/2026-06-16/readme-public-installed-baseline-main-python-baseline-rust-hip-cpp-20260616.json b/benchmarks/results/2026-06-16/readme-public-installed-baseline-main-python-baseline-rust-hip-cpp-20260616.json new file mode 100644 index 0000000..a6de60c --- /dev/null +++ b/benchmarks/results/2026-06-16/readme-public-installed-baseline-main-python-baseline-rust-hip-cpp-20260616.json @@ -0,0 +1,82 @@ +{ + "timestamp_utc": "2026-06-16T14:33:30Z", + "commit_sha": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "run_count": 3, + "env": { + "torch": "2.13.0a0+git53bbebe", + "device": "AMD Radeon RX 6700 XT", + "rocm": { + "runtime_from_torch": "7.2.26015", + "driver_from_hipconfig": "7.2.26015-fc0010cf6a", + "runtime_from_rocminfo": "Runtime Version: 1.18" + }, + "env": { + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "PYTORCH_ROCM_ARCH": null, + "GFXGRAPH": null, + "GFXGRAPH_VRAM_CAP": null, + "SGLANG_RDNA2_KERNELS": null, + "HIP_VISIBLE_DEVICES": null, + "CUDA_VISIBLE_DEVICES": null + } + }, + "results": [ + { + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024", + "iters": 2000, + "run_count": 3, + "eager_ms_per_iter": 0.16348431649930717, + "graph_ms_per_iter": 0.20575329900020733, + "eager_ms_per_iter_runs": [ + 0.16643990649936313, + 0.16348431649930717, + 0.16239262800081633 + ], + "graph_ms_per_iter_runs": [ + 0.21657518900065043, + 0.20296334449994902, + 0.20575329900020733 + ], + "speedup_x": 0.794564739878812, + "fallback": true + }, + { + "workload": "mlp_bs32_d1024", + "iters": 1500, + "run_count": 3, + "eager_ms_per_iter": 0.10626193933421746, + "graph_ms_per_iter": 0.10674115866519666, + "eager_ms_per_iter_runs": [ + 0.10626193933421746, + 0.10758362066796205, + 0.10621896066732006 + ], + "graph_ms_per_iter_runs": [ + 0.10652992466687768, + 0.10690318066675293, + 0.10674115866519666 + ], + "speedup_x": 0.9955104541025049, + "fallback": true + }, + { + "workload": "mlp_bs128_d2048", + "iters": 300, + "run_count": 3, + "eager_ms_per_iter": 0.6403489033255028, + "graph_ms_per_iter": 0.6404162000035285, + "eager_ms_per_iter_runs": [ + 0.6403489033255028, + 0.6421439200009141, + 0.6369884666613265 + ], + "graph_ms_per_iter_runs": [ + 0.6404162000035285, + 0.6404631666737259, + 0.6363502833240394 + ], + "speedup_x": 0.9998949172771935, + "fallback": true + } + ] +} \ No newline at end of file diff --git a/benchmarks/results/2026-06-16/readme-public-installed-graph-enabled-main-python-baseline-rust-hip-cpp-20260616.json b/benchmarks/results/2026-06-16/readme-public-installed-graph-enabled-main-python-baseline-rust-hip-cpp-20260616.json new file mode 100644 index 0000000..4908eb4 --- /dev/null +++ b/benchmarks/results/2026-06-16/readme-public-installed-graph-enabled-main-python-baseline-rust-hip-cpp-20260616.json @@ -0,0 +1,82 @@ +{ + "timestamp_utc": "2026-06-16T14:34:07Z", + "commit_sha": "fe14ca8017e25f29248aa9bcefdb811cbc0c1e5e", + "run_count": 3, + "env": { + "torch": "2.13.0a0+git53bbebe", + "device": "AMD Radeon RX 6700 XT", + "rocm": { + "runtime_from_torch": "7.2.26015", + "driver_from_hipconfig": "7.2.26015-fc0010cf6a", + "runtime_from_rocminfo": "Runtime Version: 1.18" + }, + "env": { + "HSA_OVERRIDE_GFX_VERSION": "10.3.0", + "PYTORCH_ROCM_ARCH": null, + "GFXGRAPH": "1", + "GFXGRAPH_VRAM_CAP": null, + "SGLANG_RDNA2_KERNELS": null, + "HIP_VISIBLE_DEVICES": null, + "CUDA_VISIBLE_DEVICES": null + } + }, + "results": [ + { + "workload": "decode_like_layernorm_gelu_chain_bs1_d1024", + "iters": 2000, + "run_count": 3, + "eager_ms_per_iter": 0.16572348100089584, + "graph_ms_per_iter": 0.21004998950047593, + "eager_ms_per_iter_runs": [ + 0.16572348100089584, + 0.1741914234989963, + 0.1650394204989425 + ], + "graph_ms_per_iter_runs": [ + 0.21257842700106266, + 0.21004998950047593, + 0.19883593099984864 + ], + "speedup_x": 0.788971622398107, + "fallback": true + }, + { + "workload": "mlp_bs32_d1024", + "iters": 1500, + "run_count": 3, + "eager_ms_per_iter": 0.1065557226659924, + "graph_ms_per_iter": 0.10684876866677466, + "eager_ms_per_iter_runs": [ + 0.10651393800071673, + 0.10730442200050068, + 0.1065557226659924 + ], + "graph_ms_per_iter_runs": [ + 0.10686785466774988, + 0.10647171933427065, + 0.10684876866677466 + ], + "speedup_x": 0.9972573759675587, + "fallback": true + }, + { + "workload": "mlp_bs128_d2048", + "iters": 300, + "run_count": 3, + "eager_ms_per_iter": 0.634038509997481, + "graph_ms_per_iter": 0.6388252400089792, + "eager_ms_per_iter_runs": [ + 0.634038509997481, + 0.6393794599959316, + 0.6335876566663501 + ], + "graph_ms_per_iter_runs": [ + 0.6385631166631356, + 0.6388252400089792, + 0.6396404866609373 + ], + "speedup_x": 0.992506980451444, + "fallback": true + } + ] +} \ No newline at end of file diff --git a/benchmarks/schemas/gfxgraph-benchmark-v1.schema.json b/benchmarks/schemas/gfxgraph-benchmark-v1.schema.json new file mode 100644 index 0000000..7daf483 --- /dev/null +++ b/benchmarks/schemas/gfxgraph-benchmark-v1.schema.json @@ -0,0 +1,296 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/carlosfundora/gfxGRAPH/benchmarks/schemas/gfxgraph-benchmark-v1.schema.json", + "title": "gfxGRAPH benchmark report v1", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "report_kind", + "run_id", + "phase", + "timestamp_utc", + "report_date", + "schema_path", + "repo", + "environment", + "python", + "package_state", + "gate_checks", + "benchmarks" + ], + "properties": { + "schema_version": { + "const": "gfxgraph-benchmark-v1" + }, + "report_kind": { + "const": "benchmark_gate_phase_report" + }, + "run_id": { + "type": "string", + "minLength": 1 + }, + "phase": { + "enum": [ + "installed-baseline", + "installed-graph-enabled", + "clean-candidate", + "graph-candidate" + ] + }, + "timestamp_utc": { + "type": "string", + "minLength": 1 + }, + "report_date": { + "type": "string", + "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" + }, + "schema_path": { + "type": "string", + "minLength": 1 + }, + "repo": { + "type": "object", + "additionalProperties": false, + "required": [ + "root", + "branch", + "commit", + "tracked_dirty" + ], + "properties": { + "root": { + "type": "string" + }, + "branch": { + "type": "string" + }, + "commit": { + "type": "string" + }, + "tracked_dirty": { + "type": "boolean" + } + } + }, + "environment": { + "type": "object", + "additionalProperties": true, + "required": [ + "os", + "rocm_path", + "hipcc_version", + "env" + ], + "properties": { + "os": { + "type": "string" + }, + "rocm_path": { + "type": [ + "string", + "null" + ] + }, + "hipcc_version": { + "type": [ + "string", + "null" + ] + }, + "env": { + "type": "object", + "additionalProperties": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "python": { + "type": [ + "object", + "null" + ] + }, + "package_state": { + "type": "object", + "additionalProperties": false, + "required": [ + "target_import_policy", + "graph_enabled", + "allow_package_changes", + "package_actions" + ], + "properties": { + "target_import_policy": { + "enum": [ + "site-packages", + "repo", + "not-enforced", + "native-only" + ] + }, + "graph_enabled": { + "type": "boolean" + }, + "allow_package_changes": { + "type": "boolean" + }, + "package_actions": { + "type": "array", + "items": { + "$ref": "#/$defs/command_record" + } + } + } + }, + "gate_checks": { + "type": "array", + "items": { + "$ref": "#/$defs/gate_check" + } + }, + "benchmarks": { + "type": "array", + "items": { + "$ref": "#/$defs/benchmark_record" + } + } + }, + "$defs": { + "status": { + "enum": [ + "passed", + "failed", + "skipped" + ] + }, + "command_record": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "command", + "status", + "duration_ms", + "exit_code", + "stdout_tail", + "stderr_tail" + ], + "properties": { + "name": { + "type": "string" + }, + "command": { + "type": "string" + }, + "status": { + "$ref": "#/$defs/status" + }, + "duration_ms": { + "type": "number", + "minimum": 0 + }, + "exit_code": { + "type": [ + "integer", + "null" + ] + }, + "stdout_tail": { + "type": "string" + }, + "stderr_tail": { + "type": "string" + } + } + }, + "gate_check": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "status", + "message", + "details" + ], + "properties": { + "name": { + "type": "string" + }, + "status": { + "$ref": "#/$defs/status" + }, + "message": { + "type": "string" + }, + "details": {} + } + }, + "benchmark_record": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "kind", + "status", + "command", + "iterations", + "duration_ms", + "throughput_ops_per_sec", + "stdout_tail", + "stderr_tail", + "metrics" + ], + "properties": { + "name": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "status": { + "$ref": "#/$defs/status" + }, + "command": { + "type": "string" + }, + "iterations": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "duration_ms": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "throughput_ops_per_sec": { + "type": [ + "number", + "null" + ], + "minimum": 0 + }, + "stdout_tail": { + "type": "string" + }, + "stderr_tail": { + "type": "string" + }, + "metrics": { + "type": "object", + "additionalProperties": true + } + } + } + } +} diff --git a/ci.sh b/ci.sh index b350c5e..088b96a 100755 --- a/ci.sh +++ b/ci.sh @@ -1,31 +1,41 @@ #!/usr/bin/env bash -# Publisher: Carlos Fundora · GitHub: @carlosfundora · Hugging Face: @carlosfundora · MIT -# Local CI for gfxGRAPH — GitHub Actions is billing-locked, so THIS is the release/merge gate. -# Runs on the local box (which has gfx1030 + ROCm, unlike the dead ubuntu-latest workflows). -# ./ci.sh # full gate: tests + build + version-sync -# uv-only; no network publish here (publish is a separate manual `uv publish --token`). +# Publisher: Carlos Fundora · GitHub: @carlosfundora · MIT +# Local CI runner for gfxGRAPH (rust-hip-cpp branch) set -euo pipefail + cd "$(dirname "$0")" -: "${VIRTUAL_ENV:=/home/local/ai/.venv}" -export VIRTUAL_ENV UV_LINK_MODE=copy -echo "[ci] gfxGRAPH local CI (venv=$VIRTUAL_ENV)" +PROJECT_DIR="$PWD" + +# Detect and export branch-local virtual environment +VENV_DIR="$PROJECT_DIR/.venv" +if [ -d "$VENV_DIR" ]; then + export VIRTUAL_ENV="$VENV_DIR" + echo "[ci] Using branch-local virtual environment: $VENV_DIR" +else + echo "[ci] Warning: local .venv not found. Running with system environment" +fi -# 1) version-sync guard — pyproject [project].version must equal gfxgraph.__version__. -# Catches the 1.0.0 regression where the wheel shipped __version__="0.4.0". -python - <<'PY' -import tomllib, re, pathlib -pj = tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"] -init = pathlib.Path("python/gfxgraph/__init__.py").read_text() -got = re.search(r'__version__\s*=\s*"([^"]+)"', init).group(1) -assert got == pj, f"version drift: __version__={got!r} != pyproject={pj!r}" -print(f"[ci] version-sync ok: {pj}") -PY +# Ensure all step scripts are executable +chmod +x ci/*.sh -# 2) test suite (ephemeral pytest overlay over the active venv). -uv run --no-project --with pytest python -m pytest tests/ -q +STAGES=( + "ci/version_sync.sh" + "ci/build_rust.sh" + "ci/build_cpp.sh" + "ci/test_cpp.sh" + "ci/test_python.sh" + "ci/build_package.sh" +) -# 3) build sdist+wheel — catches packaging errors before a manual publish. -uv build >/dev/null -echo "[ci] build ok: $(ls -t dist/*.whl | head -1)" +echo "=== Starting gfxGRAPH Local CI Pipeline ===" +for stage in "${STAGES[@]}"; do + echo "--------------------------------------------------" + echo "Running stage: $stage" + if ! ./"$stage"; then + echo "⛔ Stage failed: $stage" >&2 + exit 1 + fi +done -echo "[ci] PASS" +echo "--------------------------------------------------" +echo "✓ ALL CI STAGES PASSED SUCCESSFULLY" diff --git a/ci/build_cpp.sh b/ci/build_cpp.sh new file mode 100755 index 0000000..47c9160 --- /dev/null +++ b/ci/build_cpp.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# Publisher: Carlos Fundora · GitHub: @carlosfundora · MIT +# CI step: Build native C++ compat bridge target using CMake +set -euo pipefail +cd "$(dirname "$0")/.." + +echo "[ci] Configuring and building C++ native bridge..." +cmake -S . -B build --preset release -DBUILD_CUDA_COMPAT=ON +cmake --build build -j$(nproc) diff --git a/ci/build_package.sh b/ci/build_package.sh new file mode 100755 index 0000000..90a03f3 --- /dev/null +++ b/ci/build_package.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Publisher: Carlos Fundora · GitHub: @carlosfundora · MIT +# CI step: Validate sdist and wheel compilation using uv build +set -euo pipefail +cd "$(dirname "$0")/.." + +echo "[ci] Validating package builds..." +if command -v uv >/dev/null 2>&1; then + uv build >/dev/null + echo "[ci] Build ok: $(ls -t dist/*.whl | head -1)" +else + echo "[ci] Skip: uv not installed on PATH" +fi diff --git a/ci/build_rust.sh b/ci/build_rust.sh new file mode 100755 index 0000000..28a9511 --- /dev/null +++ b/ci/build_rust.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# Publisher: Carlos Fundora · GitHub: @carlosfundora · MIT +# CI step: Compile and register PyO3 Rust bindings via Maturin +set -euo pipefail +cd "$(dirname "$0")/.." + +# Detect Maturin path +if [ -x "/home/local/.local/bin/maturin" ]; then + MATURIN_BIN="/home/local/.local/bin/maturin" +else + MATURIN_BIN="maturin" +fi + +# Detect VENV +VENV_DIR="${VIRTUAL_ENV:-$PWD/.venv}" + +echo "[ci] Rebuilding Rust bindings via system maturin..." +cd rust/rs_gfxgraph +VIRTUAL_ENV="$VENV_DIR" "$MATURIN_BIN" develop --release diff --git a/ci/test_cpp.sh b/ci/test_cpp.sh new file mode 100755 index 0000000..68ea32e --- /dev/null +++ b/ci/test_cpp.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Publisher: Carlos Fundora · GitHub: @carlosfundora · MIT +# CI step: Run the CTest native test suite +set -euo pipefail +cd "$(dirname "$0")/.." + +echo "[ci] Running CTest native test suite..." +ctest --test-dir build --output-on-failure diff --git a/ci/test_python.sh b/ci/test_python.sh new file mode 100755 index 0000000..201c397 --- /dev/null +++ b/ci/test_python.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# Publisher: Carlos Fundora · GitHub: @carlosfundora · MIT +# CI step: Run the python test suite +set -euo pipefail +cd "$(dirname "$0")/.." + +# Detect python binary +PYTHON_BIN="${VIRTUAL_ENV:-.venv}/bin/python" +if [ ! -x "$PYTHON_BIN" ]; then + PYTHON_BIN="python3" +fi + +echo "[ci] Running pytest integration tests..." +"$PYTHON_BIN" -m pytest tests/ diff --git a/ci/version_sync.sh b/ci/version_sync.sh new file mode 100755 index 0000000..547e1a0 --- /dev/null +++ b/ci/version_sync.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Publisher: Carlos Fundora · GitHub: @carlosfundora · MIT +# CI step: Verify version synchronization between __init__.py and pyproject.toml +set -euo pipefail +cd "$(dirname "$0")/.." + +# Detect python binary +PYTHON_BIN="${VIRTUAL_ENV:-.venv}/bin/python" +if [ ! -x "$PYTHON_BIN" ]; then + PYTHON_BIN="python3" +fi + +echo "[ci] Checking version synchronization..." +"$PYTHON_BIN" - <<'PY' +import tomllib, re, pathlib +pj = tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"] +init = pathlib.Path("python/gfxgraph/__init__.py").read_text() +got = re.search(r'__version__\s*=\s*"([^"]+)"', init).group(1) +assert got == pj, f"version drift: __version__={got!r} != pyproject={pj!r}" +print(f"[ci] Version-sync check passed: {pj}") +PY diff --git a/docs/benchmarking-guide.md b/docs/benchmarking-guide.md new file mode 100644 index 0000000..069c794 --- /dev/null +++ b/docs/benchmarking-guide.md @@ -0,0 +1,107 @@ +# gfxGRAPH Benchmarking Guide + +This guide details the benchmarking suite, script configurations, output formats, and how to verify execution performance on AMD ROCm (specifically RDNA2 hardware). + +--- + +## 1. Native-Only Gate + +The `rust-hip-cpp` branch must prove the native runtime path without importing the +Python package. Use this gate before changing runtime behavior: + +```bash +cargo build -p rs_gfxgraph_native --bin gfxgraph-native-probe +cargo run -p rs_gfxgraph_bench -- \ + --repo-root . \ + --phase clean-candidate \ + --native-only \ + --run-id native-only-runtime-YYYYMMDD +``` + +This writes a schema-validated report under `benchmarks/results/YYYY-MM-DD/` with +`python: null`, `target_import_policy: native-only`, and a +`rust-native-runtime-cli` benchmark produced by `gfxgraph-native-probe`. The probe +loads `libhipgraph_bridge.so` directly, exercises lifecycle and profiler FFI, and +reports `python_used: false`. + +Python package install/uninstall is only for compatibility baselines against the +published package. It is not the development target for this branch. + +--- + +## 2. Micro-Benchmarks + +Micro-benchmarks isolate specific components to compare the performance between the pure Python fallback logic and the PyO3 Rust extension modules. + +### Shape Bucketing Router: `bench_routing.py` vs `bench_routing_rust.py` +- **File Location**: [benchmarks/bench_routing.py](file:///home/local/ai/projects/gfxGRAPH/benchmarks/bench_routing.py) and [benchmarks/bench_routing_rust.py](file:///home/local/ai/projects/gfxGRAPH/benchmarks/bench_routing_rust.py) +- **Goal**: Measure the overhead of selecting shape buckets over 1,000,000 routing iterations. +- **Pure Python Baseline**: Maps input size using Python's `bisect_left` and set lookup operations. +- **Rust Implementation**: Uses PyO3 bindings mapped to `std::collections::HashSet` and binary search arrays. +- **How to Run**: + ```bash + python benchmarks/bench_routing.py + python benchmarks/bench_routing_rust.py + ``` + +### Conditional Execution Mock: `bench_conditional_mock.py` +- **File Location**: [benchmarks/bench_conditional_mock.py](file:///home/local/ai/projects/gfxGRAPH/benchmarks/bench_conditional_mock.py) +- **Goal**: Measures the throughput (ops/sec) of alternating branch execution with a mocked GPU. +- **Mocks Used**: Mocks `torch` and overrides `torch_cuda_execution_probe` to simulate a contiguous CUDA environment on CPU, allowing the benchmark to execute fallbacks without hardware dependencies. +- **How to Run**: + ```bash + python benchmarks/bench_conditional_mock.py + ``` + +--- + +## 3. Public GPU Benchmarks + +The public benchmark suite is intended to run on a real GPU to verify overall latency and throughput improvements. + +### Public Workload Benchmark: `bench_readme_public.py` +- **File Location**: [benchmarks/bench_readme_public.py](file:///home/local/ai/projects/gfxGRAPH/benchmarks/bench_readme_public.py) +- **Goal**: Measures execution duration (ms/iter) for core model layers (e.g. LayerNorm/GELU chains and MLPs) comparing direct Eager mode vs. Graph execution. +- **How to Run**: + ```bash + PYTHONPATH=python python benchmarks/bench_readme_public.py \ + --run-count 3 \ + --output benchmarks/results/readme_benchmark_latest.json + ``` +- **Optional Hot Replay Mode**: Enable via environment variable `GFXGRAPH_REPLAY_HOT_MODE=1` to use the optimized low-overhead native launcher path. + +--- + +## 4. Output JSON Schema & Provenance + +When running the public benchmark, results are saved to a JSON file containing provenance tracking metadata: + +```json +{ + "provenance": { + "commit_sha": "abc123def...", + "rocm_version": "7.2.0", + "gpu_target": "gfx1030", + "timestamp": "2026-06-16T08:00:00Z" + }, + "results": [ + { + "workload": "mlp_bs32_d1024", + "eager_ms_per_iter": 0.1023, + "graph_ms_per_iter": 0.1028, + "speedup": 1.00 + } + ] +} +``` + +--- + +## 5. Targets and Performance Gates + +| Benchmark Component | Baseline Reference | Target Performance | +|---------------------|--------------------|--------------------| +| Conditional 2-branch| Native HIP (no cond) | $\ge$ 85% throughput | +| Pipeline launch | `hipGraphLaunch` (cold) | $\le$ 50 $\mu$s latency | +| Shape bucketing | Static graph replay | $\ge$ 90% throughput | +| Composition | Monolithic graph | $\ge$ 90% throughput | diff --git a/docs/hipgraph-bridge-design.md b/docs/hipgraph-bridge-design.md index 60396d1..aa83e77 100644 --- a/docs/hipgraph-bridge-design.md +++ b/docs/hipgraph-bridge-design.md @@ -850,7 +850,7 @@ Phase 1 + 2 alone cover the two **High severity** gaps and deliver | HIPIFY mappings | `ai/build/tools/HIPIFY/src/` | CUDA→HIP symbol table | | aiter JIT | `ai/build/resources/aiter/aiter/jit/` | .so build pattern | | AOTriton | `ai/build/resources/aotriton/` | Drop-in .so pattern | -| Triton cache | `ai/build/resources/kernel-cache/triton-gfx1031/` | HSACO examples | +| Triton cache | `ai/GFX-KERNELS-HIP-PY-RS/py/frozen-jit-kernel-cache/triton-gfx1030/` | HSACO examples (gfx1030; relocated 2026-06-18) | | kernel-learning | `ai/build/resources/kernel-learning/09-pytorch-custom-ops/` | Op registration | | TheRock CMake | `ai/build/resources/TheRock/cmake/` | Build infrastructure | | hipGraph report | `ai/build/resources/hipgraph-analysis-report.md` | Performance data | diff --git a/docs/torch-hip-rocm-graph.md b/docs/torch-hip-rocm-graph.md index ba5f315..eb927ff 100644 --- a/docs/torch-hip-rocm-graph.md +++ b/docs/torch-hip-rocm-graph.md @@ -521,7 +521,7 @@ to close specific parity gaps on gfx1030. | **aiter** | `ai/build/resources/aiter` | AMD attention + JIT hipify | | **Triton** | `ai/build/resources/triton` | Kernel authoring (ROCm) | | **kernel-learning** | `ai/build/resources/kernel-learning` | 12-chapter GPU curriculum | -| **kernel-cache** | `ai/build/resources/kernel-cache/` | gfx1031 Triton + aiter kernels | +| **kernel-cache** | `ai/GFX-KERNELS-HIP-PY-RS/py/frozen-jit-kernel-cache/` | gfx1030 Triton + AITER frozen JIT cache (relocated 2026-06-18) | | **AOTriton** | `ai/build/resources/aotriton` | Flash/SDPA attention | | **TheRock** | `ai/build/resources/TheRock` | ROCm build system (gfx1030 ✅) | @@ -533,10 +533,11 @@ to close specific parity gaps on gfx1030. 3. **Verify on gfx1030**: `hipcc --offload-arch=gfx1030 hip_kernel.hip` 4. **Optimize with Triton** (optional): Rewrite for portability and auto-tuning via `ai/build/resources/triton` -5. **Cache**: Store compiled kernels in `kernel-cache/` for reuse +5. **Cache**: Store compiled kernels in `GFX-KERNELS-HIP-PY-RS/py/frozen-jit-kernel-cache/` for reuse -For Triton kernels targeting RDNA2, reference the 298 cached -compilations in `kernel-cache/triton-gfx1031/` as starting patterns. +For Triton kernels targeting RDNA2, reference the 296 cached compilations (258 kernel +variants + 38 runtime) in `GFX-KERNELS-HIP-PY-RS/py/frozen-jit-kernel-cache/triton-gfx1030/` +as starting patterns. diff --git a/include/hipgraph_bridge.h b/include/hipgraph_bridge.h index af4cff6..e55bd23 100644 --- a/include/hipgraph_bridge.h +++ b/include/hipgraph_bridge.h @@ -12,6 +12,8 @@ #pragma once #include #include +#include +#include #ifdef __cplusplus extern "C" { @@ -143,6 +145,70 @@ HGB_EXPORT hipError_t hgb_pipeline_update_kernel( HGB_EXPORT void hgb_pipeline_destroy(hgb_pipeline_t* pipe); +HGB_EXPORT hipError_t hgb_pipeline_update_and_launch( + hgb_pipeline_t* pipe, + hipGraphNode_t node, + hipKernelNodeParams* params +); + +/* ── Native Telemetry ───────────────────────────────── */ + +#define HGB_PROFILER_CAPACITY 4096 + +typedef enum { + HGB_PROFILE_EVENT_UNKNOWN = 0, + HGB_PROFILE_EVENT_PIPELINE_CREATE = 1, + HGB_PROFILE_EVENT_PIPELINE_UPLOAD = 2, + HGB_PROFILE_EVENT_PIPELINE_LAUNCH = 3, + HGB_PROFILE_EVENT_PIPELINE_UPDATE = 4, + HGB_PROFILE_EVENT_COMPOSE_LAUNCH = 5, + HGB_PROFILE_EVENT_SHAPE_LAUNCH = 6, + HGB_PROFILE_EVENT_DEVICE_CLOCK_PROBE = 7, +} hgb_profile_event_kind_t; + +typedef struct { + uint64_t seq; + uint64_t timestamp_ns; + uint64_t duration_ns; + uint64_t value0; + uint64_t value1; + uint32_t event; + uint32_t device_id; + uint32_t stream_id; + uint32_t flags; +} hgb_profile_sample_t; + +typedef struct { + uint64_t written; + uint64_t dropped; + uint64_t capacity; +} hgb_profile_counters_t; + +/** Monotonic host timestamp in nanoseconds, suitable for native reports. */ +HGB_EXPORT uint64_t hgb_monotonic_ns(void); + +/** Reset the native cyclic profiler buffer. Safe while no producer is active. */ +HGB_EXPORT void hgb_profiler_reset(void); + +/** Record one native event into the lock-free cyclic profiler buffer. */ +HGB_EXPORT uint64_t hgb_profiler_record( + uint32_t event, + uint64_t duration_ns, + uint64_t value0, + uint64_t value1 +); + +/** + * Copy the newest profiler samples into caller memory. + * + * Returns the number of samples copied. Samples are ordered oldest to newest. + */ +HGB_EXPORT size_t hgb_profiler_snapshot( + hgb_profile_sample_t* out, + size_t max_samples, + hgb_profile_counters_t* counters +); + /* ── Gap 53: Dynamic Shape Management ───────────────── */ typedef hipError_t (*hgb_capture_fn)(int size, hipGraph_t* out, void* ctx); @@ -196,6 +262,79 @@ HGB_EXPORT hipError_t hgb_shape_pool_update_params( HGB_EXPORT void hgb_shape_pool_destroy(hgb_shape_pool_t* pool); +/* ── Capture-safe paged decode ────────────────────────── + * + * Fixes decode-attention-under-hipGraph replay-data-unsafety: a captured decode graph that bakes the + * per-step sequence length / block table BY VALUE garbles when replayed as the sequence grows (each + * replay attends the capture-time length). This pool owns PERSISTENT device metadata buffers at fixed + * addresses; the captured graph reads them, and replay = memcpy(live -> persistent) + hipGraphLaunch. + * No hipGraphExec*SetParams — the kernel-node pointer args never change, only the buffer CONTENTS, so + * the captured node reads fresh data. One graph per bucket (bucket-constant max) replays correctly for + * every decode step. (Wires the previously-vestigial hgb_shape_pool_t::static_bufs slot, the right way.) + */ + +/** + * Capture callback for decode. Build a graph for `bucket_max` whose decode kernel reads the supplied + * PERSISTENT device metadata buffers — d_seq_lens[max_num_seqs] and + * d_block_tables[max_num_seqs * max_blocks_per_seq]. The SAME buffers are passed for every bucket, so a + * single in-place refresh before launch updates whichever bucket's graph runs. Sizing args (head/page + * geometry, kernel pointers) ride in `ctx`. + */ +typedef hipError_t (*hgb_decode_capture_fn)( + int bucket_max, + const int* d_seq_lens, + const int* d_block_tables, + hipGraph_t* out, + void* ctx +); + +typedef struct { + int* bucket_sizes; + int num_buckets; + hipGraphExec_t* execs; + hipGraph_t* graphs; + hipEvent_t* events; /**< Per-bucket event for in-flight tracking */ + int* d_seq_lens; /**< persistent device int[max_num_seqs] */ + int* d_block_tables; /**< persistent device int[max_num_seqs*max_blocks_per_seq] */ + int max_num_seqs; + int max_blocks_per_seq; + int device_id; + pthread_mutex_t lock; +} hgb_decode_pool_t; + +/** + * Create a capture-safe decode pool: allocate the persistent metadata buffers, then capture one graph + * per bucket via `fn` (each reading those buffers) and instantiate it. `buckets` = ascending per-bucket + * max sequence lengths. + */ +HGB_EXPORT hipError_t hgb_decode_pool_create( + hgb_decode_capture_fn fn, + void* ctx, + const int* buckets, + int num_buckets, + int max_num_seqs, + int max_blocks_per_seq, + hgb_decode_pool_t* out +); + +/** + * Refresh the persistent metadata in place from host arrays, then launch the smallest bucket >= + * input_size. `h_seq_lens` is int[num_seqs]; `h_block_tables` is int[num_seqs*max_blocks_per_seq] + * (may be NULL to skip the block-table copy). The memcpy is enqueued on `stream` before the launch, so + * the replay sees the fresh metadata. Returns the actual bucket used in `actual_bucket`. + */ +HGB_EXPORT hipError_t hgb_decode_pool_replay( + hgb_decode_pool_t* pool, + int input_size, + const int* h_seq_lens, + int num_seqs, + const int* h_block_tables, + hipStream_t stream, + int* actual_bucket +); + +HGB_EXPORT void hgb_decode_pool_destroy(hgb_decode_pool_t* pool); + /* ── Gap 54: Capture Compositor ─────────────────────── */ typedef struct { @@ -238,6 +377,82 @@ HGB_EXPORT hipError_t hgb_compose_launch( HGB_EXPORT void hgb_compose_destroy(hgb_composed_graph_t* comp); +/* ── Opaque Native Runtime Handles ──────────────────── */ + +typedef struct hgb_pipeline_handle hgb_pipeline_handle_t; +typedef struct hgb_composed_graph_handle hgb_composed_graph_handle_t; +typedef struct hgb_decode_pool_handle hgb_decode_pool_handle_t; + +/** + * Create an opaque double-buffered pipeline handle for FFI callers. + * + * This keeps pthread/HIP struct layout out of the Rust ABI while preserving + * the native launch path. + */ +HGB_EXPORT hipError_t hgb_pipeline_handle_create( + hipGraph_t graph, + hgb_pipeline_handle_t** out +); + +HGB_EXPORT hipError_t hgb_pipeline_handle_launch(hgb_pipeline_handle_t* handle); + +HGB_EXPORT hipError_t hgb_pipeline_handle_update_kernel( + hgb_pipeline_handle_t* handle, + hipGraphNode_t node, + hipKernelNodeParams* params +); + +HGB_EXPORT hipError_t hgb_pipeline_handle_update_and_launch( + hgb_pipeline_handle_t* handle, + hipGraphNode_t node, + hipKernelNodeParams* params +); + +HGB_EXPORT void hgb_pipeline_handle_destroy(hgb_pipeline_handle_t* handle); + +HGB_EXPORT hipError_t hgb_composed_handle_create( + hipGraph_t* sub_graphs, + int count, + const int* deps, + hgb_composed_graph_handle_t** out +); + +HGB_EXPORT hipError_t hgb_composed_handle_launch( + hgb_composed_graph_handle_t* handle, + hipStream_t stream +); + +HGB_EXPORT hipError_t hgb_composed_handle_update_child( + hgb_composed_graph_handle_t* handle, + int child_index, + hipGraph_t new_sub_graph +); + +HGB_EXPORT void hgb_composed_handle_destroy(hgb_composed_graph_handle_t* handle); + +/* Capture-safe decode pool (opaque handle over hgb_decode_pool_*). */ +HGB_EXPORT hipError_t hgb_decode_pool_handle_create( + hgb_decode_capture_fn fn, + void* ctx, + const int* buckets, + int num_buckets, + int max_num_seqs, + int max_blocks_per_seq, + hgb_decode_pool_handle_t** out +); + +HGB_EXPORT hipError_t hgb_decode_pool_handle_replay( + hgb_decode_pool_handle_t* handle, + int input_size, + const int* h_seq_lens, + int num_seqs, + const int* h_block_tables, + hipStream_t stream, + int* actual_bucket +); + +HGB_EXPORT void hgb_decode_pool_handle_destroy(hgb_decode_pool_handle_t* handle); + /* ── Utilities ──────────────────────────────────────── */ /** Check if running on gfx1030. Returns hipSuccess or hipErrorInvalidDevice. */ diff --git a/kernels/README.md b/kernels/README.md index 596c934..b7a5c13 100644 --- a/kernels/README.md +++ b/kernels/README.md @@ -1,11 +1,8 @@ # Kernel Reference Archive -Copies of custom/modified GPU kernels from ENCOM/THOTH build work. +Copies of all custom/modified GPU kernels from ENCOM/THOTH build work. These serve as reusable references for future HIP/ROCm/CUDA porting. -> [!NOTE] -> This directory is for reference material only and is not packaged or shipped in the `gfxGRAPH` PyPI wheel. - ## Contents ### [`deepspeed-hip/`](deepspeed-hip/) — DeepSpeed CUDA→HIP Ports @@ -13,9 +10,42 @@ Three core inference kernels (layer_norm, linear, rms_norm) ported from CUDA to for ROCm/RDNA2 compatibility. Includes tiled GEMM with parallel dequantization. - **19 files** | `.hip`, `.cpp`, `.cuh`, `.h` -### [`rdna2/`](rdna2/) — Triton RDNA2 Optimizations -Triton kernels explicitly optimized for the AMD Radeon RX 6700 XT (gfx1030) architecture. Features optimized block sizes, manual unrolling, and avoidance of `bfloat16` instructions not supported on RDNA2. +### [`sglang-prism-q1/`](sglang-prism-q1/) — PRISM Q1_0 GPU Kernels +1-bit quantization (Q1_0) CUDA kernels for sglang's GGUF inference path. +Symmetric binary quantization: each bit → `+d` or `-d`. Two block sizes (32, 128). +Uses `dp4a` INT8 dot product for fast accumulation. +- **6 source files + 1 patch** | `.cu`, `.cuh`, `.h` +- Source: `sglang-1-bit-turbo` fork (uncommitted on `main`) + +### [`llama-cpp-tq3-kvcache/`](llama-cpp-tq3-kvcache/) — TQ3_0 KV Cache Quantization +TurboQuant 3-bit (3.5 bpw) KV cache compression kernels for llama.cpp. +Per-block Walsh-Hadamard Transform rotation with 4-centroid MSE codebook. +CUDA and CPU implementations. +- **12 source files + 1 patch** | `.cu`, `.cuh`, `.c`, `.h` +- Source: `llama.cpp-1-bit-turbo` fork, commit `a432f38e5` + +### [`vllm-rdna2/`](vllm-rdna2/) — RDNA2 Advanced Indexing Fallback +CPU fallback for HIP runtime crash on RDNA2 during speculative decode +tensor indexing. Catches HIP `AcceleratorError` and falls back to +CPU-side `index_select`. +- **1 source file + 1 patch** | `.py` +- Source: `vllm` fork, branch `rdna2-index-fallback` + +## Not included + +- **SpecForge** — No custom CUDA/HIP kernels (pure Python/ML framework) +- **llama.cpp `review/rocm-hardening`** — Only test harness files, no kernel changes +- **WIP llama.cpp builds** — Compiled `.so` artifacts only, no unique kernel sources ## How to use -These kernels are provided as-is for reference and manual inclusion into inference pipelines. They do not automatically load into PyTorch via `gfxGRAPH`. +Each directory contains full source files plus a `.patch` file showing just our +modifications vs upstream. The patches are the fastest way to see what changed: + +```bash +# View what we added to sglang for PRISM Q1_0: +cat sglang-prism-q1/PRISM_Q1_0.patch + +# Apply TQ3_0 changes to a fresh llama.cpp checkout: +cd /path/to/llama.cpp && git apply /mnt/ai/build/kernels/llama-cpp-tq3-kvcache/TQ3_0_KV_CACHE.patch +``` diff --git a/kernels/deepspeed-hip/CHANGELOG.md b/kernels/deepspeed-hip/CHANGELOG.md index 2f782c8..928e665 100644 --- a/kernels/deepspeed-hip/CHANGELOG.md +++ b/kernels/deepspeed-hip/CHANGELOG.md @@ -9,3 +9,7 @@ All notable changes to the DeepSpeed HIP ported kernels will be documented in th - `hip_layer_norm/`: Fused layer normalization kernel targeting ROCm/RDNA2. - `hip_linear/`: Tiled GEMM implementation with parallel dequantization for INT4/INT8 workloads. - `hip_rms_norm/`: Root-mean-square normalization kernel optimized for LLaMA-family models. + +### Changed +- Hardened layer norm and RMSNorm launch scheduling on RDNA2 so the subblock path is only used for supported 1/2/4/8/16-thread groups; larger small-row float cases now route to the full-block schedule instead of silently skipping launch. +- Kept RMSNorm reciprocal-square-root scaling in float until the final cast to reduce half/bfloat16 precision loss. diff --git a/kernels/deepspeed-hip/hip_layer_norm/layer_norm_hip.hip b/kernels/deepspeed-hip/hip_layer_norm/layer_norm_hip.hip index 2712099..2a6a76a 100644 --- a/kernels/deepspeed-hip/hip_layer_norm/layer_norm_hip.hip +++ b/kernels/deepspeed-hip/hip_layer_norm/layer_norm_hip.hip @@ -140,11 +140,13 @@ void launch_fused_ln(T* output, // For Flaoat, unRoll 4, for __half, unRoll 2 constexpr int internal_unRoll = sizeof(T) == 4 ? 4 : 2; - const bool is_subblock_schedule = (elems_per_row <= 128) ? true : false; - const int h_per_step = is_subblock_schedule ? T_per_load : T_per_load * internal_unRoll; - // Scheduling concern: may be slightly faster for some inputs to assign multiple stages of // warp-sized blocks rather than stepping up to 64/96 threads + const int subblock_one_step_threads = + next_pow2((elems_per_row + T_per_load - 1) / T_per_load); + const bool is_subblock_schedule = + elems_per_row <= 128 && subblock_one_step_threads <= 16; + const int h_per_step = is_subblock_schedule ? T_per_load : T_per_load * internal_unRoll; const int one_step_threads = next_pow2((elems_per_row + h_per_step - 1) / h_per_step); const int threadsPerGroup = (one_step_threads < maxThreads) ? one_step_threads : maxThreads; @@ -349,11 +351,13 @@ void launch_fused_post_ln(T* output, // For Flaoat, unRoll 4, for __half, unRoll 2 constexpr int internal_unRoll = sizeof(T) == 4 ? 4 : 2; - const bool is_subblock_schedule = (elems_per_row <= 128) ? true : false; - const int h_per_step = is_subblock_schedule ? T_per_load : T_per_load * internal_unRoll; - // Scheduling concern: may be slightly faster for some inputs to assign multiple stages of // warp-sized blocks rather than stepping up to 64/96 threads + const int subblock_one_step_threads = + next_pow2((elems_per_row + T_per_load - 1) / T_per_load); + const bool is_subblock_schedule = + elems_per_row <= 128 && subblock_one_step_threads <= 16; + const int h_per_step = is_subblock_schedule ? T_per_load : T_per_load * internal_unRoll; const int one_step_threads = next_pow2((elems_per_row + h_per_step - 1) / h_per_step); const int threadsPerGroup = (one_step_threads < maxThreads) ? one_step_threads : maxThreads; @@ -422,11 +426,13 @@ void launch_fused_pre_ln(T* norm_output, // For Flaoat, unRoll 4, for __half, unRoll 2 constexpr int internal_unRoll = sizeof(T) == 4 ? 4 : 2; - const bool is_subblock_schedule = (elems_per_row <= 128) ? true : false; - const int h_per_step = is_subblock_schedule ? T_per_load : T_per_load * internal_unRoll; - // Scheduling concern: may be slightly faster for some inputs to assign multiple stages of // warp-sized blocks rather than stepping up to 64/96 threads + const int subblock_one_step_threads = + next_pow2((elems_per_row + T_per_load - 1) / T_per_load); + const bool is_subblock_schedule = + elems_per_row <= 128 && subblock_one_step_threads <= 16; + const int h_per_step = is_subblock_schedule ? T_per_load : T_per_load * internal_unRoll; const int one_step_threads = next_pow2((elems_per_row + h_per_step - 1) / h_per_step); const int threadsPerGroup = (one_step_threads < maxThreads) ? one_step_threads : maxThreads; diff --git a/kernels/deepspeed-hip/hip_rms_norm/rms_norm_hip.hip b/kernels/deepspeed-hip/hip_rms_norm/rms_norm_hip.hip index c5c3b0c..6d5189a 100644 --- a/kernels/deepspeed-hip/hip_rms_norm/rms_norm_hip.hip +++ b/kernels/deepspeed-hip/hip_rms_norm/rms_norm_hip.hip @@ -56,7 +56,7 @@ __global__ void rms_norm(T* output, const T* vals, const T* gamma, float epsilon reduce::partitioned_block(tb, warp, var_sum); const float var = var_sum / elems_per_row; - const T denom = conversion::to(__frsqrt_rn(var + epsilon)); + const float denom = __frsqrt_rn(var + epsilon); T* block_output = output + block_offset; @@ -72,8 +72,9 @@ __global__ void rms_norm(T* output, const T* vals, const T* gamma, float epsilon #pragma unroll for (int j = 0; j < T_per_load; j++) { - iteration_buffer[j] *= denom; - iteration_buffer[j] *= gamma_local[j]; + float val = conversion::to(iteration_buffer[j]); + val = val * denom * conversion::to(gamma_local[j]); + iteration_buffer[j] = conversion::to(val); } if (do_loads) { @@ -139,7 +140,7 @@ __global__ void pre_rms_norm(T* output, reduce::partitioned_block(tb, warp, var_sum); const float var = var_sum / elems_per_row; - const T denom = conversion::to(__frsqrt_rn(var + epsilon)); + const float denom = __frsqrt_rn(var + epsilon); T* block_output = output + block_offset; @@ -155,8 +156,9 @@ __global__ void pre_rms_norm(T* output, #pragma unroll for (int j = 0; j < T_per_load; j++) { - iteration_buffer[j] *= denom; - iteration_buffer[j] *= gamma_local[j]; + float val = conversion::to(iteration_buffer[j]); + val = val * denom * conversion::to(gamma_local[j]); + iteration_buffer[j] = conversion::to(val); } if (do_loads) { @@ -196,11 +198,13 @@ void launch_rms_norm(T* norm_output, constexpr int maxThreads = 256; constexpr int internalUnroll = sizeof(T) == 4 ? 4 : 2; - const bool is_subblock_schedule = (elems_per_row <= 128) ? true : false; - const int h_per_step = is_subblock_schedule ? T_per_load : T_per_load * internalUnroll; - // Scheduling concern: may be slightly faster for some inputs to assign multiple stages of // warp-sized blocks rather than stepping up to 64/96 threads + const int subblock_one_step_threads = + next_pow2((elems_per_row + T_per_load - 1) / T_per_load); + const bool is_subblock_schedule = + elems_per_row <= 128 && subblock_one_step_threads <= 16; + const int h_per_step = is_subblock_schedule ? T_per_load : T_per_load * internalUnroll; const int one_step_threads = next_pow2((elems_per_row + h_per_step - 1) / h_per_step); const int threads_per_group = (one_step_threads < maxThreads) ? one_step_threads : maxThreads; diff --git a/pyproject.toml b/pyproject.toml index 22f0e06..68e25a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "gfxgraph" -version = "1.0.1" +version = "1.1.0" description = "Drop-in CUDA Graph → HIP Graph translation layer for AMD gfx1030/1031 (RDNA2): safe eager fallback, dynamic-shape bucketing, illegal-access GUARD, and always-on bilingual (English/中文) HIP/ROCm error & status diagnostics." readme = "README.md" requires-python = ">=3.12" diff --git a/python/gfxgraph/__init__.py b/python/gfxgraph/__init__.py index d767e6c..224414e 100644 --- a/python/gfxgraph/__init__.py +++ b/python/gfxgraph/__init__.py @@ -12,7 +12,7 @@ # GFXGRAPH=validate python my_script.py """ -__version__ = "1.0.1" +__version__ = "1.1.0" import os as _os import logging as _logging diff --git a/python/hipgraph_bridge/capture_safety.py b/python/hipgraph_bridge/capture_safety.py index 59b97d6..0348b6e 100644 --- a/python/hipgraph_bridge/capture_safety.py +++ b/python/hipgraph_bridge/capture_safety.py @@ -1,5 +1,6 @@ """Runtime guardrails for high-level PyTorch graph capture.""" +import contextlib import os import subprocess import sys @@ -7,6 +8,45 @@ import torch +try: + import rs_gfxgraph as _rs_gfxgraph +except Exception: + _rs_gfxgraph = None + +# Process-global hipGraph capture serialization lives in Rust +# (rs_gfxgraph_core::capture_gate). On gfx1030/RDNA2, HIP capture bookkeeping is +# process-global, so two in-process LLM sessions capturing at once corrupt each +# other. These thin wrappers serialize capture across sessions while leaving +# replay concurrent; when the native extension is absent (pure-Python install) +# they degrade to a no-op, matching the rest of the optional-native pattern. +_HAS_CAPTURE_GATE = _rs_gfxgraph is not None and hasattr(_rs_gfxgraph, "CaptureLock") + + +def capture_lock(): + """Return the process-global capture lock (exclusive) as a context manager.""" + if _HAS_CAPTURE_GATE: + return _rs_gfxgraph.CaptureLock() + return contextlib.nullcontext() + + +def replay_lock(): + """Return the shared replay lock as a context manager (excluded during capture).""" + if _HAS_CAPTURE_GATE: + return _rs_gfxgraph.ReplayLock() + return contextlib.nullcontext() + + +def acquire_capture_lock(): + """Acquire the capture lock for the begin/end API (spans two calls).""" + if _HAS_CAPTURE_GATE: + _rs_gfxgraph.acquire_capture_lock() + + +def release_capture_lock(): + """Release the lock taken by :func:`acquire_capture_lock`.""" + if _HAS_CAPTURE_GATE: + _rs_gfxgraph.release_capture_lock() + @lru_cache(maxsize=1) def torch_cuda_execution_probe() -> tuple[bool, str]: diff --git a/python/hipgraph_bridge/conditional.py b/python/hipgraph_bridge/conditional.py index 9fa5da8..f7a6b71 100644 --- a/python/hipgraph_bridge/conditional.py +++ b/python/hipgraph_bridge/conditional.py @@ -17,6 +17,8 @@ from typing import Callable, Dict, Optional from hipgraph_bridge.capture_safety import ( + capture_lock, + replay_lock, torch_graph_capture_block_reason, torch_cuda_execution_error, torch_cuda_execution_usable, @@ -98,18 +100,21 @@ def capture(self, example_input: torch.Tensor): if not unsafe_torch_graph_capture_enabled(): raise RuntimeError(torch_graph_capture_block_reason()) - # Warmup - torch.cuda.synchronize() - with torch.no_grad(): - _ = fn(self._shared_input) - torch.cuda.synchronize() - - # Capture - graph = torch.cuda.CUDAGraph() - pool = torch.cuda.graph_pool_handle() - self._graph_pools[name] = pool - with torch.cuda.graph(graph, pool=pool): - static_output = fn(self._shared_input) + # Serialize this branch's capture process-wide (gfx1030 + # concurrent-capture corruption). One-time per branch. + with capture_lock(): + # Warmup + torch.cuda.synchronize() + with torch.no_grad(): + _ = fn(self._shared_input) + torch.cuda.synchronize() + + # Capture + graph = torch.cuda.CUDAGraph() + pool = torch.cuda.graph_pool_handle() + self._graph_pools[name] = pool + with torch.cuda.graph(graph, pool=pool): + static_output = fn(self._shared_input) self._graphs[name] = graph self._static_outputs[name] = static_output @@ -151,7 +156,8 @@ def run(self, branch: str, input_tensor: Optional[torch.Tensor] = None) -> torch raise RuntimeError("Call capture() first") if self._rust_runner is not None: - return self._rust_runner.run(branch, input_tensor) + with replay_lock(): + return self._rust_runner.run(branch, input_tensor) if branch not in self._branches: raise KeyError( @@ -175,7 +181,8 @@ def run(self, branch: str, input_tensor: Optional[torch.Tensor] = None) -> torch t0 = time.perf_counter() try: - self._graphs[branch].replay() + with replay_lock(): + self._graphs[branch].replay() except Exception as e: _log.warning("Replay failed for branch '%s': %s — eager fallback", branch, e) if branch not in self._failed_branches: diff --git a/python/hipgraph_bridge/diagnostics.py b/python/hipgraph_bridge/diagnostics.py index cb083f8..0474fe9 100644 --- a/python/hipgraph_bridge/diagnostics.py +++ b/python/hipgraph_bridge/diagnostics.py @@ -207,12 +207,17 @@ def __str__(self) -> str: ( "aiter_on_rdna", "warning", [r"aiter.*not.*support", r"aiter.*rdna", r"flydsl\.moe_common", r"CK.*not available"], - "AITER (AMD CK/ASM kernels) is not available/optimal on this GPU.", - "AITER's ASM/CK kernels target CDNA (MI2xx/MI3xx); on RDNA they're missing or fall back.", - f"{_GFX1030} is RDNA2 — AITER attention routes to (slower) Triton, and AITER MoE/flydsl bits " - "may be absent. Not an error, just unsupported hardware.", - "Prefer the Triton path on RDNA (sglang auto-routes `aiter`→triton on gfx10xx). Don't expect " - "CK/ASM acceleration here.", + "An AITER CK/ASM-only op (e.g. flydsl/CK-MoE, CK rmsnorm) is unbuilt here — but native " + "AITER attention works on this gfx1030.", + "Only AITER's CK/ASM ops (flydsl moe_common, CK rmsnorm) are CDNA-only (MI2xx/MI3xx). The " + "patched AITER flash-attention + JIT path is built and working on this RDNA2 gfx1030.", + f"{_GFX1030}: the patched native AITER attention runs here — enable it with " + "`SGLANG_USE_AITER=1`. Only the genuinely-unbuilt CK-MoE/flydsl/CK-rmsnorm ops fall back. " + "(The old 'AITER routes to Triton on RDNA' claim is FALSE for the patched build.)", + "Use native AITER attention (`SGLANG_USE_AITER=1`); reserve the Triton fallback for the " + "unbuilt CK ops, not for attention. For capture-safe AITER decode under hipGraph, use the " + "device-resident-metadata path (gfxGRAPH `hgb_decode_pool_*`) — the garble was stale baked-by-" + "value seq metadata, not an AITER defect.", ), ( "invalid_configuration", "error", diff --git a/python/hipgraph_bridge/graph_manager.py b/python/hipgraph_bridge/graph_manager.py index 1702e82..5bda79d 100644 --- a/python/hipgraph_bridge/graph_manager.py +++ b/python/hipgraph_bridge/graph_manager.py @@ -17,6 +17,9 @@ import torch from hipgraph_bridge.capture_safety import ( + acquire_capture_lock, + release_capture_lock, + replay_lock, torch_graph_capture_block_reason, torch_cuda_execution_error, torch_cuda_execution_usable, @@ -156,12 +159,23 @@ def capture_begin(self, *args, **kwargs): raise RuntimeError(torch_graph_capture_block_reason()) if self._graph is None: self._graph = _OriginalCUDAGraph() - self._graph.capture_begin(*args, **kwargs) + # Serialize capture process-wide: on gfx1030/RDNA2, two in-process LLM + # sessions capturing at once corrupt each other. Held until capture_end(); + # released here if capture_begin itself fails so the lock never leaks. + acquire_capture_lock() + try: + self._graph.capture_begin(*args, **kwargs) + except Exception: + release_capture_lock() + raise def capture_end(self): """End graph capture — delegates to real CUDAGraph.""" if self._graph is not None: - self._graph.capture_end() + try: + self._graph.capture_end() + finally: + release_capture_lock() _bump_capture() def pool(self): @@ -176,6 +190,9 @@ def __init__(self, parent, dynamic_shapes, buckets, conditional_branches): self.dynamic_shapes = dynamic_shapes self.buckets = buckets self.conditional_branches = conditional_branches + # True while this context holds the process-global capture lock + # (standard capture path only; deferred bucketing locks per-bucket). + self._capture_lock_held = False def __enter__(self): self.parent._stream = torch.cuda.Stream() @@ -193,6 +210,10 @@ def __enter__(self): try: if not unsafe_torch_graph_capture_enabled(): raise RuntimeError(torch_graph_capture_block_reason()) + # Serialize capture across in-process sessions (gfx1030 fix). + # Released in __exit__, or below if this enter fails. + acquire_capture_lock() + self._capture_lock_held = True self.parent._graph = _OriginalCUDAGraph() torch.cuda.synchronize() self.parent._capture_ctx = torch.cuda.graph( @@ -206,6 +227,9 @@ def __enter__(self): torch.cuda.synchronize() except Exception: pass + if self._capture_lock_held: + release_capture_lock() + self._capture_lock_held = False self.parent._capture_ctx = None self.parent._graph = None self.parent._eager_fallback = True @@ -252,6 +276,9 @@ def __exit__(self, exc_type, exc_val, exc_tb): torch.cuda.synchronize() except Exception: pass + if self._capture_lock_held: + release_capture_lock() + self._capture_lock_held = False return True # suppress the exception if self.parent._graph is not None: @@ -273,6 +300,9 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.parent._graph = None self.parent._eager_fallback = True _bump_fallback() + if self._capture_lock_held: + release_capture_lock() + self._capture_lock_held = False return False def capture(self, *, dynamic_shapes=False, buckets=None, @@ -344,10 +374,12 @@ def replay(self, *, batch_size=None, branch=None, input_tensor=None): self._record_replay_sample(t0) return self._maybe_validate(result, input_tensor) - # Standard graph replay + # Standard graph replay (shared replay lock: concurrent replays are + # fine; excluded only during another session's one-time capture). if self._graph is not None: if _HOT_REPLAY_MODE: - self._graph.replay() + with replay_lock(): + self._graph.replay() return self._static_output sample_diagnostics = True if _TRUSTED_REPLAY_THRESHOLD > 0 and self._trusted_replay_active: @@ -356,7 +388,8 @@ def replay(self, *, batch_size=None, branch=None, input_tensor=None): torch.cuda.synchronize() t0 = time.perf_counter() if sample_diagnostics else 0.0 try: - self._graph.replay() + with replay_lock(): + self._graph.replay() except Exception as e: # GUARD tier 2: turn an opaque illegal-access into a precise, # localized report (op + tensor layouts) before falling back. diff --git a/python/hipgraph_bridge/shape_bucketing.py b/python/hipgraph_bridge/shape_bucketing.py index 7d3e013..ac09026 100644 --- a/python/hipgraph_bridge/shape_bucketing.py +++ b/python/hipgraph_bridge/shape_bucketing.py @@ -28,6 +28,8 @@ import torch from hipgraph_bridge.capture_safety import ( + capture_lock, + replay_lock, torch_graph_capture_block_reason, torch_cuda_execution_error, torch_cuda_execution_usable, @@ -219,18 +221,24 @@ def _capture_bucket( else: static_input = self._static_inputs[bucket_size] - # Warmup run (required before capture) - torch.cuda.synchronize() - with torch.no_grad(): - _ = self.model_fn(static_input) - torch.cuda.synchronize() - - # Capture - graph = torch.cuda.CUDAGraph() - pool = torch.cuda.graph_pool_handle() - self._graph_pools[bucket_size] = pool - with torch.cuda.graph(graph, pool=pool): - static_output = self.model_fn(static_input) + # Serialize capture process-wide: each bucket is its own hipGraph, + # and concurrent capture from a second in-process session corrupts + # output on gfx1030. The lock spans warmup + capture (one-time/lazy), + # then is released before the replay below — no nesting with the + # shared replay lock. + with capture_lock(): + # Warmup run (required before capture) + torch.cuda.synchronize() + with torch.no_grad(): + _ = self.model_fn(static_input) + torch.cuda.synchronize() + + # Capture + graph = torch.cuda.CUDAGraph() + pool = torch.cuda.graph_pool_handle() + self._graph_pools[bucket_size] = pool + with torch.cuda.graph(graph, pool=pool): + static_output = self.model_fn(static_input) self._graphs[bucket_size] = graph self._static_outputs[bucket_size] = static_output @@ -320,8 +328,10 @@ def __call__(self, input_tensor_or_size) -> torch.Tensor: if input_size < bucket: static_in[input_size:].zero_() # Zero-pad - # Replay - self._graphs[bucket].replay() + # Replay (shared lock; the lazy capture above already released the + # exclusive lock, so there is no self-deadlock). + with replay_lock(): + self._graphs[bucket].replay() return self._materialize_output(bucket, input_size) diff --git a/rust/rs_gfxgraph/Cargo.lock b/rust/rs_gfxgraph/Cargo.lock index 7874961..c0486e6 100644 --- a/rust/rs_gfxgraph/Cargo.lock +++ b/rust/rs_gfxgraph/Cargo.lock @@ -2,131 +2,3567 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "ar_archive_writer" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" +dependencies = [ + "object", +] + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "boxcar" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f64beae40a84da1b4b26ff2761a5b895c12adc41dc25aaee1c4f2bbfe97a6e" + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "bytesize" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3" + +[[package]] +name = "bzip2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" +dependencies = [ + "libbz2-rs-sys", +] + +[[package]] +name = "cab" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171228650e6721d5acc0868a462cd864f49ac5f64e4a42cde270406e64e404d2" +dependencies = [ + "byteorder", + "flate2", + "lzxd", + "time", +] + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-config2" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ada53f7339c78084fb37d7e17f34e76537541c4fbb02fa3a2baa14b8faad37" +dependencies = [ + "serde", + "serde_derive", + "toml 1.1.2+spec-1.1.0", +] + +[[package]] +name = "cargo-options" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89e1d6d6f65fe04d5e21be9de19d31a074e3b7e43aa39ee5b85f4cee16c3188" +dependencies = [ + "anstyle", + "clap", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84982c6c0ae343635a3a4ee6dedef965513735c8b183caa7289fa6e27399ebd4" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-util-schemas" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63d2780ac94487eb9f1fea7b0d56300abc9eb488800854ca217f102f5caccca" +dependencies = [ + "semver", + "serde", + "serde-untagged", + "serde-value", + "thiserror 1.0.69", + "toml 0.8.23", + "unicode-xid", + "url", +] + +[[package]] +name = "cargo-xwin" +version = "0.18.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dff83aad332bd6ee29072dd874b48892cd22c58e233c25735eb4417b3999685" +dependencies = [ + "anyhow", + "cargo-config2", + "cargo-options", + "clap", + "dirs", + "fs-err", + "humantime", + "indicatif", + "paste", + "path-slash", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "tar", + "tracing-subscriber", + "ureq", + "which", + "xwin", + "xz2", +] + +[[package]] +name = "cargo-zigbuild" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9584d77470f7ffea2fb67fbcc9e8dbe9fa79a80dafd579a83507c0a08d1f658" +dependencies = [ + "anyhow", + "cargo-config2", + "cargo-options", + "cargo_metadata 0.19.2", + "clap", + "crc", + "dirs", + "fs-err", + "path-slash", + "rustc_version", + "rustflags", + "semver", + "serde", + "serde_json", + "shlex", + "target-lexicon", + "which", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform 0.1.9", + "semver", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "cargo_metadata" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f7835cfc6135093070e95eb2b53e5d9b5c403dc3a6be6040ee026270aa82502" +dependencies = [ + "camino", + "cargo-platform 0.2.0", + "cargo-util-schemas", + "semver", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "cbindgen" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" +dependencies = [ + "heck", + "indexmap", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", + "tempfile", + "toml 0.9.12+spec-1.1.0", +] + +[[package]] +name = "cc" +version = "1.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfb" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a4f8e55be323b378facfcf1f06aa97f6ec17cf4ac84fb17325093aaf62da41" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "charset" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f927b07c74ba84c7e5fe4db2baeb3e996ab2688992e39ac68ce3220a677c7e" +dependencies = [ + "base64", + "encoding_rs", +] + +[[package]] +name = "chumsky" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba4a05c9ce83b07de31b31c874e87c069881ac4355db9e752e3a55c11ec75a6" +dependencies = [ + "hashbrown 0.15.5", + "regex-automata 0.3.9", + "serde", + "stacker", + "unicode-ident", + "unicode-segmentation", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_complete" +version = "4.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "660c0520455b1013b9bcb0393d5f643d7e4454fb69c915b8d6d2aa0e9a45acc3" +dependencies = [ + "clap", +] + +[[package]] +name = "clap_complete_command" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da8e198c052315686d36371e8a3c5778b7852fc75cc313e4e11eeb7a644a1b62" +dependencies = [ + "clap", + "clap_complete", + "clap_complete_nushell", +] + +[[package]] +name = "clap_complete_nushell" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb9e9715d29a754b468591be588f6b926f5b0a1eb6a8b62acabeb66ff84d897" +dependencies = [ + "clap", + "clap_complete", +] + +[[package]] +name = "clap_derive" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "cli-table" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b53f9241f288a7b12c56565f04aaeaeeab6b8923d42d99255d4ca428b4d97f89" +dependencies = [ + "termcolor", + "unicode-width 0.1.14", +] + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "configparser" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57e3272f0190c3f1584272d613719ba5fc7df7f4942fe542e63d949cf3a649b" + +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width 0.2.2", + "windows-sys 0.59.0", +] + +[[package]] +name = "console" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +dependencies = [ + "encode_unicode", + "libc", + "unicode-width 0.2.2", + "windows-sys 0.61.2", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "data-encoding" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dialoguer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" +dependencies = [ + "console 0.15.11", + "shell-words", + "thiserror 1.0.69", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fat-macho" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64465b99fa411ca36a47048e9b1deec20f609b072711e3949e6d135403ea16d" +dependencies = [ + "goblin", +] + +[[package]] +name = "filetime" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs-err" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fde052dbfc920003cfd2c8e2c6e6d4cc7c1091538c3a24226cec0665ab08c0" +dependencies = [ + "autocfg", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "gfxgraph_rs" +version = "0.1.0" +dependencies = [ + "maturin", + "pyo3", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "globset" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata 0.4.14", + "regex-syntax 0.8.10", +] + +[[package]] +name = "goblin" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "983a6aafb3b12d4c41ea78d39e189af4298ce747353945ff5105b54a056e5cd9" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "ignore" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata 0.4.14", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", + "serde", + "serde_core", +] + +[[package]] +name = "indicatif" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +dependencies = [ + "console 0.15.11", + "number_prefix", + "portable-atomic", + "unicode-width 0.2.2", + "web-time", +] + +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lddtree" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd71f004036b2ea41763739528084d0d2a9dea4fda11816a31d67edb2bd239f" +dependencies = [ + "fs-err", + "glob", + "goblin", + "memmap2", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libbz2-rs-sys" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a6a8c165077efc8f3a971534c50ea6a1a18b329ef4a66e897a7e3a1494565f" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libmimalloc-sys" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1eacfa31c33ec25e873c136ba5669f00f9866d0688bea7be4d3f7e43067df6" +dependencies = [ + "cc", +] + +[[package]] +name = "libredox" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +dependencies = [ + "bitflags", + "libc", + "plain", + "redox_syscall 0.7.5", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lzma-rust2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c60a23ffb90d527e23192f1246b14746e2f7f071cb84476dd879071696c18a4a" +dependencies = [ + "crc", + "sha2", +] + +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "lzxd" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b29dffab797218e12e4df08ef5d15ab9efca2504038b1b32b9b32fc844b39c9" + +[[package]] +name = "mailparse" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60819a97ddcb831a5614eb3b0174f3620e793e97e09195a395bfa948fd68ed2f" +dependencies = [ + "charset", + "data-encoding", + "quoted_printable", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata 0.4.14", +] + +[[package]] +name = "maturin" +version = "1.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20e80309d624ac75e42b621910adfcf3ee89331331ecea0b5ca510db575f66f0" +dependencies = [ + "anyhow", + "base64", + "bytesize", + "cargo-config2", + "cargo-options", + "cargo-xwin", + "cargo-zigbuild", + "cargo_metadata 0.20.0", + "cbindgen", + "cc", + "clap", + "clap_complete_command", + "configparser", + "console 0.16.3", + "dialoguer", + "dirs", + "dunce", + "fat-macho", + "flate2", + "fs-err", + "glob", + "goblin", + "ignore", + "indexmap", + "itertools 0.14.0", + "lddtree", + "minijinja", + "multipart", + "normpath", + "once_cell", + "path-slash", + "pep440_rs", + "pep508_rs", + "platform-info", + "pyproject-toml", + "python-pkginfo", + "regex", + "rustc_version", + "rustflags", + "rustls", + "rustls-pemfile", + "same-file", + "semver", + "serde", + "serde_json", + "sha2", + "tar", + "target-lexicon", + "tempfile", + "textwrap", + "thiserror 2.0.18", + "time", + "toml 0.9.12+spec-1.1.0", + "toml_edit 0.23.10+spec-1.0.0", + "tracing", + "tracing-subscriber", + "unicode-xid", + "ureq", + "url", + "wild", + "xz2", + "zip 6.0.0", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + +[[package]] +name = "memo-map" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d1115007560874e373613744c6fba374c17688327a71c1476d1a5954cc857b" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mimalloc" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3627c4272df786b9260cabaa46aec1d59c93ede723d4c3ef646c503816b0640" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minijinja" +version = "2.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805bfd7352166bae857ee569628b52bcd85a1cecf7810861ebceb1686b72b75d" +dependencies = [ + "memo-map", + "serde", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "msi" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a2332f87a064dea9cce571408c879e0da8dc193b3af06a2b3b2604ee4182a32" +dependencies = [ + "byteorder", + "cfb", + "encoding_rs", + "uuid", +] + +[[package]] +name = "multipart" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" +dependencies = [ + "log", + "mime", + "mime_guess", + "rand", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "normpath" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9985ef7269fa99f3b12437bb698381da2428743ab90f20393f399fa14cab21a" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + +[[package]] +name = "pep440_rs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31095ca1f396e3de32745f42b20deef7bc09077f918b085307e8eab6ddd8fb9c" +dependencies = [ + "once_cell", + "serde", + "tracing", + "unicode-width 0.2.2", + "unscanny", + "version-ranges", +] + +[[package]] +name = "pep508_rs" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faee7227064121fcadcd2ff788ea26f0d8f2bd23a0574da11eca23bc935bcc05" +dependencies = [ + "boxcar", + "indexmap", + "itertools 0.13.0", + "once_cell", + "pep440_rs", + "regex", + "rustc-hash", + "serde", + "smallvec", + "thiserror 1.0.69", + "tracing", + "unicode-width 0.2.2", + "url", + "urlencoding", + "version-ranges", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "platform-info" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9368d62437c8cbb7c31ee37fd8c08a7d390e09a3ff75698a674953f46705ffcb" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761ea" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "pyo3" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17da310086b068fbdcefbba30aeb3721d5bb9af8db4987d6735b2183ca567229" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e27165889bd793000a098bb966adc4300c312497ea25cf7a690a9f0ac5aa5fc1" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05280526e1dbf6b420062f3ef228b78c0c54ba94e157f5cb724a609d0f2faabc" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3ce5686aa4d3f63359a5100c62a127c9f15e8398e5fdeb5deef1fed5cd5f44" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4cf6faa0cbfb0ed08e89beb8103ae9724eb4750e3a78084ba4017cbe94f3855" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn", +] + +[[package]] +name = "pyproject-toml" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d755483ad14b49e76713b52285235461a5b4f73f17612353e11a5de36a5fd2" +dependencies = [ + "glob", + "indexmap", + "pep440_rs", + "pep508_rs", + "serde", + "thiserror 2.0.18", + "toml 0.9.12+spec-1.1.0", +] + +[[package]] +name = "python-pkginfo" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229fe47647d6602b9b0934b21fab8aece1c5a5aeb0a934196a14355fec656623" +dependencies = [ + "flate2", + "fs-err", + "mailparse", + "rfc2047-decoder", + "tar", + "thiserror 2.0.18", + "zip 8.6.0", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "quoted_printable" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478e0585659a122aa407eb7e3c0e1fa51b1d8a870038bd29f0cf4a8551eea972" + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4666a1a60d8412eab19d94f6d13dcc9cea0a5ef4fdf6a5db306537413c661b1b" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.14", + "regex-syntax 0.8.10", +] + +[[package]] +name = "regex-automata" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.5", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.10", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rfc2047-decoder" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504ea008279c473dfeafce327fa26bf8825463cfcc06ef82f866187e81334d16" +dependencies = [ + "base64", + "charset", + "chumsky", + "memchr", + "quoted_printable", + "thiserror 2.0.18", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustflags" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a39e0e9135d7a7208ee80aa4e3e4b88f0f5ad7be92153ed70686c38a03db2e63" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scroll" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + +[[package]] +name = "socks" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b" +dependencies = [ + "byteorder", + "libc", + "winapi", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stacker" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.61.2", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tar" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" +dependencies = [ + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width 0.2.2", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.2", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.2", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata 0.4.14", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "rand", + "static_assertions", +] + +[[package]] +name = "typed-path" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unindent" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" + +[[package]] +name = "unscanny" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9df2af067a7953e9c3831320f35c1cc0600c30d44d9f7a12b01db1cd88d6b47" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "socks", + "url", + "webpki-roots 0.26.11", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version-ranges" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e9bd4e9c9ff6a2a9b5969462ba26216af3e010df0377dad8320ab515262ef8" +dependencies = [ + "smallvec", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "versions" +version = "6.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25d498b63d1fdb376b4250f39ab3a5ee8d103957346abacd911e2d8b612c139" +dependencies = [ + "itertools 0.13.0", + "nom", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.7", +] [[package]] -name = "libc" -version = "0.2.186" +name = "webpki-roots" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +dependencies = [ + "rustls-pki-types", +] [[package]] -name = "once_cell" -version = "1.21.4" +name = "which" +version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" +dependencies = [ + "either", + "env_home", + "rustix", + "winsafe", +] [[package]] -name = "portable-atomic" -version = "1.13.1" +name = "wild" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "a3131afc8c575281e1e80f36ed6a092aa502c08b18ed7524e86fbbb12bb410e1" +dependencies = [ + "glob", +] [[package]] -name = "proc-macro2" -version = "1.0.106" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "unicode-ident", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "pyo3" -version = "0.29.0" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "libc", - "once_cell", - "portable-atomic", - "pyo3-build-config", - "pyo3-ffi", - "pyo3-macros", + "windows-sys 0.61.2", ] [[package]] -name = "pyo3-build-config" -version = "0.29.0" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "target-lexicon", + "windows-targets 0.48.5", ] [[package]] -name = "pyo3-ffi" -version = "0.29.0" +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" + +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "xattr" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "pyo3-build-config", + "rustix", ] [[package]] -name = "pyo3-macros" -version = "0.29.0" +name = "xwin" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca7e4546db1514c186778f0a257d89732ed9ed75587d0953ac25be7519d9f0d1" +dependencies = [ + "anyhow", + "bytes", + "cab", + "camino", + "clap", + "cli-table", + "crossbeam-channel", + "indicatif", + "memchr", + "mimalloc", + "msi", + "parking_lot", + "rayon", + "regex", + "serde", + "serde_json", + "sha2", + "tempfile", + "toml 0.8.23", + "tracing", + "tracing-subscriber", + "twox-hash", + "ureq", + "versions", + "walkdir", + "zip 2.4.2", +] + +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + +[[package]] +name = "yoke" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", - "pyo3-macros-backend", "quote", "syn", + "synstructure", ] [[package]] -name = "pyo3-macros-backend" -version = "0.29.0" +name = "zerocopy" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ - "heck", "proc-macro2", "quote", "syn", ] [[package]] -name = "quote" -version = "1.0.45" +name = "zerofrom" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", + "quote", + "syn", + "synstructure", ] [[package]] -name = "rs_gfxgraph" -version = "0.1.0" +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ - "pyo3", + "displaydoc", + "yoke", + "zerofrom", ] [[package]] -name = "syn" -version = "2.0.117" +name = "zerovec" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "unicode-ident", + "syn", ] [[package]] -name = "target-lexicon" -version = "0.13.5" +name = "zip" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" +checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +dependencies = [ + "arbitrary", + "crc32fast", + "crossbeam-utils", + "displaydoc", + "flate2", + "indexmap", + "memchr", + "thiserror 2.0.18", + "zopfli", +] [[package]] -name = "unicode-ident" -version = "1.0.24" +name = "zip" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b" +dependencies = [ + "arbitrary", + "bzip2", + "crc32fast", + "flate2", + "indexmap", + "lzma-rust2", + "memchr", + "time", + "zopfli", + "zstd", +] + +[[package]] +name = "zip" +version = "8.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" +dependencies = [ + "crc32fast", + "flate2", + "indexmap", + "memchr", + "typed-path", + "zopfli", +] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/rust/rs_gfxgraph/Cargo.toml b/rust/rs_gfxgraph/Cargo.toml index 00ceff7..6d2f686 100644 --- a/rust/rs_gfxgraph/Cargo.toml +++ b/rust/rs_gfxgraph/Cargo.toml @@ -8,5 +8,9 @@ name = "rs_gfxgraph" crate-type = ["cdylib", "rlib"] [dependencies] -pyo3 = { version = "0.29.0", features = ["extension-module", "auto-initialize"] } +pyo3 = { version = "0.24.1", features = ["extension-module", "auto-initialize"] } +libc = "0.2" +rs_gfxgraph_core = { path = "../rs_gfxgraph_core" } +[build-dependencies] +maturin = "1.5.0" diff --git a/rust/rs_gfxgraph/src/lib.rs b/rust/rs_gfxgraph/src/lib.rs index afa360a..5d0d83a 100644 --- a/rust/rs_gfxgraph/src/lib.rs +++ b/rust/rs_gfxgraph/src/lib.rs @@ -1,9 +1,157 @@ use pyo3::prelude::*; use pyo3::exceptions::{PyValueError, PyKeyError, PyRuntimeError, PyTypeError}; -use pyo3::types::{PyAny, PyDict}; +use pyo3::types::PyDict; +use rs_gfxgraph_core::capture_gate; use std::collections::HashSet; use std::sync::RwLock; +use std::sync::OnceLock; + +/// Stores the result of system-level environment and core-affinity initializations. +static INIT_RESULT: OnceLock, Option>), String>> = OnceLock::new(); + +/// Helper to parse standard Linux sysfs CPU lists (e.g. "0-2,12-14"). +#[cfg(target_os = "linux")] +fn parse_cpu_list(list_str: &str) -> Vec { + let mut cores = Vec::new(); + for part in list_str.split(',') { + let part = part.trim(); + if part.contains('-') { + let mut range_parts = part.split('-'); + if let (Some(start_str), Some(end_str)) = (range_parts.next(), range_parts.next()) { + if let (Ok(start), Ok(end)) = (start_str.parse::(), end_str.parse::()) { + for core in start..=end { + cores.push(core); + } + } + } + } else if let Ok(core) = part.parse::() { + cores.push(core); + } + } + cores +} + +/// Dynamic GPU detection and thread-affinity alignment optimized for AMD systems. +/// +/// 1. Detects if an RDNA2 card (gfx1030/1031) is installed on Linux. If so, and +/// HSA_OVERRIDE_GFX_VERSION is unset, it programmatically sets it to "10.3.0". +/// 2. Resolves CPU Core Complex (CCX) cache-sharing topology via sysfs and pins +/// the calling thread to local CPU cores to minimize Infinity Fabric latency. +#[cfg(target_os = "linux")] +fn init_environment_and_affinity() -> Result<(Option, Option>), String> { + // 1. Programmatic HSA Override for gfx1030/1031 (Navi 21 / Navi 22) + let mut hsa_overridden = None; + if std::env::var("HSA_OVERRIDE_GFX_VERSION").is_err() { + if let Ok(entries) = std::fs::read_dir("/sys/class/drm") { + for entry in entries.flatten() { + let path = entry.path(); + let name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); + if name.starts_with("card") { + let dev_path = path.join("device/device"); + let vend_path = path.join("device/vendor"); + if let (Ok(dev_str), Ok(vend_str)) = (std::fs::read_to_string(dev_path), std::fs::read_to_string(vend_path)) { + let dev_id = dev_str.trim().to_lowercase(); + let vend_id = vend_str.trim().to_lowercase(); + // 0x1002 is the AMD PCI vendor ID + if vend_id.contains("1002") { + // Check for Navi 22 (0x73df - RX 6700 XT) or Navi 21 (0x73a5, 0x73a0, 0x73bf) + if dev_id.contains("73df") || dev_id.contains("73a5") || dev_id.contains("73a0") || dev_id.contains("73bf") { + std::env::set_var("HSA_OVERRIDE_GFX_VERSION", "10.3.0"); + hsa_overridden = Some("10.3.0".to_string()); + // gfx1030/Zen2 perf env (don't override the user): SDMA copy engines for + // CPU-free H2D/D2H, and non-coherent host memory so the ~96 MB Infinity + // Cache can cache system-RAM reads instead of every access traversing PCIe. + if std::env::var("HSA_ENABLE_SDMA").is_err() { + std::env::set_var("HSA_ENABLE_SDMA", "1"); + } + if std::env::var("HIP_HOST_COHERENT").is_err() { + std::env::set_var("HIP_HOST_COHERENT", "0"); + } + break; + } + } + } + } + } + } + } + + // 2. Local L3/CCX Cache Pinning + let mut pinned_cores = None; + unsafe { + let cpu = libc::sched_getcpu(); + if cpu >= 0 { + let cache_list_path = format!("/sys/devices/system/cpu/cpu{}/cache/index3/shared_cpu_list", cpu); + if let Ok(list_str) = std::fs::read_to_string(&cache_list_path) { + let cores = parse_cpu_list(&list_str); + if !cores.is_empty() { + let mut cpuset: libc::cpu_set_t = std::mem::zeroed(); + for &core in &cores { + if core < 1024 { + libc::CPU_SET(core, &mut cpuset); + } + } + let res = libc::sched_setaffinity(0, std::mem::size_of::(), &cpuset); + if res == 0 { + pinned_cores = Some(cores); + } + } + } + } + } + + Ok((hsa_overridden, pinned_cores)) +} +#[cfg(not(target_os = "linux"))] +fn init_environment_and_affinity() -> Result<(Option, Option>), String> { + Err("HSA overrides and CPU pinning are only supported on Linux targets.".to_string()) +} + +/// Exposes the CPU core indices that the current process thread was pinned to. +#[pyfunction] +fn pinned_cpu_cores() -> PyResult>> { + match INIT_RESULT.get() { + Some(Ok((_, Some(cores)))) => Ok(Some(cores.clone())), + _ => Ok(None), + } +} + +/// Exposes the value of HSA_OVERRIDE_GFX_VERSION if programmatically set on boot. +#[pyfunction] +fn hsa_override_applied() -> PyResult> { + match INIT_RESULT.get() { + Some(Ok((Some(val), _))) => Ok(Some(val.clone())), + _ => Ok(None), + } +} + +/// Returns a descriptive diagnostic message of the system initialization achievements. +#[pyfunction] +fn init_status_message() -> PyResult { + match INIT_RESULT.get() { + Some(Ok((override_val, pinned))) => { + let mut msg = String::new(); + if let Some(val) = override_val { + msg.push_str(&format!("Applied HSA override value '{}' for RDNA2. ", val)); + } else { + msg.push_str("No programmatic HSA overrides needed. "); + } + if let Some(cores) = pinned { + msg.push_str(&format!("Successfully pinned thread to local L3 cache/CCX cores: {:?}", cores)); + } else { + msg.push_str("Affinity core-pinning not executed or bypassed."); + } + Ok(msg) + } + Some(Err(e)) => Ok(format!("Initialization failed with warning: {}", e)), + None => Ok("Initialization has not run yet.".to_string()), + } +} + +/// High-performance bucket selection and state tracker for dynamic-shape inputs. +/// +/// Implemented natively in Rust to bypass Python Bisect and interpreter boundary crossings. #[pyclass] pub struct BucketRouter { buckets: Vec, @@ -22,43 +170,57 @@ impl BucketRouter { } } - fn route(&self, input_size: usize) -> PyResult<(i64, u8)> { - let bucket_val = match self.buckets.binary_search(&input_size) { + /// Selects the smallest bucket size >= input_size and returns (bucket_size, state_code). + /// + /// State Codes: + /// - 0: Ready (Graph is warmed up) + /// - 1: NeedsWarmup (Graph needs capture/replay warmup) + /// - 2: Failed (Graph capture or execution previously failed) + fn route(&self, input_size: usize) -> PyResult<(usize, u8)> { + let bucket = match self.buckets.binary_search(&input_size) { Ok(idx) => self.buckets[idx], Err(idx) => { if idx < self.buckets.len() { self.buckets[idx] } else { - return Ok((-1, 2)); + return Err(PyValueError::new_err(format!( + "Input size {} exceeds largest bucket {}. Add a larger bucket.", + input_size, + self.buckets.last().unwrap_or(&0) + ))); } } }; - let state = if self.warmed_up.contains(&bucket_val) { - 0 // Ready - } else if self.failed_buckets.contains(&bucket_val) { - 2 // Failed + let state = if self.warmed_up.contains(&bucket) { + 0 + } else if self.failed_buckets.contains(&bucket) { + 2 } else { - 1 // NeedsWarmup + 1 }; - Ok((bucket_val as i64, state)) + Ok((bucket, state)) } + /// Marks a bucket size as successfully warmed up. fn mark_warmed_up(&mut self, bucket_size: usize) { self.warmed_up.insert(bucket_size); } + /// Marks a bucket size as failed (forcing eager execution routing). fn mark_failed(&mut self, bucket_size: usize) { self.failed_buckets.insert(bucket_size); } + /// Returns the sorted list of warmed up bucket sizes. fn warmed_up_list(&self) -> Vec { let mut list: Vec = self.warmed_up.iter().copied().collect(); list.sort_unstable(); list } + /// Returns the sorted list of failed bucket sizes. fn failed_list(&self) -> Vec { let mut list: Vec = self.failed_buckets.iter().copied().collect(); list.sort_unstable(); @@ -66,14 +228,34 @@ impl BucketRouter { } } +/// Safe RAII guard to track currently replaying branches in ConditionalGraphRunner. +/// Prevents thread re-entrancy collision by removing the branch from the running registry when dropped. +struct ReentrancyGuard<'a> { + runner: &'a ConditionalGraphRunner, + branch: &'a str, +} + +impl<'a> Drop for ReentrancyGuard<'a> { + fn drop(&mut self) { + if let Ok(mut lock) = self.runner.running_branches.write() { + lock.remove(self.branch); + } + } +} + +/// Native conditional graph execution manager. +/// +/// Bypasses Python dictionary mapping checks and provides thread-safe validation, +/// eager callbacks, performance logging, and atomic thread re-entrancy collision protection. #[pyclass] pub struct ConditionalGraphRunner { branches: Vec, - graphs: Py, // dict branch_name -> CUDAGraph - static_outputs: Py, // dict branch_name -> static output tensor + graphs: PyObject, // dict branch_name -> CUDAGraph + static_outputs: PyObject, // dict branch_name -> static output tensor failed_branches: RwLock>, - shared_input: Py, // optional shared tensor - branches_callbacks: Py, // dict branch_name -> callable fallback + running_branches: RwLock>, // Keeps track of currently replaying branches + shared_input: PyObject, // optional shared tensor + branches_callbacks: PyObject, // dict branch_name -> callable fallback } #[pymethods] @@ -81,11 +263,11 @@ impl ConditionalGraphRunner { #[new] fn new( branches: Vec, - graphs: Py, - static_outputs: Py, + graphs: PyObject, + static_outputs: PyObject, failed_branches: Vec, - shared_input: Py, - branches_callbacks: Py, + shared_input: PyObject, + branches_callbacks: PyObject, ) -> Self { let mut failed = HashSet::new(); for b in failed_branches { @@ -96,17 +278,22 @@ impl ConditionalGraphRunner { graphs, static_outputs, failed_branches: RwLock::new(failed), + running_branches: RwLock::new(HashSet::new()), shared_input, branches_callbacks, } } + /// Runs a specific branch's graph capture. + /// + /// Validates inputs, handles eager fallbacks, records run latency, and protects + /// against parallel re-entrancy conflicts on the GPU. fn run<'py>( &self, py: Python<'py>, branch: &str, - input_tensor: Option>, - ) -> PyResult> { + input_tensor: Option, + ) -> PyResult { if !self.branches.iter().any(|b| b == branch) { return Err(PyKeyError::new_err(format!( "Unknown branch '{}'. Available: {:?}", @@ -115,6 +302,7 @@ impl ConditionalGraphRunner { ))); } + // Validate input tensor type and location if provided if let Some(ref input) = input_tensor { let torch_mod = py.import("torch")?; let tensor_cls = torch_mod.getattr("Tensor")?; @@ -123,10 +311,11 @@ impl ConditionalGraphRunner { } let is_cuda: bool = input.getattr(py, "is_cuda")?.extract(py)?; if !is_cuda { - return Err(PyValueError::new_err("input_tensor must be on CUDA device")); + return Err(PyValueError::new_err("input_tensor must be on CUDA/HIP device")); } } + // If the branch is already marked as failed, immediately route to eager fallback let failed = { let lock = self.failed_branches.read().unwrap(); lock.contains(branch) @@ -135,13 +324,37 @@ impl ConditionalGraphRunner { return self.eager_fallback(py, branch, input_tensor); } + // Re-entrancy / Thread Collision Guard: + // If this branch is currently running on another thread/stream, bypass the graph + // replay and route to eager fallback to prevent memory space address conflicts. + { + let lock = self.running_branches.read().unwrap(); + if lock.contains(branch) { + let log_mod = py.import("logging")?; + let logger = log_mod.call_method1("getLogger", ("gfxgraph",))?; + logger.call_method1("warning", (format!("Parallel re-entrancy collision detected on branch '{}' — bypassing graph replay for safety", branch),))?; + return self.eager_fallback(py, branch, input_tensor); + } + } + + // Register that the branch is running + { + let mut lock = self.running_branches.write().unwrap(); + lock.insert(branch.to_string()); + } + + // Establish the RAII drop guard to release this branch execution lock on exit + let _guard = ReentrancyGuard { runner: self, branch }; + + // Copy input to shared static buffer if necessary if let Some(ref input) = input_tensor { if !self.shared_input.is_none(py) { self.shared_input.call_method1(py, "copy_", (input,))?; } } - let start = std::time::Instant::now(); + let time_mod = py.import("time")?; + let t0: f64 = time_mod.call_method0("perf_counter")?.extract()?; let graphs_dict = self.graphs.downcast_bound::(py) .map_err(|_| PyRuntimeError::new_err("Invalid state: graphs must be a dict"))?; @@ -153,17 +366,13 @@ impl ConditionalGraphRunner { logger.call_method1("warning", (format!("Replay failed for branch '{}': {:?} — eager fallback", branch, e),))?; if let Ok(mut lock) = self.failed_branches.write() { - if lock.insert(branch.to_string()) { - if let Ok(enable_mod) = py.import("gfxgraph._enable") { - let _ = enable_mod.call_method1("bump", ("fallback_count",)); - } - } + lock.insert(branch.to_string()); } return self.eager_fallback(py, branch, input_tensor); } } - let us = start.elapsed().as_secs_f64() * 1_000_000.0; + let us = (time_mod.call_method0("perf_counter")?.extract::()? - t0) * 1e6; if let Ok(enable_mod) = py.import("gfxgraph._enable") { let _ = enable_mod.call_method1("record_replay_us", (us,)); @@ -175,21 +384,23 @@ impl ConditionalGraphRunner { if let Some(out) = output { Ok(out.into()) } else { - Err(PyRuntimeError::new_err("Output not found")) + Err(PyRuntimeError::new_err("Static output buffer not found for branch")) } } - fn eager_fallback<'py>(&self, py: Python<'py>, branch: &str, input_tensor: Option>) -> PyResult> { + /// Evaluates branch callback function eagerly inside a PyTorch no_grad context. + fn eager_fallback<'py>(&self, py: Python<'py>, branch: &str, input_tensor: Option) -> PyResult { let callbacks_dict = self.branches_callbacks.downcast_bound::(py) .map_err(|_| PyRuntimeError::new_err("Invalid state: branches_callbacks must be a dict"))?; let fn_obj = callbacks_dict.get_item(branch)?.ok_or_else(|| PyRuntimeError::new_err("Branch fallback not found"))?; - // We no longer bump fallback_count here, it's structurally bumped on transition. + if let Ok(enable_mod) = py.import("gfxgraph._enable") { + let _ = enable_mod.call_method1("bump", ("fallback_count",)); + } let torch_mod = py.import("torch")?; let no_grad_ctx = torch_mod.call_method0("no_grad")?; - // Use no_grad context let _ = no_grad_ctx.call_method0("__enter__")?; let result = if let Some(ref input) = input_tensor { @@ -213,21 +424,132 @@ impl ConditionalGraphRunner { None => py.None(), }; let _ = no_grad_ctx.call_method1("__exit__", (exc_type, exc_value, exc_traceback)); - return Err(e); + Err(e) } } } } +/// Context manager that serializes hipGraph capture process-wide. +/// +/// On gfx1030/RDNA2 under ROCm, two in-process LLM sessions that capture graphs +/// at the same time corrupt each other's output (HIP capture bookkeeping is +/// process-global). Wrapping a capture in `with rs_gfxgraph.CaptureLock():` +/// guarantees one capture at a time across every session, while replay stays +/// concurrent. Acquisition releases the GIL so a thread blocked here cannot +/// deadlock the thread that holds the lock. +#[pyclass] +struct CaptureLock { + held: bool, +} + +#[pymethods] +impl CaptureLock { + #[new] + fn new() -> Self { + CaptureLock { held: false } + } + + fn __enter__(mut slf: PyRefMut<'_, Self>, py: Python<'_>) -> PyResult<()> { + // Release the GIL while blocking on the exclusive lock. + py.allow_threads(capture_gate::lock_capture); + slf.held = true; + Ok(()) + } + + fn __exit__( + mut slf: PyRefMut<'_, Self>, + _exc_type: PyObject, + _exc_value: PyObject, + _traceback: PyObject, + ) -> PyResult { + if slf.held { + capture_gate::unlock_capture(); + slf.held = false; + } + Ok(false) // never suppress exceptions raised inside the `with` block + } +} + +/// Context manager for a shared (concurrent) graph replay. +/// +/// Multiple replays may proceed at once; they are excluded only while a +/// `CaptureLock` holds the gate (i.e. during the brief one-time capture +/// window). Replay is the hot path, so this is a single uncontended atomic. +#[pyclass] +struct ReplayLock { + held: bool, +} + +#[pymethods] +impl ReplayLock { + #[new] + fn new() -> Self { + ReplayLock { held: false } + } + + fn __enter__(mut slf: PyRefMut<'_, Self>, py: Python<'_>) -> PyResult<()> { + py.allow_threads(capture_gate::lock_replay); + slf.held = true; + Ok(()) + } + + fn __exit__( + mut slf: PyRefMut<'_, Self>, + _exc_type: PyObject, + _exc_value: PyObject, + _traceback: PyObject, + ) -> PyResult { + if slf.held { + capture_gate::unlock_replay(); + slf.held = false; + } + Ok(false) + } +} + +/// Acquire the process-global capture lock for the begin/end capture API +/// (`BridgedCUDAGraph.capture_begin`/`capture_end`, the SGLang/vLLM drop-in +/// path) which spans two calls and cannot use a context manager. Releases the +/// GIL while blocking. Pair exactly once with [`release_capture_lock`]. +#[pyfunction] +fn acquire_capture_lock(py: Python<'_>) { + py.allow_threads(capture_gate::lock_capture); +} +/// Release the process-global capture lock acquired by [`acquire_capture_lock`]. +#[pyfunction] +fn release_capture_lock() { + capture_gate::unlock_capture(); +} + +/// Exposes the compiled Rust components as a python module. #[pymodule] fn rs_gfxgraph(m: &Bound<'_, PyModule>) -> PyResult<()> { + // Perform one-time initialization of core-affinity and HSA overrides on boot + let _ = INIT_RESULT.get_or_init(init_environment_and_affinity); + m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + + // Register system info functions + m.add_function(wrap_pyfunction!(pinned_cpu_cores, m)?)?; + m.add_function(wrap_pyfunction!(hsa_override_applied, m)?)?; + m.add_function(wrap_pyfunction!(init_status_message, m)?)?; + + // Process-global hipGraph capture serialization (begin/end API). + m.add_function(wrap_pyfunction!(acquire_capture_lock, m)?)?; + m.add_function(wrap_pyfunction!(release_capture_lock, m)?)?; + Ok(()) } +/// Evaluates graph outputs against eager outputs to validate capture correctness. +/// +/// Designed to catch silent incorrect replays on AMD platforms (e.g. PyTorch #155684). #[pyclass] pub struct BridgedGraphValidator { validation_enabled: bool, @@ -240,13 +562,14 @@ impl BridgedGraphValidator { BridgedGraphValidator { validation_enabled } } + /// Verifies if graph execution matches eager execution when validation mode is on. fn maybe_validate<'py>( &self, py: Python<'py>, - graph_output: Py, - input_tensor: Option>, - model_fn: Option>, - ) -> PyResult> { + graph_output: PyObject, + input_tensor: Option, + model_fn: Option, + ) -> PyResult { if !self.validation_enabled { return Ok(graph_output); } @@ -269,14 +592,13 @@ impl BridgedGraphValidator { let _ = no_grad_ctx.call_method1("__exit__", (py.None(), py.None(), py.None()))?; - // simplified for now, use default tolerances or implement kwargs equivalent let allclose = torch.call_method1("allclose", (&graph_output, &eager_output))?; let is_close: bool = allclose.extract()?; if !is_close { let log_mod = py.import("logging")?; let logger = log_mod.call_method1("getLogger", ("gfxgraph",))?; - logger.call_method1("error", ("VALIDATION FAILURE: graph output differs from eager output! \u{2014} possible PyTorch #155684",))?; + logger.call_method1("error", ("VALIDATION FAILURE: graph output differs from eager output! — possible PyTorch #155684",))?; let enable_mod = py.import("gfxgraph._enable").ok(); if let Some(m) = enable_mod { diff --git a/rust/rs_gfxgraph_bench/Cargo.toml b/rust/rs_gfxgraph_bench/Cargo.toml new file mode 100644 index 0000000..a2732e3 --- /dev/null +++ b/rust/rs_gfxgraph_bench/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "rs_gfxgraph_bench" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "gfxgraph-bench-gate" +path = "src/main.rs" + +[dependencies] +clap = { version = "4.5.38", features = ["derive"] } +rs_gfxgraph_core = { path = "../rs_gfxgraph_core" } +rs_gfxgraph_native = { path = "../rs_gfxgraph_native" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" + +[lints] +workspace = true diff --git a/rust/rs_gfxgraph_bench/src/main.rs b/rust/rs_gfxgraph_bench/src/main.rs new file mode 100644 index 0000000..72594c8 --- /dev/null +++ b/rust/rs_gfxgraph_bench/src/main.rs @@ -0,0 +1,1552 @@ +use std::collections::BTreeMap; +use std::error::Error; +use std::fs; +use std::hint::black_box; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; + +use clap::{Parser, ValueEnum}; +use rs_gfxgraph_core::{BucketRouterCore, GfxGraphStatsSample}; +use rs_gfxgraph_native::{default_library_candidates, NativeBridge, ProfileEventKind}; +use serde::Serialize; +use serde_json::{json, Value}; + +const SCHEMA_VERSION: &str = "gfxgraph-benchmark-v1"; +const REPORT_KIND: &str = "benchmark_gate_phase_report"; +const SCHEMA_RELATIVE_PATH: &str = "benchmarks/schemas/gfxgraph-benchmark-v1.schema.json"; + +#[derive(Parser, Debug)] +#[command( + name = "gfxgraph-bench-gate", + about = "Rust-owned gfxGRAPH benchmark gate for installed and candidate package phases" +)] +struct Cli { + #[arg(long)] + repo_root: Option, + + #[arg(long)] + output_root: Option, + + #[arg(long)] + python: Option, + + #[arg(long = "phase", value_enum)] + phases: Vec, + + #[arg(long)] + matrix: bool, + + #[arg(long)] + allow_package_changes: bool, + + #[arg(long)] + no_enforce_import_isolation: bool, + + #[arg(long)] + skip_public: bool, + + #[arg(long)] + skip_python_micro: bool, + + #[arg(long)] + include_python_micro: bool, + + #[arg(long)] + skip_hip: bool, + + #[arg(long)] + native_only: bool, + + #[arg(long, default_value_t = 3)] + public_run_count: u32, + + #[arg(long, default_value_t = 200_000)] + rust_iterations: u64, + + #[arg(long)] + run_id: Option, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)] +enum Phase { + InstalledBaseline, + InstalledGraphEnabled, + CleanCandidate, + GraphCandidate, +} + +impl Phase { + fn as_str(self) -> &'static str { + match self { + Self::InstalledBaseline => "installed-baseline", + Self::InstalledGraphEnabled => "installed-graph-enabled", + Self::CleanCandidate => "clean-candidate", + Self::GraphCandidate => "graph-candidate", + } + } + + fn graph_enabled(self) -> bool { + matches!(self, Self::InstalledGraphEnabled | Self::GraphCandidate) + } + + fn candidate(self) -> bool { + matches!(self, Self::CleanCandidate | Self::GraphCandidate) + } + + fn target_import_policy(self, enforce: bool) -> &'static str { + if !enforce { + "not-enforced" + } else if self.candidate() { + "repo" + } else { + "site-packages" + } + } +} + +#[derive(Serialize)] +struct BenchmarkReport { + schema_version: &'static str, + report_kind: &'static str, + run_id: String, + phase: &'static str, + timestamp_utc: String, + report_date: String, + schema_path: String, + repo: RepoProvenance, + environment: EnvironmentProvenance, + python: Option, + package_state: PackageState, + gate_checks: Vec, + benchmarks: Vec, +} + +#[derive(Serialize)] +struct RepoProvenance { + root: String, + branch: String, + commit: String, + tracked_dirty: bool, +} + +#[derive(Serialize)] +struct EnvironmentProvenance { + os: String, + rocm_path: Option, + hipcc_version: Option, + env: BTreeMap>, +} + +#[derive(Serialize)] +struct PackageState { + target_import_policy: &'static str, + graph_enabled: bool, + allow_package_changes: bool, + package_actions: Vec, +} + +#[derive(Serialize)] +struct CommandRecord { + name: String, + command: String, + status: &'static str, + duration_ms: f64, + exit_code: Option, + stdout_tail: String, + stderr_tail: String, +} + +#[derive(Serialize)] +struct GateCheck { + name: String, + status: &'static str, + message: String, + details: Value, +} + +#[derive(Serialize)] +struct BenchmarkRecord { + name: String, + kind: String, + status: &'static str, + command: String, + iterations: Option, + duration_ms: Option, + throughput_ops_per_sec: Option, + stdout_tail: String, + stderr_tail: String, + metrics: BTreeMap, +} + +fn main() { + if let Err(error) = run() { + eprintln!("gfxgraph-bench-gate: {error}"); + std::process::exit(2); + } +} + +fn run() -> Result<(), Box> { + let cli = Cli::parse(); + let repo_root = cli + .repo_root + .clone() + .unwrap_or_else(|| PathBuf::from(".")) + .canonicalize()?; + let python_candidate = cli + .python + .clone() + .unwrap_or_else(|| default_python(&repo_root)); + let python = absolute_path(&repo_root, python_candidate); + let output_root = cli + .output_root + .clone() + .unwrap_or_else(|| repo_root.join("benchmarks/results")); + let clock = UtcClock::read(); + let run_id = cli.run_id.clone().unwrap_or_else(|| { + clock + .timestamp_utc + .replace(['-', ':'], "") + .replace('Z', "Z") + }); + let phases = resolve_phases(&cli); + let output_dir = output_root.join(&clock.report_date); + fs::create_dir_all(&output_dir)?; + + let mut any_failed = false; + for phase in phases { + let report = run_phase(&cli, &repo_root, &python, phase, &clock, &run_id)?; + validate_report(&report)?; + let report_path = + output_dir.join(format!("{SCHEMA_VERSION}-{}-{run_id}.json", phase.as_str())); + let json = serde_json::to_string_pretty(&report)?; + fs::write(&report_path, format!("{json}\n"))?; + println!("wrote {}", report_path.display()); + + any_failed |= report + .gate_checks + .iter() + .any(|check| check.status == "failed"); + any_failed |= report + .benchmarks + .iter() + .any(|benchmark| benchmark.status == "failed"); + } + + if any_failed { + std::process::exit(1); + } + Ok(()) +} + +fn resolve_phases(cli: &Cli) -> Vec { + if !cli.phases.is_empty() { + return cli.phases.clone(); + } + if cli.matrix { + return vec![ + Phase::InstalledBaseline, + Phase::InstalledGraphEnabled, + Phase::CleanCandidate, + Phase::GraphCandidate, + ]; + } + vec![Phase::InstalledBaseline, Phase::InstalledGraphEnabled] +} + +fn run_phase( + cli: &Cli, + repo_root: &Path, + python: &Path, + phase: Phase, + clock: &UtcClock, + run_id: &str, +) -> Result> { + let enforce_import_isolation = !cli.no_enforce_import_isolation; + let candidate_transition_allowed = !phase.candidate() || cli.allow_package_changes; + let effective_import_enforcement = enforce_import_isolation && candidate_transition_allowed; + let mut package_actions = Vec::new(); + let mut gate_checks = Vec::new(); + let mut benchmarks = Vec::new(); + let phase_env = phase_env(phase); + + let mut python_probe = None; + + if cli.native_only { + gate_checks.push(GateCheck { + name: "native-runtime-only".to_string(), + status: "passed", + message: "native-only gate skips Python package transition and import provenance" + .to_string(), + details: json!({ + "phase": phase.as_str(), + "python": Value::Null, + }), + }); + } else if phase.candidate() && !cli.allow_package_changes { + gate_checks.push(GateCheck { + name: "candidate-package-transition".to_string(), + status: "skipped", + message: "candidate phase requires --allow-package-changes before UV uninstall/install" + .to_string(), + details: json!({ + "phase": phase.as_str(), + "python": python.display().to_string() + }), + }); + benchmarks.push(skipped_benchmark( + "phase-benchmarks", + "phase-control", + "candidate package transition was not allowed", + )); + } else if phase.candidate() { + package_actions.extend(prepare_candidate_packages(repo_root, python)); + gate_checks.push(check_candidate_package_actions(&package_actions)); + } + + if cli.native_only { + benchmarks.push(skipped_benchmark( + "python-import-provenance", + "package-provenance", + "skipped by --native-only", + )); + } else { + let (probe, python_command) = collect_python_provenance(python, repo_root, &phase_env); + python_probe = probe; + benchmarks.push(command_as_benchmark( + "python-import-provenance", + "package-provenance", + python_command, + )); + gate_checks.push(check_python_import_policy( + phase, + repo_root, + python_probe.as_ref(), + effective_import_enforcement, + )); + } + + if !phase.candidate() || cli.allow_package_changes || cli.native_only { + if cli.native_only { + benchmarks.push(skipped_benchmark( + "torch-capture-policy", + "capture-policy", + "skipped by --native-only", + )); + } else { + benchmarks.push(run_capture_policy_probe(repo_root, python, &phase_env)); + } + benchmarks.push(bench_rust_router(cli.rust_iterations)); + benchmarks.push(bench_rust_stats(cli.rust_iterations)); + + if cli.skip_hip { + benchmarks.push(skipped_benchmark( + "native-hip-benchmark", + "hip-native", + "skipped by --skip-hip", + )); + benchmarks.push(skipped_benchmark( + "native-hip-tests", + "hip-native", + "skipped by --skip-hip", + )); + } else { + benchmarks.push(run_native_runtime_cli(repo_root)); + benchmarks.push(run_native_runtime_ffi(repo_root)); + benchmarks.push(run_hip_benchmark(repo_root)); + benchmarks.push(run_ctest(repo_root)); + } + + if cli.native_only { + benchmarks.push(skipped_benchmark( + "readme-public-benchmark", + "python-public", + "skipped by --native-only", + )); + } else if cli.skip_public { + benchmarks.push(skipped_benchmark( + "readme-public-benchmark", + "python-public", + "skipped by --skip-public", + )); + } else { + let public_record = run_python_script( + "readme-public-benchmark", + "python-public", + repo_root, + python, + "benchmarks/bench_readme_public.py", + &[ + "--output".to_string(), + format!( + "benchmarks/results/{}/readme-public-{}-{run_id}.json", + clock.report_date, + phase.as_str() + ), + "--run-count".to_string(), + cli.public_run_count.to_string(), + ], + &phase_env, + ); + benchmarks.push(public_benchmark_record(public_record)); + } + + if cli.native_only { + benchmarks.push(skipped_benchmark( + "legacy-python-microbenchmarks", + "python-micro", + "skipped by --native-only", + )); + } else if cli.skip_python_micro || !cli.include_python_micro { + benchmarks.push(skipped_benchmark( + "legacy-python-microbenchmarks", + "python-micro", + "skipped; pass --include-python-micro to run legacy Python microbenchmarks", + )); + } else { + for script in [ + "benchmarks/bench_routing.py", + "benchmarks/bench_routing_rust.py", + "benchmarks/bench_stats.py", + "benchmarks/bench_stats_rust.py", + ] { + benchmarks.push(run_python_script( + script, + "python-micro", + repo_root, + python, + script, + &[], + &phase_env, + )); + } + } + } + + Ok(BenchmarkReport { + schema_version: SCHEMA_VERSION, + report_kind: REPORT_KIND, + run_id: run_id.to_string(), + phase: phase.as_str(), + timestamp_utc: clock.timestamp_utc.clone(), + report_date: clock.report_date.clone(), + schema_path: SCHEMA_RELATIVE_PATH.to_string(), + repo: repo_provenance(repo_root), + environment: environment_provenance(), + python: python_probe, + package_state: PackageState { + target_import_policy: if cli.native_only { + "native-only" + } else { + phase.target_import_policy(effective_import_enforcement) + }, + graph_enabled: phase.graph_enabled(), + allow_package_changes: cli.allow_package_changes, + package_actions, + }, + gate_checks, + benchmarks, + }) +} + +fn prepare_candidate_packages(repo_root: &Path, python: &Path) -> Vec { + let python = python.display().to_string(); + let repo = repo_root.display().to_string(); + let native = repo_root.join("native").display().to_string(); + let rs_gfxgraph_dir = repo_root.join("rust/rs_gfxgraph"); + let rs_gfxgraph_stats_dir = repo_root.join("rust/rs_gfxgraph_stats"); + let maturin_env = maturin_env(Path::new(&python)); + + vec![ + run_command( + "uv-uninstall-installed-python-packages", + "uv", + &[ + "pip".to_string(), + "uninstall".to_string(), + "--python".to_string(), + python.clone(), + "gfxgraph".to_string(), + "gfxgraph-native".to_string(), + "rs-gfxgraph".to_string(), + "rs-gfxgraph-stats".to_string(), + ], + Some(repo_root), + &[], + ), + run_command( + "uv-install-candidate-gfxgraph", + "uv", + &[ + "pip".to_string(), + "install".to_string(), + "--python".to_string(), + python.clone(), + "--no-deps".to_string(), + "-e".to_string(), + repo, + ], + Some(repo_root), + &[], + ), + run_command( + "uv-install-candidate-gfxgraph-native", + "uv", + &[ + "pip".to_string(), + "install".to_string(), + "--python".to_string(), + python, + "--no-deps".to_string(), + "-e".to_string(), + native, + ], + Some(repo_root), + &[], + ), + run_command( + "maturin-develop-rs-gfxgraph-uv", + "maturin", + &[ + "develop".to_string(), + "--uv".to_string(), + "--release".to_string(), + ], + Some(&rs_gfxgraph_dir), + &maturin_env, + ), + run_command( + "maturin-develop-rs-gfxgraph-stats-uv", + "maturin", + &[ + "develop".to_string(), + "--uv".to_string(), + "--release".to_string(), + ], + Some(&rs_gfxgraph_stats_dir), + &maturin_env, + ), + ] +} + +fn check_candidate_package_actions(package_actions: &[CommandRecord]) -> GateCheck { + let failed: Vec<_> = package_actions + .iter() + .filter(|action| action.status == "failed") + .map(|action| action.name.as_str()) + .collect(); + let actions: Vec<_> = package_actions + .iter() + .map(|action| { + json!({ + "name": action.name, + "status": action.status, + "exit_code": action.exit_code + }) + }) + .collect(); + + if failed.is_empty() { + GateCheck { + name: "candidate-package-transition".to_string(), + status: "passed", + message: "UV package uninstall/install transition completed".to_string(), + details: json!({ "actions": actions }), + } + } else { + GateCheck { + name: "candidate-package-transition".to_string(), + status: "failed", + message: format!("UV package transition failed: {}", failed.join(", ")), + details: json!({ "actions": actions, "failed": failed }), + } + } +} + +fn collect_python_provenance( + python: &Path, + repo_root: &Path, + envs: &[(String, String)], +) -> (Option, CommandRecord) { + let script = r#" +import importlib.metadata as md +import importlib.util +import json +import sys + +metadata_names = { + "gfxgraph": "gfxgraph", + "hipgraph_bridge": "gfxgraph", + "gfxgraph_native": "gfxgraph-native", + "rs_gfxgraph": "rs-gfxgraph", + "rs_gfxgraph_stats": "rs-gfxgraph-stats", +} + +payload = { + "executable": sys.executable, + "version": sys.version, + "prefix": sys.prefix, + "imports": [], +} + +for module, distribution in metadata_names.items(): + item = {"name": module, "distribution": distribution} + try: + spec = importlib.util.find_spec(module) + item["origin"] = None if spec is None else spec.origin + locations = None if spec is None else spec.submodule_search_locations + item["search_locations"] = None if locations is None else list(locations) + item["importable"] = spec is not None + except Exception as exc: + item["importable"] = False + item["origin_error"] = repr(exc) + try: + item["version"] = md.version(distribution) + dist = md.distribution(distribution) + item["distribution_location"] = str(dist.locate_file("")) + direct_url = dist.read_text("direct_url.json") + if direct_url: + item["direct_url"] = json.loads(direct_url) + except Exception as exc: + item["version_error"] = repr(exc) + payload["imports"].append(item) + +print(json.dumps(payload, sort_keys=True)) +"#; + let python_display = python.display().to_string(); + let args = vec!["-c".to_string(), script.to_string()]; + let command_display = + display_command(&python_display, &["-c".to_string(), "".to_string()]); + let start = Instant::now(); + let mut command = Command::new(python); + command + .args(&args) + .current_dir(std::env::temp_dir()) + .env_remove("PYTHONPATH") + .env("GFXGRAPH_REPO_ROOT", repo_root); + for (key, value) in envs { + command.env(key, value); + } + + let record = match command.output() { + Ok(output) => { + let status = if output.status.success() { + "passed" + } else { + "failed" + }; + CommandRecord { + name: "python-import-provenance".to_string(), + command: command_display, + status, + duration_ms: elapsed_ms(start.elapsed()), + exit_code: output.status.code(), + stdout_tail: tail_text(&String::from_utf8_lossy(&output.stdout), 16_384), + stderr_tail: tail_text(&String::from_utf8_lossy(&output.stderr), 16_384), + } + } + Err(error) => CommandRecord { + name: "python-import-provenance".to_string(), + command: command_display, + status: "failed", + duration_ms: elapsed_ms(start.elapsed()), + exit_code: None, + stdout_tail: String::new(), + stderr_tail: error.to_string(), + }, + }; + + let parsed = if record.status == "passed" { + serde_json::from_str(record.stdout_tail.trim()).ok() + } else { + None + }; + (parsed, record) +} + +fn run_capture_policy_probe( + repo_root: &Path, + python: &Path, + envs: &[(String, String)], +) -> BenchmarkRecord { + let script = r#" +import json +import os +import torch +from hipgraph_bridge.capture_safety import ( + torch_cuda_execution_error, + torch_cuda_execution_usable, + torch_graph_capture_block_reason, + unsafe_torch_graph_capture_enabled, +) + +print(json.dumps({ + "torch": torch.__version__, + "torch_hip": getattr(torch.version, "hip", None), + "device": torch.cuda.get_device_name(0) if torch.cuda.is_available() else None, + "cuda_available": torch.cuda.is_available(), + "cuda_execution_usable": torch_cuda_execution_usable(), + "cuda_execution_error": torch_cuda_execution_error(), + "unsafe_torch_graph_capture_enabled": unsafe_torch_graph_capture_enabled(), + "torch_graph_capture_block_reason": torch_graph_capture_block_reason(), + "GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE": os.environ.get("GFXGRAPH_ENABLE_UNSAFE_TORCH_GRAPH_CAPTURE"), +}, sort_keys=True)) +"#; + let python_display = python.display().to_string(); + let command_display = display_command( + &python_display, + &["-c".to_string(), "".to_string()], + ); + let start = Instant::now(); + let mut command = Command::new(python); + command + .arg("-c") + .arg(script) + .current_dir(std::env::temp_dir()) + .env_remove("PYTHONPATH") + .env("GFXGRAPH_REPO_ROOT", repo_root); + for (key, value) in envs { + command.env(key, value); + } + + let record = match command.output() { + Ok(output) => CommandRecord { + name: "torch-capture-policy".to_string(), + command: command_display, + status: if output.status.success() { + "passed" + } else { + "failed" + }, + duration_ms: elapsed_ms(start.elapsed()), + exit_code: output.status.code(), + stdout_tail: tail_text(&String::from_utf8_lossy(&output.stdout), 16_384), + stderr_tail: tail_text(&String::from_utf8_lossy(&output.stderr), 16_384), + }, + Err(error) => CommandRecord { + name: "torch-capture-policy".to_string(), + command: command_display, + status: "failed", + duration_ms: elapsed_ms(start.elapsed()), + exit_code: None, + stdout_tail: String::new(), + stderr_tail: error.to_string(), + }, + }; + + let mut benchmark = command_as_benchmark("torch-capture-policy", "capture-policy", record); + if let Ok(payload) = serde_json::from_str::(benchmark.stdout_tail.trim()) { + benchmark.metrics.insert("probe".to_string(), payload); + } + benchmark +} + +fn check_python_import_policy( + phase: Phase, + repo_root: &Path, + python: Option<&Value>, + enforce: bool, +) -> GateCheck { + if !enforce { + return GateCheck { + name: "python-import-isolation".to_string(), + status: "skipped", + message: "import isolation enforcement disabled by --no-enforce-import-isolation" + .to_string(), + details: json!({ "phase": phase.as_str() }), + }; + } + + let Some(python) = python else { + return GateCheck { + name: "python-import-isolation".to_string(), + status: "failed", + message: "python import provenance probe did not produce JSON".to_string(), + details: json!({ "phase": phase.as_str() }), + }; + }; + + let required_modules = ["gfxgraph", "hipgraph_bridge", "gfxgraph_native"]; + let mut failures = Vec::new(); + let mut checked = Vec::new(); + let imports = python + .get("imports") + .and_then(Value::as_array) + .cloned() + .unwrap_or_default(); + + for module in required_modules { + let import = imports.iter().find(|entry| { + entry + .get("name") + .and_then(Value::as_str) + .is_some_and(|name| name == module) + }); + let Some(import) = import else { + failures.push(format!("{module}: missing from provenance")); + continue; + }; + + let importable = import + .get("importable") + .and_then(Value::as_bool) + .unwrap_or(false); + let origin = import.get("origin").and_then(Value::as_str).unwrap_or(""); + let in_repo = path_string_is_repo_source(origin, repo_root); + checked.push(json!({ + "module": module, + "origin": origin, + "in_repo": in_repo, + "importable": importable + })); + + if !importable { + failures.push(format!("{module}: not importable")); + } else if phase.candidate() && !in_repo { + failures.push(format!("{module}: expected repo import, got {origin}")); + } else if !phase.candidate() && in_repo { + failures.push(format!( + "{module}: expected site-packages import, got {origin}" + )); + } + } + + if failures.is_empty() { + GateCheck { + name: "python-import-isolation".to_string(), + status: "passed", + message: format!( + "{} imports match {} policy", + phase.as_str(), + phase.target_import_policy(true) + ), + details: json!({ "checked": checked }), + } + } else { + GateCheck { + name: "python-import-isolation".to_string(), + status: "failed", + message: failures.join("; "), + details: json!({ "checked": checked, "failures": failures }), + } + } +} + +fn bench_rust_router(iterations: u64) -> BenchmarkRecord { + let mut router = BucketRouterCore::new(vec![1, 2, 4, 8, 16, 32, 64, 128, 256, 512]); + for bucket in [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] { + router.mark_warmed_up(bucket); + } + + let start = Instant::now(); + let mut ready_count = 0_u64; + for i in 0..iterations { + let input = ((i as usize) % 512) + 1; + let (_, state) = router + .route(input) + .expect("router input should fit buckets"); + if matches!(state, rs_gfxgraph_core::BucketState::Ready) { + ready_count += 1; + } + } + black_box(ready_count); + let duration = start.elapsed(); + + let mut metrics = BTreeMap::new(); + metrics.insert("ready_routes".to_string(), json!(ready_count)); + metrics.insert("bucket_count".to_string(), json!(router.buckets().len())); + BenchmarkRecord { + name: "rust-bucket-router-core".to_string(), + kind: "rust-micro".to_string(), + status: "passed", + command: "in-process BucketRouterCore::route loop".to_string(), + iterations: Some(iterations), + duration_ms: Some(elapsed_ms(duration)), + throughput_ops_per_sec: Some(throughput(iterations, duration)), + stdout_tail: String::new(), + stderr_tail: String::new(), + metrics, + } +} + +fn bench_rust_stats(iterations: u64) -> BenchmarkRecord { + let start = Instant::now(); + let mut sample = GfxGraphStatsSample::default(); + for i in 0..iterations { + sample.samples += 1; + if i % 1024 == 0 { + sample.failures += 1; + } + } + black_box(&sample); + let duration = start.elapsed(); + + let mut metrics = BTreeMap::new(); + metrics.insert("samples".to_string(), json!(sample.samples)); + metrics.insert("failures".to_string(), json!(sample.failures)); + BenchmarkRecord { + name: "rust-stats-sample-update".to_string(), + kind: "rust-micro".to_string(), + status: "passed", + command: "in-process GfxGraphStatsSample update loop".to_string(), + iterations: Some(iterations), + duration_ms: Some(elapsed_ms(duration)), + throughput_ops_per_sec: Some(throughput(iterations, duration)), + stdout_tail: String::new(), + stderr_tail: String::new(), + metrics, + } +} + +fn run_native_runtime_ffi(repo_root: &Path) -> BenchmarkRecord { + let candidates = default_library_candidates(repo_root); + if !candidates.iter().any(|candidate| candidate.exists()) { + let mut benchmark = skipped_benchmark( + "rust-native-runtime-ffi", + "rust-native", + "libhipgraph_bridge.so does not exist; build with CMake first", + ); + benchmark + .metrics + .insert("candidates".to_string(), json!(path_strings(&candidates))); + return benchmark; + } + + let start = Instant::now(); + match NativeBridge::open_default(repo_root) { + Ok(bridge) => { + let init_result = bridge.init(); + let version = bridge.version(); + let initialized = bridge.is_initialized(); + bridge.profiler_reset(); + let seq = bridge.profiler_record(ProfileEventKind::Unknown, 1, 2, 3); + let (samples, counters) = bridge.profiler_snapshot(8); + bridge.shutdown(); + + let status = if init_result.is_ok() && initialized && !samples.is_empty() { + "passed" + } else { + "failed" + }; + let mut metrics = BTreeMap::new(); + metrics.insert( + "library_path".to_string(), + json!(bridge.library_path().display().to_string()), + ); + metrics.insert( + "version".to_string(), + json!({ + "major": version.major, + "minor": version.minor, + "patch": version.patch, + "gfx_target": version.gfx_target, + "rocm_version": version.rocm_version, + }), + ); + metrics.insert( + "init_error".to_string(), + json!(init_result.err().map(|error| error.to_string())), + ); + metrics.insert("initialized".to_string(), json!(initialized)); + metrics.insert("recorded_seq".to_string(), json!(seq)); + metrics.insert("sample_count".to_string(), json!(samples.len())); + metrics.insert( + "profiler_counters".to_string(), + json!({ + "written": counters.written, + "dropped": counters.dropped, + "capacity": counters.capacity, + }), + ); + BenchmarkRecord { + name: "rust-native-runtime-ffi".to_string(), + kind: "rust-native".to_string(), + status, + command: format!("NativeBridge::open_default({})", repo_root.display()), + iterations: None, + duration_ms: Some(elapsed_ms(start.elapsed())), + throughput_ops_per_sec: None, + stdout_tail: String::new(), + stderr_tail: String::new(), + metrics, + } + } + Err(error) => BenchmarkRecord { + name: "rust-native-runtime-ffi".to_string(), + kind: "rust-native".to_string(), + status: "failed", + command: format!("NativeBridge::open_default({})", repo_root.display()), + iterations: None, + duration_ms: Some(elapsed_ms(start.elapsed())), + throughput_ops_per_sec: None, + stdout_tail: String::new(), + stderr_tail: error.to_string(), + metrics: BTreeMap::from([("candidates".to_string(), json!(path_strings(&candidates)))]), + }, + } +} + +fn run_native_runtime_cli(repo_root: &Path) -> BenchmarkRecord { + let probe_args = vec![ + "--repo-root".to_string(), + repo_root.display().to_string(), + "--event-count".to_string(), + "3".to_string(), + "--sample-count".to_string(), + "8".to_string(), + ]; + let release_probe = repo_root.join("target/release/gfxgraph-native-probe"); + let debug_probe = repo_root.join("target/debug/gfxgraph-native-probe"); + let record = if release_probe.exists() { + run_command( + "rust-native-runtime-cli", + &release_probe.display().to_string(), + &probe_args, + Some(repo_root), + &[], + ) + } else if debug_probe.exists() { + run_command( + "rust-native-runtime-cli", + &debug_probe.display().to_string(), + &probe_args, + Some(repo_root), + &[], + ) + } else { + let mut cargo_args = vec![ + "run".to_string(), + "--quiet".to_string(), + "-p".to_string(), + "rs_gfxgraph_native".to_string(), + "--bin".to_string(), + "gfxgraph-native-probe".to_string(), + "--".to_string(), + ]; + cargo_args.extend(probe_args); + run_command( + "rust-native-runtime-cli", + "cargo", + &cargo_args, + Some(repo_root), + &[], + ) + }; + let mut benchmark = command_as_benchmark("rust-native-runtime-cli", "rust-native", record); + if let Ok(payload) = serde_json::from_str::(benchmark.stdout_tail.trim()) { + benchmark + .metrics + .insert("payload".to_string(), payload.clone()); + for key in [ + "python_used", + "init_ok", + "initialized", + "library_path", + "native_contracts", + "event_count", + "snapshot_sample_count", + "profiler_counters", + "version", + ] { + if let Some(value) = payload.get(key) { + benchmark.metrics.insert(key.to_string(), value.clone()); + } + } + } + benchmark +} + +fn run_hip_benchmark(repo_root: &Path) -> BenchmarkRecord { + let executable = repo_root.join("build/benchmark_pipeline"); + if !executable.exists() { + return skipped_benchmark( + "native-hip-benchmark", + "hip-native", + "build/benchmark_pipeline does not exist; build with CMake BUILD_BENCHMARKS=ON", + ); + } + let record = run_command( + "native-hip-benchmark", + &executable.display().to_string(), + &[], + Some(repo_root), + &[], + ); + let mut benchmark = command_as_benchmark("native-hip-benchmark", "hip-native", record); + parse_native_pipeline_metrics(&mut benchmark); + benchmark +} + +fn path_strings(paths: &[PathBuf]) -> Vec { + paths + .iter() + .map(|path| path.display().to_string()) + .collect() +} + +fn run_ctest(repo_root: &Path) -> BenchmarkRecord { + let build_dir = repo_root.join("build"); + if !build_dir.exists() { + return skipped_benchmark( + "native-hip-tests", + "hip-native", + "build directory does not exist; configure CMake native tests first", + ); + } + let record = run_command( + "native-hip-tests", + "ctest", + &[ + "--test-dir".to_string(), + build_dir.display().to_string(), + "--output-on-failure".to_string(), + ], + Some(repo_root), + &[], + ); + command_as_benchmark("native-hip-tests", "hip-native", record) +} + +fn run_python_script( + name: &str, + kind: &str, + repo_root: &Path, + python: &Path, + script: &str, + script_args: &[String], + envs: &[(String, String)], +) -> BenchmarkRecord { + let script_path = repo_root.join(script); + if !script_path.exists() { + return skipped_benchmark(name, kind, "script does not exist"); + } + let mut args = Vec::with_capacity(script_args.len() + 1); + args.push(script.to_string()); + args.extend(script_args.iter().cloned()); + let record = run_command( + name, + &python.display().to_string(), + &args, + Some(repo_root), + envs, + ); + command_as_benchmark(name, kind, record) +} + +fn run_command( + name: &str, + program: &str, + args: &[String], + cwd: Option<&Path>, + envs: &[(String, String)], +) -> CommandRecord { + let command_display = display_command(program, args); + let start = Instant::now(); + let mut command = Command::new(program); + command.args(args); + if let Some(cwd) = cwd { + command.current_dir(cwd); + } + for (key, value) in envs { + command.env(key, value); + } + + match command.output() { + Ok(output) => CommandRecord { + name: name.to_string(), + command: command_display, + status: if output.status.success() { + "passed" + } else { + "failed" + }, + duration_ms: elapsed_ms(start.elapsed()), + exit_code: output.status.code(), + stdout_tail: tail_text(&String::from_utf8_lossy(&output.stdout), 16_384), + stderr_tail: tail_text(&String::from_utf8_lossy(&output.stderr), 16_384), + }, + Err(error) => CommandRecord { + name: name.to_string(), + command: command_display, + status: "failed", + duration_ms: elapsed_ms(start.elapsed()), + exit_code: None, + stdout_tail: String::new(), + stderr_tail: error.to_string(), + }, + } +} + +fn command_as_benchmark(name: &str, kind: &str, command: CommandRecord) -> BenchmarkRecord { + BenchmarkRecord { + name: name.to_string(), + kind: kind.to_string(), + status: command.status, + command: command.command, + iterations: None, + duration_ms: Some(command.duration_ms), + throughput_ops_per_sec: None, + stdout_tail: command.stdout_tail, + stderr_tail: command.stderr_tail, + metrics: BTreeMap::new(), + } +} + +fn public_benchmark_record(mut benchmark: BenchmarkRecord) -> BenchmarkRecord { + if benchmark.status != "passed" { + return benchmark; + } + let Ok(payload) = serde_json::from_str::(benchmark.stdout_tail.trim()) else { + benchmark.metrics.insert( + "parse_warning".to_string(), + json!("stdout was not parseable readme benchmark JSON"), + ); + return benchmark; + }; + + let results = payload + .get("results") + .and_then(Value::as_array) + .cloned() + .unwrap_or_default(); + let fallback_workloads: Vec = results + .iter() + .filter(|entry| { + entry + .get("fallback") + .and_then(Value::as_bool) + .unwrap_or(false) + }) + .map(|entry| { + json!({ + "workload": entry.get("workload").and_then(Value::as_str).unwrap_or("unknown"), + "speedup_x": entry.get("speedup_x").cloned().unwrap_or(Value::Null), + "eager_ms_per_iter": entry.get("eager_ms_per_iter").cloned().unwrap_or(Value::Null), + "graph_ms_per_iter": entry.get("graph_ms_per_iter").cloned().unwrap_or(Value::Null) + }) + }) + .collect(); + + benchmark.metrics.insert( + "fallback_workload_count".to_string(), + json!(fallback_workloads.len()), + ); + benchmark + .metrics + .insert("workload_count".to_string(), json!(results.len())); + benchmark.metrics.insert( + "all_workloads_fallback".to_string(), + json!(!results.is_empty() && fallback_workloads.len() == results.len()), + ); + benchmark + .metrics + .insert("fallback_workloads".to_string(), json!(fallback_workloads)); + benchmark.metrics.insert("payload".to_string(), payload); + benchmark +} + +fn parse_native_pipeline_metrics(benchmark: &mut BenchmarkRecord) { + if benchmark.status != "passed" { + return; + } + + for line in benchmark.stdout_tail.lines() { + if let Some(value) = line.strip_prefix("Warmup launches: ") { + if let Ok(parsed) = value.trim().parse::() { + benchmark + .metrics + .insert("warmup_launches".to_string(), json!(parsed)); + } + } else if let Some(value) = line.strip_prefix("Measured launches: ") { + if let Ok(parsed) = value.trim().parse::() { + benchmark.iterations = Some(parsed); + benchmark + .metrics + .insert("measured_launches".to_string(), json!(parsed)); + } + } else if let Some(value) = line.strip_prefix("Average pipeline launch latency: ") { + let trimmed = value.trim().trim_end_matches(" us").trim(); + if let Ok(parsed) = trimmed.parse::() { + benchmark.metrics.insert( + "average_pipeline_launch_latency_us".to_string(), + json!(parsed), + ); + } + } else if let Some(value) = line.strip_prefix("Device clock64 probe cycles: ") { + if let Ok(parsed) = value.trim().parse::() { + benchmark + .metrics + .insert("device_clock64_probe_cycles".to_string(), json!(parsed)); + } + } else if let Some(value) = line.strip_prefix("Profiler samples copied: ") { + if let Ok(parsed) = value.trim().parse::() { + benchmark + .metrics + .insert("profiler_samples_copied".to_string(), json!(parsed)); + } + } else if let Some(value) = line.strip_prefix("Profiler events written: ") { + if let Ok(parsed) = value.trim().parse::() { + benchmark + .metrics + .insert("profiler_events_written".to_string(), json!(parsed)); + } + } else if let Some(value) = line.strip_prefix("Profiler events dropped: ") { + if let Ok(parsed) = value.trim().parse::() { + benchmark + .metrics + .insert("profiler_events_dropped".to_string(), json!(parsed)); + } + } + } +} + +fn skipped_benchmark(name: &str, kind: &str, reason: &str) -> BenchmarkRecord { + let mut metrics = BTreeMap::new(); + metrics.insert("skip_reason".to_string(), json!(reason)); + BenchmarkRecord { + name: name.to_string(), + kind: kind.to_string(), + status: "skipped", + command: String::new(), + iterations: None, + duration_ms: None, + throughput_ops_per_sec: None, + stdout_tail: String::new(), + stderr_tail: String::new(), + metrics, + } +} + +fn validate_report(report: &BenchmarkReport) -> Result<(), Box> { + if report.schema_version != SCHEMA_VERSION { + return Err("schema_version mismatch".into()); + } + if report.report_kind != REPORT_KIND { + return Err("report_kind mismatch".into()); + } + if report.run_id.trim().is_empty() { + return Err("run_id is empty".into()); + } + if report.timestamp_utc.trim().is_empty() { + return Err("timestamp_utc is empty".into()); + } + if report.report_date.len() != 10 { + return Err("report_date must use YYYY-MM-DD".into()); + } + if report.gate_checks.is_empty() { + return Err("gate_checks must not be empty".into()); + } + if report.benchmarks.is_empty() { + return Err("benchmarks must not be empty".into()); + } + for check in &report.gate_checks { + validate_status(check.status)?; + } + for benchmark in &report.benchmarks { + validate_status(benchmark.status)?; + } + Ok(()) +} + +fn validate_status(status: &str) -> Result<(), Box> { + match status { + "passed" | "failed" | "skipped" => Ok(()), + _ => Err(format!("invalid status: {status}").into()), + } +} + +fn repo_provenance(repo_root: &Path) -> RepoProvenance { + let branch = command_stdout( + "git", + &[ + "-C".to_string(), + repo_root.display().to_string(), + "branch".to_string(), + "--show-current".to_string(), + ], + ) + .unwrap_or_else(|| "unknown".to_string()); + let commit = command_stdout( + "git", + &[ + "-C".to_string(), + repo_root.display().to_string(), + "rev-parse".to_string(), + "HEAD".to_string(), + ], + ) + .unwrap_or_else(|| "unknown".to_string()); + let tracked_status = command_stdout( + "git", + &[ + "-C".to_string(), + repo_root.display().to_string(), + "status".to_string(), + "--short".to_string(), + "--untracked-files=no".to_string(), + ], + ) + .unwrap_or_default(); + + RepoProvenance { + root: repo_root.display().to_string(), + branch, + commit, + tracked_dirty: !tracked_status.trim().is_empty(), + } +} + +fn environment_provenance() -> EnvironmentProvenance { + let mut env = BTreeMap::new(); + for key in [ + "GFXGRAPH", + "GFXGRAPH_VALIDATE", + "GFXGRAPH_VRAM_CAP", + "HIP_VISIBLE_DEVICES", + "HSA_OVERRIDE_GFX_VERSION", + "ROCM_PATH", + ] { + env.insert(key.to_string(), std::env::var(key).ok()); + } + + EnvironmentProvenance { + os: command_stdout("uname", &["-a".to_string()]).unwrap_or_else(|| "unknown".to_string()), + rocm_path: std::env::var("ROCM_PATH").ok(), + hipcc_version: command_stdout("hipcc", &["--version".to_string()]), + env, + } +} + +fn command_stdout(program: &str, args: &[String]) -> Option { + Command::new(program) + .args(args) + .output() + .ok() + .filter(|output| output.status.success()) + .map(|output| String::from_utf8_lossy(&output.stdout).trim().to_string()) +} + +fn default_python(repo_root: &Path) -> PathBuf { + let local = repo_root.join(".venv/bin/python"); + if local.exists() { + local + } else { + PathBuf::from("python3") + } +} + +fn phase_env(phase: Phase) -> Vec<(String, String)> { + if phase.graph_enabled() { + vec![("GFXGRAPH".to_string(), "1".to_string())] + } else { + Vec::new() + } +} + +fn maturin_env(python: &Path) -> Vec<(String, String)> { + let Some(bin_dir) = python.parent() else { + return Vec::new(); + }; + if bin_dir.file_name().and_then(|name| name.to_str()) != Some("bin") { + return Vec::new(); + } + let Some(venv_root) = bin_dir.parent() else { + return Vec::new(); + }; + + let path = std::env::var("PATH") + .map(|current| format!("{}:{current}", bin_dir.display())) + .unwrap_or_else(|_| bin_dir.display().to_string()); + vec![ + ("VIRTUAL_ENV".to_string(), venv_root.display().to_string()), + ("PATH".to_string(), path), + ] +} + +fn path_string_is_repo_source(path: &str, root: &Path) -> bool { + if path.is_empty() { + return false; + } + let candidate = PathBuf::from(path); + if let Ok(candidate) = candidate.canonicalize() { + return candidate.starts_with(root) && !path_is_installed_site_package(&candidate); + } + path.contains(&root.display().to_string()) && !path.contains("/site-packages/") +} + +fn path_is_installed_site_package(path: &Path) -> bool { + path.components().any(|component| { + component + .as_os_str() + .to_str() + .is_some_and(|part| part == "site-packages" || part == "dist-packages") + }) +} + +fn absolute_path(base: &Path, path: PathBuf) -> PathBuf { + if path.is_absolute() { + path + } else { + base.join(path) + } +} + +fn display_command(program: &str, args: &[String]) -> String { + std::iter::once(program.to_string()) + .chain(args.iter().cloned()) + .map(|part| { + if part.contains(char::is_whitespace) { + format!("{part:?}") + } else { + part + } + }) + .collect::>() + .join(" ") +} + +fn tail_text(text: &str, max_chars: usize) -> String { + let char_count = text.chars().count(); + if char_count <= max_chars { + return text.to_string(); + } + text.chars().skip(char_count - max_chars).collect() +} + +fn elapsed_ms(duration: Duration) -> f64 { + duration.as_secs_f64() * 1000.0 +} + +fn throughput(iterations: u64, duration: Duration) -> f64 { + if duration.is_zero() { + return 0.0; + } + iterations as f64 / duration.as_secs_f64() +} + +struct UtcClock { + timestamp_utc: String, + report_date: String, +} + +impl UtcClock { + fn read() -> Self { + let timestamp_utc = command_stdout( + "date", + &["-u".to_string(), "+%Y-%m-%dT%H:%M:%SZ".to_string()], + ) + .unwrap_or_else(|| { + let seconds = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_secs(); + format!("unix-{seconds}") + }); + let report_date = command_stdout("date", &["-u".to_string(), "+%Y-%m-%d".to_string()]) + .unwrap_or_else(|| timestamp_utc.chars().take(10).collect()); + Self { + timestamp_utc, + report_date, + } + } +} diff --git a/rust/rs_gfxgraph_core/Cargo.toml b/rust/rs_gfxgraph_core/Cargo.toml index 8b1e62d..e0a532a 100644 --- a/rust/rs_gfxgraph_core/Cargo.toml +++ b/rust/rs_gfxgraph_core/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" parking_lot = "0.12" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -[dev-dependencies] [features] default = [] diff --git a/rust/rs_gfxgraph_core/README.md b/rust/rs_gfxgraph_core/README.md index f562f5a..1771bc0 100644 --- a/rust/rs_gfxgraph_core/README.md +++ b/rust/rs_gfxgraph_core/README.md @@ -1,10 +1,10 @@ # rs_gfxgraph_core -Pure-Rust shared contracts for the **gfxGRAPH** ecosystem. Defines lightweight, high-performance DTOs, schemas, and enumerations without native bindings or external execution frameworks. +Pure-Rust shared contracts for the **gfxGRAPH** library. Defines lightweight, high-performance DTOs, schemas, and enumerations without native bindings or external execution frameworks. --- -## Architectural Role in the gfxGRAPH Family +## Architectural Role in gfxGRAPH ```text ┌────────────────────────┐ @@ -13,22 +13,13 @@ Pure-Rust shared contracts for the **gfxGRAPH** ecosystem. Defines lightweight, │ ┌───────────┼───────────────┐ ▼ ▼ ▼ -┌──────────────┐ ┌───────────────┐ ┌──────────────────┐ -│rs_gfxgraph │ │rs_gfxgraph │ │rs_gfxgraph_logly │ -│ _pyo3 │ │ _logly │ │ (Deep obs crate) │ -│(PyO3 bindings│ │(Observability)│ └──────────────────┘ -└──────────────┘ └───────────────┘ +┌──────────────┐ ┌───────────────┐ +│gfxgraph_rs │ │gfxgraph_stats │ +│ _pyo3 │ │ _rs │ +│(PyO3 bindings│ │(Observability)│ +└──────────────┘ └───────────────┘ ``` -### Companion Crate Naming Convention - -| Suffix | Role | Example | -|---|---|---| -| `_core` | Pure Rust logic, contracts | `rs_gfxgraph_core` | -| `_pyo3` | Python bindings (PyO3) | `rs_gfxgraph_pyo3` | -| `_logly` | Deep observability (5-level) | `rs_gfxgraph_logly` | -| `_node` | Node.js bindings (napi) | Reserved | - ### Architectural Analysis 1. **`rs_gfxgraph_core` (This Crate — Core Contract Layer)**: @@ -36,14 +27,13 @@ Pure-Rust shared contracts for the **gfxGRAPH** ecosystem. Defines lightweight, - **Role**: Defines the core schema models (`GfxGraphNodeSpec`), telemetry storage contracts (`GfxGraphStatsSample`), and routing enums (`GfxGraphAdapterKind`). A **pure contract layer**. - **Modularity Rationale**: Keeping this crate pure ensures that downstream Rust systems (database interfaces, CLI parsers, metadata pipelines) can serialize, deserialize, and reference these types without compiling heavy FFI or deep-learning runtimes. -2. **`rs_gfxgraph_pyo3` (Native PyO3 Execution Crate)**: +2. **`gfxgraph_rs` (Native PyO3 Execution Crate)**: - **Characteristics**: Coupled tightly to the Python interpreter via `PyO3`. - **Role**: Contains the high-performance conditional graph runner and bucket router for deep-learning inference workloads. - **Why Separate**: Merging with core would destroy the lightweight contract nature, introducing complex PyO3 and native library linkage. -3. **`rs_gfxgraph_logly` (Deep Observability)**: - - **Characteristics**: Self-sufficient 5-level observability with pluggable sinks. - - **Role**: Collects live execution statistics, provides benchmark infrastructure, and integrates with `rs_logly_logger` as a drop-in. +3. **`gfxgraph_stats_rs` (Observability)**: + - **Role**: Collects live execution statistics and provides benchmark infrastructure. - **Why Separate**: Decoupled to keep execution telemetry completely separate from pure schema contracts. --- @@ -52,25 +42,8 @@ Pure-Rust shared contracts for the **gfxGRAPH** ecosystem. Defines lightweight, - **Schema Contracts**: `GfxGraphNodeSpec` — graph node registry specifications. - **Observability Models**: `GfxGraphStatsSample` — bucket performance telemetry. -- **Unified Error Handling**: `GfxGraphError` with conditional `rs_logly_logger` routing. - -## Conditional Error Reporting - -```toml -[dependencies] -rs_gfxgraph_core = { path = "../rs_gfxgraph_core", features = ["logly"] } -``` - -```rust -use rs_gfxgraph_core::error::{GfxGraphError, report_error}; - -let err = GfxGraphError::InvalidNode { - name: "flash_attention_decode".to_string(), - reason: "impl_path does not exist".to_string(), -}; -report_error(&err, "GFX_NODE_VALIDATION"); -``` +- **Unified Error Handling**: `GfxGraphError`. --- -Last Updated: 2026-05-20 +Last Updated: 2026-06-12 diff --git a/rust/rs_gfxgraph_core/src/capture_gate.rs b/rust/rs_gfxgraph_core/src/capture_gate.rs new file mode 100644 index 0000000..6b80873 --- /dev/null +++ b/rust/rs_gfxgraph_core/src/capture_gate.rs @@ -0,0 +1,123 @@ +//! Process-global hipGraph capture serialization gate. +//! +//! On AMD gfx1030 / RDNA2 under ROCm, HIP stream-capture bookkeeping is +//! process-global even with `hipStreamCaptureModeThreadLocal`. Two LLM sessions +//! in one process that capture graphs at the same time corrupt each other's +//! output (NaN). This module provides ONE process-wide reader/writer lock so +//! capture is serialized across every session, while replay stays concurrent: +//! +//! * capture -> write (exclusive): one capture at a time, and excludes any +//! in-flight replay during the brief one-time capture window. +//! * replay -> read (shared): replays run concurrently; blocked only +//! while a capture holds the write lock. +//! +//! The lock is a module-level `static` on purpose: a per-object lock would give +//! each session its own lock and therefore no mutual exclusion -- which is +//! exactly the bug this prevents. +//! +//! The PyO3 layer (`rs_gfxgraph::CaptureLock` / `ReplayLock`) wraps these +//! functions in RAII context managers and releases the GIL while blocking. + +use parking_lot::lock_api::RawRwLock as _; +use parking_lot::RawRwLock; + +/// The single process-wide capture/replay gate. +static CAPTURE_GATE: RawRwLock = RawRwLock::INIT; + +/// Acquire the exclusive capture lock. +/// +/// Blocks until no other capture (writer) and no in-flight replay (reader) +/// holds the gate. Pair exactly once with [`unlock_capture`]. +#[inline] +pub fn lock_capture() { + CAPTURE_GATE.lock_exclusive(); +} + +/// Release the exclusive capture lock. +#[inline] +pub fn unlock_capture() { + // SAFETY: the raw lock has no poisoning; callers (the PyO3 `CaptureLock` + // RAII guard / `acquire_capture_lock`+`release_capture_lock` pair) call this + // exactly once per successful `lock_capture()`. + unsafe { + CAPTURE_GATE.unlock_exclusive(); + } +} + +/// Acquire a shared replay lock. +/// +/// Multiple replays may hold it concurrently; excluded only while a capture +/// holds the write lock. Pair exactly once with [`unlock_replay`]. +#[inline] +pub fn lock_replay() { + CAPTURE_GATE.lock_shared(); +} + +/// Release a shared replay lock. +#[inline] +pub fn unlock_replay() { + // SAFETY: paired exactly once with a prior `lock_replay()` by the PyO3 + // `ReplayLock` RAII guard. + unsafe { + CAPTURE_GATE.unlock_shared(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::sync::{Arc, Barrier}; + use std::thread; + use std::time::Duration; + + #[test] + fn capture_serializes_and_replay_shares() { + // Part 1: the exclusive capture lock admits at most one holder, even + // under contention from many threads. This is the actual corruption + // fix -- concurrent capture must never overlap. + let holders = Arc::new(AtomicUsize::new(0)); + let max_seen = Arc::new(AtomicUsize::new(0)); + let mut handles = Vec::new(); + for _ in 0..8 { + let holders = Arc::clone(&holders); + let max_seen = Arc::clone(&max_seen); + handles.push(thread::spawn(move || { + for _ in 0..50 { + lock_capture(); + let now = holders.fetch_add(1, Ordering::SeqCst) + 1; + max_seen.fetch_max(now, Ordering::SeqCst); + assert_eq!(now, 1, "more than one capture holder at once"); + thread::sleep(Duration::from_micros(20)); + holders.fetch_sub(1, Ordering::SeqCst); + unlock_capture(); + } + })); + } + for h in handles { + h.join().unwrap(); + } + assert_eq!( + max_seen.load(Ordering::SeqCst), + 1, + "capture lock was held by >1 thread simultaneously" + ); + + // Part 2: two replay (shared) holders coexist. If the lock were + // exclusive for readers, the barrier below would deadlock because the + // second thread could never enter while the first holds the lock. + let barrier = Arc::new(Barrier::new(2)); + let mut replay_handles = Vec::new(); + for _ in 0..2 { + let barrier = Arc::clone(&barrier); + replay_handles.push(thread::spawn(move || { + lock_replay(); + barrier.wait(); // both readers must be inside simultaneously + unlock_replay(); + })); + } + for h in replay_handles { + h.join().unwrap(); + } + } +} diff --git a/rust/rs_gfxgraph_core/src/layout.rs b/rust/rs_gfxgraph_core/src/layout.rs index 4a3d057..d4408b8 100644 --- a/rust/rs_gfxgraph_core/src/layout.rs +++ b/rust/rs_gfxgraph_core/src/layout.rs @@ -158,12 +158,45 @@ impl TensorLayout { }) } + /// Checks whether the tensor layout is contiguous in row-major order. + /// + /// This implementation is optimized to be entirely allocation-free (no heap allocation). + /// It validates strides inline, which allows the compiler to fully optimize and unroll + /// the loop, taking advantage of SIMD/AVX instructions on the host CPU. + #[inline] pub fn is_row_contiguous(&self) -> bool { - StrideSpec::row_major(&self.shape) - .map(|expected| expected == self.strides) - .unwrap_or(false) + let rank = self.shape.rank(); + if rank == 0 { + return true; + } + + let dims = self.shape.dims(); + let strides = self.strides.strides(); + if strides.len() != rank { + return false; + } + + // The innermost dimension must have a stride of 1 for row-major contiguity + if strides[rank - 1] != 1 { + return false; + } + + // Validate remaining strides from right to left (innermost to outermost) + // expected_stride[i] = expected_stride[i+1] * shape[i+1] + for i in (0..rank - 1).rev() { + match strides[i + 1].checked_mul(dims[i + 1]) { + Some(expected) => { + if strides[i] != expected { + return false; + } + } + None => return false, + } + } + true } + /// Evaluates the contiguity type of the tensor layout. pub fn contiguity(&self) -> Contiguity { match self.kind { LayoutKind::RowMajor if self.is_row_contiguous() => Contiguity::Contiguous, @@ -175,30 +208,49 @@ impl TensorLayout { } } + /// Computes the linear memory offset for the given multi-dimensional indices. + /// + /// Optimized for compiler auto-vectorization (e.g. AVX2/AVX-512) by performing + /// linear zip-iterations and preventing nested dynamic bounds checks inside the loop. + /// Returns a ShapeError if indices are out of bounds or if multiplication overflows. + #[inline] pub fn linear_offset(&self, indices: &[usize]) -> Result { - if indices.len() != self.shape.rank() { + let rank = self.shape.rank(); + if indices.len() != rank { return Err(ShapeError::AxisOutOfBounds { axis: indices.len(), - rank: self.shape.rank(), + rank, }); } + let dims = self.shape.dims(); + let strides = self.strides.strides(); + let mut offset = 0usize; - for (axis, index) in indices.iter().copied().enumerate() { - let dim = self.shape.dim(axis)?; + for i in 0..rank { + let index = indices[i]; + let dim = dims[i]; if index >= dim { return Err(ShapeError::AxisOutOfBounds { axis: index, rank: dim, }); } + let prod = index + .checked_mul(strides[i]) + .ok_or(ShapeError::ElementCountOverflow)?; offset = offset - .checked_add(index * self.strides.strides()[axis]) + .checked_add(prod) .ok_or(ShapeError::ElementCountOverflow)?; } Ok(offset) } + /// Checks if a tensor copy is required before executing a graph capture. + /// + /// Graph capture on ROCm/HIP requires tensors to be contiguous in memory + /// to prevent incorrect or overlapping buffer re-recordings. + #[inline] pub fn needs_copy_for_graph_capture(&self) -> bool { !self.is_row_contiguous() || matches!(self.kind, LayoutKind::Custom) } diff --git a/rust/rs_gfxgraph_core/src/lib.rs b/rust/rs_gfxgraph_core/src/lib.rs index 7f7e03d..6a68955 100644 --- a/rust/rs_gfxgraph_core/src/lib.rs +++ b/rust/rs_gfxgraph_core/src/lib.rs @@ -2,6 +2,7 @@ pub mod settings; pub use settings::CrateSettings; pub mod adapter; +pub mod capture_gate; pub mod convert; pub mod error; pub mod geometry; @@ -17,6 +18,7 @@ pub mod validator; pub mod wave; pub use adapter::GfxGraphAdapterKind; +pub use capture_gate::{lock_capture, lock_replay, unlock_capture, unlock_replay}; pub use convert::{ DTypeConversionContract, DTypeKind, PageTransform, ShapeLayoutConversionPlan, StrideTransform, }; diff --git a/rust/rs_gfxgraph_native/Cargo.toml b/rust/rs_gfxgraph_native/Cargo.toml new file mode 100644 index 0000000..6a93d03 --- /dev/null +++ b/rust/rs_gfxgraph_native/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "rs_gfxgraph_native" +version = "0.1.0" +edition = "2021" + +[dependencies] +libc = "0.2" +serde_json = "1.0" + +[lib] +name = "rs_gfxgraph_native" +path = "src/lib.rs" + +[[bin]] +name = "gfxgraph-native-probe" +path = "src/bin/gfxgraph-native-probe.rs" + +[lints] +workspace = true diff --git a/rust/rs_gfxgraph_native/src/bin/gfxgraph-native-probe.rs b/rust/rs_gfxgraph_native/src/bin/gfxgraph-native-probe.rs new file mode 100644 index 0000000..4bbbb47 --- /dev/null +++ b/rust/rs_gfxgraph_native/src/bin/gfxgraph-native-probe.rs @@ -0,0 +1,202 @@ +use std::env; +use std::path::PathBuf; +use std::process; +use std::time::Instant; + +use rs_gfxgraph_native::{default_library_candidates, NativeBridge, ProfileEventKind}; +use serde_json::json; + +#[derive(Debug)] +struct Args { + repo_root: PathBuf, + library: Option, + event_count: u64, + sample_count: usize, +} + +fn main() { + let started = Instant::now(); + let args = match parse_args() { + Ok(args) => args, + Err(error) => { + println!( + "{}", + json!({ + "kind": "gfxgraph-native-probe-v1", + "status": "failed", + "error": error, + "python_used": false, + }) + ); + process::exit(2); + } + }; + + let candidates = if let Some(library) = &args.library { + vec![library.clone()] + } else { + default_library_candidates(&args.repo_root) + }; + + let bridge_result = if let Some(library) = &args.library { + NativeBridge::open(library) + } else { + NativeBridge::open_default(&args.repo_root) + }; + + let bridge = match bridge_result { + Ok(bridge) => bridge, + Err(error) => { + println!( + "{}", + json!({ + "kind": "gfxgraph-native-probe-v1", + "status": "failed", + "error": error.to_string(), + "repo_root": args.repo_root, + "candidate_libraries": path_strings(&candidates), + "python_used": false, + "duration_ms": elapsed_ms(started), + }) + ); + process::exit(1); + } + }; + + let init_result = bridge.init(); + let version = bridge.version(); + let initialized = bridge.is_initialized(); + bridge.profiler_reset(); + + let mut sequences = Vec::new(); + if init_result.is_ok() { + for i in 0..args.event_count { + sequences.push(bridge.profiler_record(ProfileEventKind::Unknown, i + 1, i + 2, i + 3)); + } + } + let (samples, counters) = bridge.profiler_snapshot(args.sample_count); + bridge.shutdown(); + + let status = if init_result.is_ok() + && initialized + && samples.len() == args.event_count.min(args.sample_count as u64) as usize + { + "passed" + } else { + "failed" + }; + + println!( + "{}", + json!({ + "kind": "gfxgraph-native-probe-v1", + "status": status, + "repo_root": args.repo_root, + "library_path": bridge.library_path(), + "candidate_libraries": path_strings(&candidates), + "python_used": false, + "native_contracts": [ + "lifecycle", + "profiler", + "pipeline_handles", + "composed_handles" + ], + "version": { + "major": version.major, + "minor": version.minor, + "patch": version.patch, + "gfx_target": version.gfx_target, + "rocm_version": version.rocm_version, + }, + "init_ok": init_result.is_ok(), + "init_error": init_result.err().map(|error| error.to_string()), + "initialized": initialized, + "event_count": args.event_count, + "recorded_sequences": sequences, + "snapshot_sample_count": samples.len(), + "profiler_counters": { + "written": counters.written, + "dropped": counters.dropped, + "capacity": counters.capacity, + }, + "duration_ms": elapsed_ms(started), + }) + ); + + if status != "passed" { + process::exit(1); + } +} + +fn parse_args() -> Result { + let mut repo_root = PathBuf::from("."); + let mut library = None; + let mut event_count = 3_u64; + let mut sample_count = 8_usize; + + let mut iter = env::args().skip(1); + while let Some(arg) = iter.next() { + match arg.as_str() { + "--repo-root" => { + let Some(value) = iter.next() else { + return Err("--repo-root requires a path".to_string()); + }; + repo_root = PathBuf::from(value); + } + "--library" => { + let Some(value) = iter.next() else { + return Err("--library requires a path".to_string()); + }; + library = Some(PathBuf::from(value)); + } + "--event-count" => { + let Some(value) = iter.next() else { + return Err("--event-count requires an integer".to_string()); + }; + event_count = value + .parse() + .map_err(|_| format!("invalid --event-count value: {value}"))?; + } + "--sample-count" => { + let Some(value) = iter.next() else { + return Err("--sample-count requires an integer".to_string()); + }; + sample_count = value + .parse() + .map_err(|_| format!("invalid --sample-count value: {value}"))?; + } + "--help" | "-h" => { + return Err( + "usage: gfxgraph-native-probe [--repo-root PATH] [--library PATH] [--event-count N] [--sample-count N]" + .to_string(), + ); + } + other => return Err(format!("unknown argument: {other}")), + } + } + + if event_count == 0 { + return Err("--event-count must be greater than zero".to_string()); + } + if sample_count == 0 { + return Err("--sample-count must be greater than zero".to_string()); + } + + Ok(Args { + repo_root, + library, + event_count, + sample_count, + }) +} + +fn elapsed_ms(started: Instant) -> f64 { + started.elapsed().as_secs_f64() * 1000.0 +} + +fn path_strings(paths: &[PathBuf]) -> Vec { + paths + .iter() + .map(|path| path.display().to_string()) + .collect() +} diff --git a/rust/rs_gfxgraph_native/src/lib.rs b/rust/rs_gfxgraph_native/src/lib.rs new file mode 100644 index 0000000..2b987e2 --- /dev/null +++ b/rust/rs_gfxgraph_native/src/lib.rs @@ -0,0 +1,644 @@ +//! Rust runtime bindings for the native gfxGRAPH HIP/C++ bridge. +//! +//! This crate intentionally avoids PyO3. It loads `libhipgraph_bridge.so` +//! directly and exposes a small Rust-owned control surface for native runtime +//! health checks, versioning, and telemetry. + +use libc::{c_char, c_int, c_void}; +use std::env; +use std::error::Error; +use std::ffi::{CStr, CString}; +use std::fmt; +use std::path::{Path, PathBuf}; +use std::ptr; + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct HgbVersion { + pub major: c_int, + pub minor: c_int, + pub patch: c_int, + pub gfx_target: *const c_char, + pub rocm_version: *const c_char, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct ProfileSample { + pub seq: u64, + pub timestamp_ns: u64, + pub duration_ns: u64, + pub value0: u64, + pub value1: u64, + pub event: u32, + pub device_id: u32, + pub stream_id: u32, + pub flags: u32, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct ProfileCounters { + pub written: u64, + pub dropped: u64, + pub capacity: u64, +} + +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ProfileEventKind { + Unknown = 0, + PipelineCreate = 1, + PipelineUpload = 2, + PipelineLaunch = 3, + PipelineUpdate = 4, + ComposeLaunch = 5, + ShapeLaunch = 6, + DeviceClockProbe = 7, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct NativeVersion { + pub major: i32, + pub minor: i32, + pub patch: i32, + pub gfx_target: String, + pub rocm_version: String, +} + +#[derive(Debug)] +pub enum NativeLoadError { + Open { path: PathBuf, message: String }, + Symbol { name: &'static str, message: String }, + NoCandidate { candidates: Vec }, + InvalidSymbolName(&'static str), +} + +impl fmt::Display for NativeLoadError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Open { path, message } => { + write!(f, "failed to open {}: {message}", path.display()) + } + Self::Symbol { name, message } => write!(f, "failed to load symbol {name}: {message}"), + Self::NoCandidate { candidates } => { + write!(f, "no native bridge library candidate exists:")?; + for candidate in candidates { + write!(f, " {}", candidate.display())?; + } + Ok(()) + } + Self::InvalidSymbolName(name) => write!(f, "invalid symbol name: {name}"), + } + } +} + +impl Error for NativeLoadError {} + +#[derive(Debug)] +pub enum NativeRuntimeError { + HipError(i32), + NullHandle(&'static str), + LengthMismatch { graphs: usize, deps: usize }, +} + +impl fmt::Display for NativeRuntimeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::HipError(code) => write!(f, "HIP runtime returned error code {code}"), + Self::NullHandle(name) => write!(f, "{name} returned a null native handle"), + Self::LengthMismatch { graphs, deps } => write!( + f, + "composed graph input length mismatch: {graphs} graphs, {deps} deps" + ), + } + } +} + +impl Error for NativeRuntimeError {} + +type HgbInit = unsafe extern "C" fn() -> c_int; +type HgbShutdown = unsafe extern "C" fn(); +type HgbIsInitialized = unsafe extern "C" fn() -> c_int; +type HgbGetVersion = unsafe extern "C" fn() -> HgbVersion; +type HgbProfilerReset = unsafe extern "C" fn(); +type HgbProfilerRecord = unsafe extern "C" fn(u32, u64, u64, u64) -> u64; +type HgbProfilerSnapshot = + unsafe extern "C" fn(*mut ProfileSample, usize, *mut ProfileCounters) -> usize; +type HgbPipelineHandleCreate = unsafe extern "C" fn(*mut c_void, *mut *mut c_void) -> c_int; +type HgbPipelineHandleLaunch = unsafe extern "C" fn(*mut c_void) -> c_int; +type HgbPipelineHandleUpdateKernel = + unsafe extern "C" fn(*mut c_void, *mut c_void, *mut c_void) -> c_int; +type HgbPipelineHandleUpdateAndLaunch = + unsafe extern "C" fn(*mut c_void, *mut c_void, *mut c_void) -> c_int; +type HgbPipelineHandleDestroy = unsafe extern "C" fn(*mut c_void); +type HgbComposedHandleCreate = + unsafe extern "C" fn(*mut *mut c_void, c_int, *const c_int, *mut *mut c_void) -> c_int; +type HgbComposedHandleLaunch = unsafe extern "C" fn(*mut c_void, *mut c_void) -> c_int; +type HgbComposedHandleUpdateChild = unsafe extern "C" fn(*mut c_void, c_int, *mut c_void) -> c_int; +type HgbComposedHandleDestroy = unsafe extern "C" fn(*mut c_void); + +/// Capture callback for the capture-safe decode pool: +/// `(bucket_max, d_seq_lens, d_block_tables, *out_graph, ctx) -> hipError_t`. The graph it captures +/// must read the supplied PERSISTENT `d_seq_lens`/`d_block_tables` device buffers (so replay refreshes +/// them in place rather than baking the sequence length by value). +pub type HgbDecodeCaptureFn = + unsafe extern "C" fn(c_int, *const c_int, *const c_int, *mut *mut c_void, *mut c_void) -> c_int; +type HgbDecodePoolHandleCreate = unsafe extern "C" fn( + Option, + *mut c_void, + *const c_int, + c_int, + c_int, + c_int, + *mut *mut c_void, +) -> c_int; +type HgbDecodePoolHandleReplay = unsafe extern "C" fn( + *mut c_void, + c_int, + *const c_int, + c_int, + *const c_int, + *mut c_void, + *mut c_int, +) -> c_int; +type HgbDecodePoolHandleDestroy = unsafe extern "C" fn(*mut c_void); + +#[derive(Clone, Copy)] +struct NativeApi { + init: HgbInit, + shutdown: HgbShutdown, + is_initialized: HgbIsInitialized, + get_version: HgbGetVersion, + profiler_reset: HgbProfilerReset, + profiler_record: HgbProfilerRecord, + profiler_snapshot: HgbProfilerSnapshot, + pipeline_handle_create: HgbPipelineHandleCreate, + pipeline_handle_launch: HgbPipelineHandleLaunch, + pipeline_handle_update_kernel: HgbPipelineHandleUpdateKernel, + pipeline_handle_update_and_launch: HgbPipelineHandleUpdateAndLaunch, + pipeline_handle_destroy: HgbPipelineHandleDestroy, + composed_handle_create: HgbComposedHandleCreate, + composed_handle_launch: HgbComposedHandleLaunch, + composed_handle_update_child: HgbComposedHandleUpdateChild, + composed_handle_destroy: HgbComposedHandleDestroy, + decode_pool_handle_create: HgbDecodePoolHandleCreate, + decode_pool_handle_replay: HgbDecodePoolHandleReplay, + decode_pool_handle_destroy: HgbDecodePoolHandleDestroy, +} + +pub struct NativeBridge { + handle: *mut c_void, + path: PathBuf, + api: NativeApi, +} + +unsafe impl Send for NativeBridge {} +unsafe impl Sync for NativeBridge {} + +impl NativeBridge { + pub fn open(path: impl AsRef) -> Result { + let path = path.as_ref().to_path_buf(); + let c_path = CString::new(path.as_os_str().to_string_lossy().as_bytes()).map_err(|_| { + NativeLoadError::Open { + path: path.clone(), + message: "path contains interior NUL".to_string(), + } + })?; + + clear_dlerror(); + let handle = unsafe { libc::dlopen(c_path.as_ptr(), libc::RTLD_NOW | libc::RTLD_LOCAL) }; + if handle.is_null() { + return Err(NativeLoadError::Open { + path, + message: dlerror_string(), + }); + } + + let api = unsafe { + NativeApi { + init: load_symbol(handle, "hgb_init")?, + shutdown: load_symbol(handle, "hgb_shutdown")?, + is_initialized: load_symbol(handle, "hgb_is_initialized")?, + get_version: load_symbol(handle, "hgb_get_version")?, + profiler_reset: load_symbol(handle, "hgb_profiler_reset")?, + profiler_record: load_symbol(handle, "hgb_profiler_record")?, + profiler_snapshot: load_symbol(handle, "hgb_profiler_snapshot")?, + pipeline_handle_create: load_symbol(handle, "hgb_pipeline_handle_create")?, + pipeline_handle_launch: load_symbol(handle, "hgb_pipeline_handle_launch")?, + pipeline_handle_update_kernel: load_symbol( + handle, + "hgb_pipeline_handle_update_kernel", + )?, + pipeline_handle_update_and_launch: load_symbol( + handle, + "hgb_pipeline_handle_update_and_launch", + )?, + pipeline_handle_destroy: load_symbol(handle, "hgb_pipeline_handle_destroy")?, + composed_handle_create: load_symbol(handle, "hgb_composed_handle_create")?, + composed_handle_launch: load_symbol(handle, "hgb_composed_handle_launch")?, + composed_handle_update_child: load_symbol( + handle, + "hgb_composed_handle_update_child", + )?, + composed_handle_destroy: load_symbol(handle, "hgb_composed_handle_destroy")?, + decode_pool_handle_create: load_symbol(handle, "hgb_decode_pool_handle_create")?, + decode_pool_handle_replay: load_symbol(handle, "hgb_decode_pool_handle_replay")?, + decode_pool_handle_destroy: load_symbol(handle, "hgb_decode_pool_handle_destroy")?, + } + }; + + Ok(Self { handle, path, api }) + } + + pub fn open_default(repo_root: impl AsRef) -> Result { + let candidates = default_library_candidates(repo_root); + for candidate in &candidates { + if candidate.exists() { + return Self::open(candidate); + } + } + Err(NativeLoadError::NoCandidate { candidates }) + } + + pub fn library_path(&self) -> &Path { + &self.path + } + + pub fn init(&self) -> Result<(), NativeRuntimeError> { + match unsafe { (self.api.init)() } { + 0 => Ok(()), + code => Err(NativeRuntimeError::HipError(code)), + } + } + + pub fn shutdown(&self) { + unsafe { (self.api.shutdown)() }; + } + + pub fn is_initialized(&self) -> bool { + unsafe { (self.api.is_initialized)() != 0 } + } + + pub fn version(&self) -> NativeVersion { + let raw = unsafe { (self.api.get_version)() }; + NativeVersion { + major: raw.major, + minor: raw.minor, + patch: raw.patch, + gfx_target: cstr_to_string(raw.gfx_target), + rocm_version: cstr_to_string(raw.rocm_version), + } + } + + pub fn profiler_reset(&self) { + unsafe { (self.api.profiler_reset)() }; + } + + pub fn profiler_record( + &self, + event: ProfileEventKind, + duration_ns: u64, + value0: u64, + value1: u64, + ) -> u64 { + unsafe { (self.api.profiler_record)(event as u32, duration_ns, value0, value1) } + } + + pub fn profiler_snapshot(&self, max_samples: usize) -> (Vec, ProfileCounters) { + let mut counters = ProfileCounters::default(); + let mut samples = vec![ProfileSample::default(); max_samples]; + let copied = unsafe { + (self.api.profiler_snapshot)( + samples.as_mut_ptr(), + samples.len(), + &mut counters as *mut ProfileCounters, + ) + }; + samples.truncate(copied); + (samples, counters) + } + + pub unsafe fn pipeline_from_raw_graph( + &self, + graph: *mut c_void, + ) -> Result, NativeRuntimeError> { + let mut handle = ptr::null_mut(); + let code = unsafe { (self.api.pipeline_handle_create)(graph, &mut handle) }; + if code != 0 { + return Err(NativeRuntimeError::HipError(code)); + } + if handle.is_null() { + return Err(NativeRuntimeError::NullHandle("hgb_pipeline_handle_create")); + } + Ok(NativePipeline { + bridge: self, + handle, + }) + } + + pub unsafe fn composed_from_raw_graphs( + &self, + sub_graphs: &mut [*mut c_void], + deps: &[c_int], + ) -> Result, NativeRuntimeError> { + if sub_graphs.len() != deps.len() { + return Err(NativeRuntimeError::LengthMismatch { + graphs: sub_graphs.len(), + deps: deps.len(), + }); + } + + let mut handle = ptr::null_mut(); + let code = unsafe { + (self.api.composed_handle_create)( + sub_graphs.as_mut_ptr(), + sub_graphs.len() as c_int, + deps.as_ptr(), + &mut handle, + ) + }; + if code != 0 { + return Err(NativeRuntimeError::HipError(code)); + } + if handle.is_null() { + return Err(NativeRuntimeError::NullHandle("hgb_composed_handle_create")); + } + Ok(NativeComposedGraph { + bridge: self, + handle, + }) + } + + /// Create a capture-safe decode pool. `capture_fn` (signature [`HgbDecodeCaptureFn`]) captures a + /// graph for each bucket that reads the pool's PERSISTENT `d_seq_lens`/`d_block_tables` device + /// buffers; `ctx` is passed through to it. `buckets` = ascending per-bucket max sequence lengths. + /// [`NativeCaptureSafeDecode::replay`] refreshes the metadata in place then launches — fixing the + /// decode-attn-under-capture garble (baked-by-value seq metadata). + /// + /// # Safety + /// `capture_fn`/`ctx` must remain valid for the capture, and the callback must only enqueue + /// capture-legal work (no alloc/sync/JIT) reading the supplied device buffers. + pub unsafe fn capture_safe_decode( + &self, + capture_fn: HgbDecodeCaptureFn, + ctx: *mut c_void, + buckets: &[c_int], + max_num_seqs: c_int, + max_blocks_per_seq: c_int, + ) -> Result, NativeRuntimeError> { + let mut handle = ptr::null_mut(); + let code = unsafe { + (self.api.decode_pool_handle_create)( + Some(capture_fn), + ctx, + buckets.as_ptr(), + buckets.len() as c_int, + max_num_seqs, + max_blocks_per_seq, + &mut handle, + ) + }; + if code != 0 { + return Err(NativeRuntimeError::HipError(code)); + } + if handle.is_null() { + return Err(NativeRuntimeError::NullHandle("hgb_decode_pool_handle_create")); + } + Ok(NativeCaptureSafeDecode { + bridge: self, + handle, + }) + } +} + +impl Drop for NativeBridge { + fn drop(&mut self) { + if !self.handle.is_null() { + unsafe { + libc::dlclose(self.handle); + } + self.handle = ptr::null_mut(); + } + } +} + +pub struct NativePipeline<'a> { + bridge: &'a NativeBridge, + handle: *mut c_void, +} + +impl<'a> NativePipeline<'a> { + pub fn as_raw(&self) -> *mut c_void { + self.handle + } + + pub fn launch(&self) -> Result<(), NativeRuntimeError> { + match unsafe { (self.bridge.api.pipeline_handle_launch)(self.handle) } { + 0 => Ok(()), + code => Err(NativeRuntimeError::HipError(code)), + } + } + + pub unsafe fn update_kernel( + &self, + node: *mut c_void, + params: *mut c_void, + ) -> Result<(), NativeRuntimeError> { + match unsafe { (self.bridge.api.pipeline_handle_update_kernel)(self.handle, node, params) } + { + 0 => Ok(()), + code => Err(NativeRuntimeError::HipError(code)), + } + } + + pub unsafe fn update_and_launch( + &self, + node: *mut c_void, + params: *mut c_void, + ) -> Result<(), NativeRuntimeError> { + match unsafe { + (self.bridge.api.pipeline_handle_update_and_launch)(self.handle, node, params) + } { + 0 => Ok(()), + code => Err(NativeRuntimeError::HipError(code)), + } + } +} + +impl Drop for NativePipeline<'_> { + fn drop(&mut self) { + if !self.handle.is_null() { + unsafe { (self.bridge.api.pipeline_handle_destroy)(self.handle) }; + self.handle = ptr::null_mut(); + } + } +} + +pub struct NativeComposedGraph<'a> { + bridge: &'a NativeBridge, + handle: *mut c_void, +} + +impl<'a> NativeComposedGraph<'a> { + pub fn as_raw(&self) -> *mut c_void { + self.handle + } + + pub unsafe fn launch(&self, stream: *mut c_void) -> Result<(), NativeRuntimeError> { + match unsafe { (self.bridge.api.composed_handle_launch)(self.handle, stream) } { + 0 => Ok(()), + code => Err(NativeRuntimeError::HipError(code)), + } + } + + pub unsafe fn update_child( + &self, + child_index: c_int, + new_sub_graph: *mut c_void, + ) -> Result<(), NativeRuntimeError> { + match unsafe { + (self.bridge.api.composed_handle_update_child)(self.handle, child_index, new_sub_graph) + } { + 0 => Ok(()), + code => Err(NativeRuntimeError::HipError(code)), + } + } +} + +impl Drop for NativeComposedGraph<'_> { + fn drop(&mut self) { + if !self.handle.is_null() { + unsafe { (self.bridge.api.composed_handle_destroy)(self.handle) }; + self.handle = ptr::null_mut(); + } + } +} + +/// A capture-safe paged-decode pool: one captured hipGraph per bucket over PERSISTENT device metadata +/// buffers; [`replay`](Self::replay) refreshes the metadata in place then launches, so a captured +/// decode graph stays correct as the sequence grows (fixes the decode-attn-under-capture garble — +/// stale baked-by-value seq metadata). +pub struct NativeCaptureSafeDecode<'a> { + bridge: &'a NativeBridge, + handle: *mut c_void, +} + +impl<'a> NativeCaptureSafeDecode<'a> { + pub fn as_raw(&self) -> *mut c_void { + self.handle + } + + /// Refresh the persistent metadata from host arrays, then launch the smallest bucket >= + /// `input_size`. `seq_lens` is `[num_seqs]`; `block_tables` is `[num_seqs * max_blocks_per_seq]` + /// (or `None` to skip the block-table copy). Returns the actual bucket used. + /// + /// # Safety + /// `stream` must be a valid `hipStream_t`, and the host slices must match the pool geometry. + pub unsafe fn replay( + &self, + input_size: c_int, + seq_lens: &[c_int], + block_tables: Option<&[c_int]>, + stream: *mut c_void, + ) -> Result { + let bt = block_tables.map_or(ptr::null(), |b| b.as_ptr()); + let mut actual_bucket: c_int = 0; + let code = unsafe { + (self.bridge.api.decode_pool_handle_replay)( + self.handle, + input_size, + seq_lens.as_ptr(), + seq_lens.len() as c_int, + bt, + stream, + &mut actual_bucket, + ) + }; + match code { + 0 => Ok(actual_bucket), + code => Err(NativeRuntimeError::HipError(code)), + } + } +} + +impl Drop for NativeCaptureSafeDecode<'_> { + fn drop(&mut self) { + if !self.handle.is_null() { + unsafe { (self.bridge.api.decode_pool_handle_destroy)(self.handle) }; + self.handle = ptr::null_mut(); + } + } +} + +pub fn default_library_candidates(repo_root: impl AsRef) -> Vec { + let repo_root = repo_root.as_ref(); + let mut candidates = Vec::new(); + for key in ["GFXGRAPH_NATIVE_LIB", "GFXGRAPH_LIB"] { + if let Ok(value) = env::var(key) { + if !value.trim().is_empty() { + candidates.push(PathBuf::from(value)); + } + } + } + candidates.push(repo_root.join("build/libhipgraph_bridge.so")); + candidates.push(repo_root.join("build/lib/libhipgraph_bridge.so")); + candidates.push(PathBuf::from("/usr/local/lib/libhipgraph_bridge.so")); + candidates +} + +unsafe fn load_symbol( + handle: *mut c_void, + name: &'static str, +) -> Result { + let c_name = CString::new(name).map_err(|_| NativeLoadError::InvalidSymbolName(name))?; + clear_dlerror(); + let symbol = unsafe { libc::dlsym(handle, c_name.as_ptr()) }; + if symbol.is_null() { + return Err(NativeLoadError::Symbol { + name, + message: dlerror_string(), + }); + } + Ok(unsafe { std::mem::transmute_copy::<*mut c_void, T>(&symbol) }) +} + +fn cstr_to_string(ptr: *const c_char) -> String { + if ptr.is_null() { + return String::new(); + } + unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() } +} + +fn clear_dlerror() { + unsafe { + libc::dlerror(); + } +} + +fn dlerror_string() -> String { + let ptr = unsafe { libc::dlerror() }; + if ptr.is_null() { + return "unknown dynamic loader error".to_string(); + } + unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn default_candidates_include_repo_build_output() { + let candidates = default_library_candidates("/tmp/gfxGRAPH"); + assert!(candidates + .iter() + .any(|path| path.ends_with("build/libhipgraph_bridge.so"))); + } + + #[test] + fn profile_structs_have_expected_capacity_for_c_abi() { + assert!(std::mem::size_of::() >= 56); + assert_eq!(std::mem::size_of::(), 24); + } +} diff --git a/rust/rs_gfxgraph_stats/Cargo.toml b/rust/rs_gfxgraph_stats/Cargo.toml index 41aa1d2..8d506fc 100644 --- a/rust/rs_gfxgraph_stats/Cargo.toml +++ b/rust/rs_gfxgraph_stats/Cargo.toml @@ -8,7 +8,9 @@ name = "rs_gfxgraph_stats" crate-type = ["cdylib", "rlib"] [dependencies] -pyo3 = { version = "0.29.0", features = ["extension-module"] } +pyo3 = { version = "0.24.1", features = ["extension-module"] } dashmap = "6.1.0" lazy_static = "1.5.0" +[build-dependencies] +maturin = "1.5.0" diff --git a/rust/rs_gfxgraph_stats/src/lib.rs b/rust/rs_gfxgraph_stats/src/lib.rs index 3114726..9fb25fe 100644 --- a/rust/rs_gfxgraph_stats/src/lib.rs +++ b/rust/rs_gfxgraph_stats/src/lib.rs @@ -1,5 +1,4 @@ use pyo3::prelude::*; -use pyo3::types::PyAny; use std::sync::{Arc, Mutex}; use dashmap::DashMap; @@ -38,7 +37,7 @@ fn record_replay_us(us: f64) -> PyResult<()> { } #[pyfunction] -fn stats(py: Python<'_>) -> PyResult> { +fn stats(py: Python<'_>) -> PyResult { use pyo3::types::PyDict; let dict = PyDict::new(py); @@ -63,7 +62,7 @@ fn stats(py: Python<'_>) -> PyResult> { dict.set_item("avg_replay_us", avg)?; - Ok(dict.into_any().unbind()) + Ok(dict.into()) } #[pyfunction] diff --git a/rust/rs_gfxgraph_toolbox/Cargo.toml b/rust/rs_gfxgraph_toolbox/Cargo.toml index 7c5f88d..38b29dc 100644 --- a/rust/rs_gfxgraph_toolbox/Cargo.toml +++ b/rust/rs_gfxgraph_toolbox/Cargo.toml @@ -8,9 +8,10 @@ description = "Policy-free developer toolbox for gfxGRAPH geometry, shape, layou name = "rs_gfxgraph_toolbox" path = "src/lib.rs" +[lints] +workspace = true + [dependencies] rs_gfxgraph_core = { path = "../rs_gfxgraph_core", default-features = false } serde = { version = "1.0", features = ["derive"] } -[lints] -workspace = true diff --git a/rust/rs_gfxgraph_toolbox/README.md b/rust/rs_gfxgraph_toolbox/README.md index bda456a..53d933a 100644 --- a/rust/rs_gfxgraph_toolbox/README.md +++ b/rust/rs_gfxgraph_toolbox/README.md @@ -1,5 +1,5 @@ # rs_gfxgraph_toolbox -Policy-free developer toolbox around `rs_gfxgraph_core`. +Developer toolbox around `rs_gfxgraph_core`. -This crate contains agent/developer-facing helpers for shape bucketing, graph-capture layout analysis, RDNA2 launch planning, and abstract signal-domain helpers such as Hann windows and frequency-bin mapping. It intentionally has no `rs_policy_mesh`, PyO3, audio runtime, voice runtime, or logly dependency so it can be governed as a separate tool boundary. +This crate contains helpers for shape bucketing, graph-capture layout analysis, RDNA2 launch planning, and abstract signal-domain helpers such as Hann windows and frequency-bin mapping. It intentionally has no PyO3 dependency so it can be governed as a separate tool boundary. diff --git a/skills/gfxgraph-benchmarking/SKILL.md b/skills/gfxgraph-benchmarking/SKILL.md new file mode 100644 index 0000000..e0da9f9 --- /dev/null +++ b/skills/gfxgraph-benchmarking/SKILL.md @@ -0,0 +1,33 @@ +--- +name: gfxgraph-benchmarking +description: Benchmark gfxGRAPH internals, run the public benchmark suite, and compare performance between Python and Rust. +--- + +# gfxGRAPH Benchmarking + +**Goal** +Run and analyze performance benchmarks on gfxGRAPH. + +## When to use this skill +- When verifying the performance impact of modifications to the routing logic (e.g. conditional runner, shape bucketing). +- When validating the package's overall latency and throughput improvements. +- When generating performance report JSON files containing provenance tracking (e.g. commit SHA, ROCm parameters). + +## How to use it +1. Use real hardware (e.g. AMD Radeon RX 6700 XT) under ROCm 7.2 when running GPU benchmarks. +2. For micro-benchmarking CPU/mock pathways, ensure standard mocks (like mocking `torch_cuda_execution_probe`) are set up. +3. Run the public benchmark script: + ```bash + PYTHONPATH=python python benchmarks/bench_readme_public.py --run-count 3 --output benchmarks/results/readme_benchmark_latest.json + ``` +4. Run python/rust micro-benchmarks: + - Routing: `python benchmarks/bench_routing.py` vs. `python benchmarks/bench_routing_rust.py` + - Conditional: `python benchmarks/bench_conditional_mock.py` + +## Preferred checks +- Check latency output (`avg_replay_us`) in `gfxgraph.stats()`. +- Compare ops/sec throughput differences on dynamic-shape bucketed runs. + +## Pass criteria +- Public benchmark completes successfully and writes a populated JSON output containing system provenance metrics (commit SHA, ROCm runtime, etc.). +- Performance regression checking shows throughput remains within target bounds (e.g. >= 90% static graph replay for shape bucketing, >= 85% for conditional branching). diff --git a/skills/rocm-atom-inference/SKILL.md b/skills/rocm-atom-inference/SKILL.md new file mode 100644 index 0000000..2122b40 --- /dev/null +++ b/skills/rocm-atom-inference/SKILL.md @@ -0,0 +1,55 @@ +--- +name: rocm-atom-inference +description: Guide and resources for deployment and development using the ROCm/AMD ATOM (AiTer Optimized Model) inference backend. +--- + +# ROCm ATOM Inference Backend + +ATOM (AiTer Optimized Model) is a lightweight vLLM-like implementation, focusing on integration and optimization based on AITER kernels. It provides an OpenAI-Compatible API drop-in server (`/v1/chat/completions` and `/v1/completions`) that is optimized for AMD's ROCm platform. + +## When to use this skill +- You need to deploy a Large Language Model (e.g., LLaMa, Qwen, DeepSeek, Mixtral) using an AMD GPU environment. +- You need to benchmark or test inference throughput and latency on ROCm. +- You want to start an OpenAI-compatible API server using the ATOM backend. +- You need to manage KV cache transfers, speculative decoding (MTP), or multi-GPU parallelism (TP/DP/EP) on AMD hardware. + +## Features +- **ROCm Optimized**: Built on AMD's ROCm platform with AITER kernels (ASM, CK, Triton). +- **Piecewise `torch.compile`**: 4 compilation levels with CUDA graph capture for low-latency decode. +- **Multi-GPU Parallelism**: Tensor parallelism (TP), data parallelism (DP), and expert parallelism (EP) with MORI all-to-all. +- **Speculative Decoding**: Multi-Token Prediction (MTP) with EAGLE proposer. +- **Prefix Caching**: xxhash64-based KV cache block sharing across sequences. + +## Installation +The recommended way to install and use ATOM is via the nightly Docker image. See `scripts/install_atom_container.sh` for an example. Alternatively, you can build from the base ROCm image by pulling `rocm/pytorch` and installing `amd-aiter` via pip. + +## Basic Usage + +### Simple Inference Example +```bash +# Requires ninja and huggingface_hub installed +python -m atom.examples.simple_inference --model meta-llama/Meta-Llama-3-8B --kv_cache_dtype fp8 +``` +*Note: First-time execution may take approximately 10 minutes for model compilation.* + +### Starting the Server +Start an OpenAI-compatible server using the entrypoint. See `examples/example_openai_server.sh` for multi-GPU and speculative decoding examples. + +```bash +python -m atom.entrypoints.openai_server --model Qwen/Qwen3-0.6B --kv_cache_dtype fp8 +``` + +## Performance & Profiling +To run an online throughput benchmark against a running server: +```bash +python -m atom.benchmarks.benchmark_serving \ + --model=deepseek-ai/DeepSeek-R1 --backend=vllm --base-url=http://localhost:8000 \ + --dataset-name=random \ + --random-input-len=1024 --random-output-len=1024 \ + --random-range-ratio=0.8 \ + --num-prompts=1280 --max-concurrency=128 \ + --request-rate=inf --ignore-eos \ + --save-result --percentile-metrics="ttft,tpot,itl,e2el" +``` + +To collect a profile trace, launch the server with `--torch-profiler-dir ./trace --mark-trace`. diff --git a/skills/rocm-atom-inference/examples/example_openai_server.sh b/skills/rocm-atom-inference/examples/example_openai_server.sh new file mode 100755 index 0000000..d106031 --- /dev/null +++ b/skills/rocm-atom-inference/examples/example_openai_server.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Example script to start the ATOM OpenAI-compatible server + +MODEL="deepseek-ai/DeepSeek-R1" +TP_SIZE=8 +KV_CACHE_DTYPE="fp8" + +# Start the server with Tensor Parallelism and Multi-Token Prediction (MTP) speculative decoding +python3 -m atom.entrypoints.openai_server \ + --model $MODEL \ + --kv_cache_dtype $KV_CACHE_DTYPE \ + -tp $TP_SIZE \ + --method mtp \ + --num-speculative-tokens 3 diff --git a/skills/rocm-atom-inference/scripts/install_atom_container.sh b/skills/rocm-atom-inference/scripts/install_atom_container.sh new file mode 100755 index 0000000..9f180ec --- /dev/null +++ b/skills/rocm-atom-inference/scripts/install_atom_container.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Script to install and run the recommended ATOM nightly docker image + +docker pull rocm/atom-dev:latest + +docker run -it --network=host \ + --device=/dev/kfd \ + --device=/dev/dri \ + --group-add video \ + --cap-add=SYS_PTRACE \ + --security-opt seccomp=unconfined \ + -v $HOME:/home/$USER \ + -v /mnt:/mnt \ + -v /data:/data \ + --shm-size=16G \ + --ulimit memlock=-1 \ + --ulimit stack=67108864 \ + rocm/atom-dev:latest diff --git a/skills/rocm-ds-smi-science-tools/SKILL.md b/skills/rocm-ds-smi-science-tools/SKILL.md new file mode 100644 index 0000000..446e8ea --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/SKILL.md @@ -0,0 +1,27 @@ +--- +name: rocm-ds-smi-science-tools +description: Parent overview skill for ROCm Data Science (ROCm-DS) components and + SMI tools. Provides guidance on routing workloads, compatibility triage, and component-specific + tasks like hipDF, hipVS, and hipMM. +--- + + +# ROCm-DS SMI Science Tools Overview + +This is the parent skill for managing tasks related to ROCm Data Science (ROCm-DS) and AMD GPU-accelerated scientific computing tools. + +## When to use this skill +Use this skill to determine the appropriate nested skill to invoke when working with ROCm-DS components, porting data science workflows to ROCm, or handling installation and compatibility. + +## Nested Skills Directory + +- **`compatibility-triage`**: Verifies whether a requested ROCm-DS workflow is officially supported, source-build feasible, or experimental on the target system. +- **`hipdf-pandas-port`**: Migrates pandas-like workflows to hipDF and cudf.pandas style acceleration, auditing for unsupported features. +- **`hipgraph-analytics`**: Leverages GPU acceleration to process and analyze complex graph structures using hipGRAPH. +- **`hipmm-memory-ops`**: Utilizes the HIP Memory Manager (hipMM) for advanced GPU memory pooling, efficient allocation, and data movement. +- **`hipraft-primitives`**: Utilizes hipRAFT for foundational, reusable GPU-accelerated primitives like clustering, dimensionality reduction, and statistical operations. +- **`hipvs-ann`**: Selects, builds, benchmarks, and validates hipVS ANN indexes and query paths for ROCm-DS workloads. +- **`install-build`**: Handles installation and source compilation of ROCm-DS components via conda, PyPI, or source builds. +- **`pipeline-integration`**: Integrates ROCm-DS components into broader data science pipelines. +- **`benchmark-validate`**: Validates and benchmarks ROCm-DS component ports against their CPU baselines (e.g., pandas vs hipDF). +- **`tool-router`**: Classifies and routes tasks to the appropriate ROCm-DS component (hipDF, hipVS, hipGRAPH, hipRAFT, hipMM) based on workload requirements. diff --git a/skills/rocm-ds-smi-science-tools/benchmark-validate/SKILL.md b/skills/rocm-ds-smi-science-tools/benchmark-validate/SKILL.md new file mode 100644 index 0000000..65e15e7 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/benchmark-validate/SKILL.md @@ -0,0 +1,39 @@ +--- +name: benchmark-validate +description: Validates and benchmarks ROCm-DS component ports against their CPU baselines + (e.g., pandas vs hipDF). Use this to generate parity tests, verify correctness, + and measure the performance speedups of GPU-accelerated code. +--- + + +# Purpose + +To execute and measure data science tasks across CPU and ROCm GPU backends to ensure both functional parity and measure performance acceleration. + +# When to use + +- After migrating a script to use ROCm-DS components (e.g., hipDF, hipRAFT) and needing to verify it produces the same results as the original. +- To quantify the wall-clock performance difference between CPU baseline and GPU accelerated scripts. + +# Procedure + +1. Read the provided baseline CPU script and the migrated ROCm-DS script. +2. Formulate a small test dataset if one is not provided. +3. Run the baseline CPU script and record the outputs and execution time. +4. Run the migrated ROCm script and record the outputs and execution time. +5. Verify functional parity between the two outputs (e.g., using `pandas.testing.assert_frame_equal`). +6. Calculate the acceleration factor (CPU_time / GPU_time). +7. Use the `examples/benchmark_report.md` template to generate the final report. + +# Execution Support + +* **Helper Script:** `scripts/run_rocm_benchmark.sh` + * *Usage:* `bash scripts/run_rocm_benchmark.sh ` + * This script acts as a basic wrapper to time execution and capture outputs. +* **Report Template:** `examples/benchmark_report.md` + +# Deliverables + +- Output of parity check (Pass/Fail) +- Performance metrics (CPU time, GPU time, Speedup) +- Formatted `benchmark_report.md` diff --git a/skills/rocm-ds-smi-science-tools/benchmark-validate/TOOLING.yaml b/skills/rocm-ds-smi-science-tools/benchmark-validate/TOOLING.yaml new file mode 100644 index 0000000..07d0915 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/benchmark-validate/TOOLING.yaml @@ -0,0 +1,27 @@ +toolification: + callable: true + safe_to_parallelize: false + preferred_runtimes: + - bash + - python + entrypoints: + - SKILL.md + wrappers: + sglang: + tool_name: rocm_ds_skill + mode: routed + io: json + langchain: + tool_name: rocm_ds_skill + mode: structured + io: pydantic + mcp: + tool_name: rocm_ds_skill + mode: stdio + io: jsonrpc + approval_gates: + required_for: + - destructive file changes + - dependency pin changes + - unsupported GPU claims + - benchmark claims without evidence diff --git a/skills/rocm-ds-smi-science-tools/benchmark-validate/examples/benchmark_report.md b/skills/rocm-ds-smi-science-tools/benchmark-validate/examples/benchmark_report.md new file mode 100644 index 0000000..e9912c8 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/benchmark-validate/examples/benchmark_report.md @@ -0,0 +1,28 @@ +# ROCm-DS Benchmark Report + +## Overview +**Component:** (e.g., hipDF, hipRAFT) +**Task:** (e.g., Dataframe Join, KMeans Clustering) +**Date:** YYYY-MM-DD + +## Scripts Tested +* **CPU Baseline:** `path/to/cpu_baseline.py` +* **ROCm Script:** `path/to/rocm_accelerated.py` + +## Environment Facts +* **OS:** +* **GPU Model:** +* **ROCm Version:** + +## Parity Validation +* **Status:** [PASS | FAIL] +* **Notes:** (e.g., "pandas.testing.assert_frame_equal passed with rtol=1e-5. Minor floating point differences were observed but within acceptable tolerance.") + +## Performance Results +| Metric | CPU Baseline | ROCm Accelerated | +| :--- | :--- | :--- | +| Execution Time (s) | XX.XX | YY.YY | +| Speedup Factor | 1.0x | ZZ.Zx | + +## Limitations & Unresolved Issues +* (List any unsupported features encountered, memory constraints, or limitations in the porting process) diff --git a/skills/rocm-ds-smi-science-tools/benchmark-validate/scripts/run_rocm_benchmark.sh b/skills/rocm-ds-smi-science-tools/benchmark-validate/scripts/run_rocm_benchmark.sh new file mode 100755 index 0000000..f55c633 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/benchmark-validate/scripts/run_rocm_benchmark.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +# run_rocm_benchmark.sh +# A helper script to time and compare a CPU baseline script vs a ROCm script. + +if [[ $# -lt 2 ]]; then + echo "Usage: $0 " + echo "Runs both scripts, times them, and saves their outputs for comparison." + exit 1 +fi + +CPU_SCRIPT="$1" +ROCM_SCRIPT="$2" + +echo "=== ROCm-DS Benchmark Wrapper ===" +echo "CPU Baseline: ${CPU_SCRIPT}" +echo "ROCM Script: ${ROCM_SCRIPT}" +echo "---------------------------------" + +# Run CPU Baseline +echo "[1/2] Running CPU Baseline..." +CPU_START=$(date +%s.%N) +python3 "${CPU_SCRIPT}" > cpu_output.txt 2> cpu_error.txt || echo "CPU Script returned non-zero exit code" +CPU_END=$(date +%s.%N) +CPU_TIME=$(echo "$CPU_END - $CPU_START" | bc) +echo "CPU Execution Time: ${CPU_TIME} seconds" + +# Run ROCm Script +echo "" +echo "[2/2] Running ROCm Script..." +ROCM_START=$(date +%s.%N) +python3 "${ROCM_SCRIPT}" > rocm_output.txt 2> rocm_error.txt || echo "ROCm Script returned non-zero exit code" +ROCM_END=$(date +%s.%N) +ROCM_TIME=$(echo "$ROCM_END - $ROCM_START" | bc) +echo "ROCm Execution Time: ${ROCM_TIME} seconds" + +echo "---------------------------------" +echo "Benchmark Complete." +echo "CPU Output saved to: cpu_output.txt (Errors: cpu_error.txt)" +echo "ROCm Output saved to: rocm_output.txt (Errors: rocm_error.txt)" +echo "" +echo "To verify parity, manually compare the outputs or run a parity testing script." diff --git a/skills/rocm-ds-smi-science-tools/compatibility-triage/SKILL.md b/skills/rocm-ds-smi-science-tools/compatibility-triage/SKILL.md new file mode 100644 index 0000000..75204ce --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/compatibility-triage/SKILL.md @@ -0,0 +1,38 @@ +--- +name: compatibility-triage +description: Verifies whether a requested ROCm-DS workflow is officially supported, + source-build feasible, or experimental on the target system. +--- + + +# Purpose + +Prevent agents from making unsupported assumptions about ROCm-DS compatibility. + +# Procedure + +1. Collect environment facts using `rocminfo`, `hipcc --version`, Python version, and OS release. +2. Map the requested workflow to one or more ROCm-DS components. +3. Compare the environment to official support statements and tested-GPU notes. +4. Classify the request: + + * supported + * partially supported + * source-build experimental + * unsupported +5. Stop unsafe automation when the mismatch is material. +6. Produce a short report with exact blockers and realistic next moves. + +# Rules + +* Never claim support based solely on generic ROCm support. +* Distinguish official support from “might compile.” +* For experimental paths, require explicit evidence from local smoke tests. +* Do not silently widen GPU support claims. + +# Deliverables + +* Environment summary +* Support classification +* Exact mismatch list +* Recommended next action diff --git a/skills/rocm-ds-smi-science-tools/compatibility-triage/TOOLING.yaml b/skills/rocm-ds-smi-science-tools/compatibility-triage/TOOLING.yaml new file mode 100644 index 0000000..07d0915 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/compatibility-triage/TOOLING.yaml @@ -0,0 +1,27 @@ +toolification: + callable: true + safe_to_parallelize: false + preferred_runtimes: + - bash + - python + entrypoints: + - SKILL.md + wrappers: + sglang: + tool_name: rocm_ds_skill + mode: routed + io: json + langchain: + tool_name: rocm_ds_skill + mode: structured + io: pydantic + mcp: + tool_name: rocm_ds_skill + mode: stdio + io: jsonrpc + approval_gates: + required_for: + - destructive file changes + - dependency pin changes + - unsupported GPU claims + - benchmark claims without evidence diff --git a/skills/rocm-ds-smi-science-tools/compatibility-triage/references/official-support-notes.md b/skills/rocm-ds-smi-science-tools/compatibility-triage/references/official-support-notes.md new file mode 100644 index 0000000..329834f --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/compatibility-triage/references/official-support-notes.md @@ -0,0 +1,6 @@ +Check: +- ROCm version +- OS version +- Python version +- GPU architecture / gfx target +- Whether workload is officially supported, source-build only, or experimental diff --git a/skills/rocm-ds-smi-science-tools/compatibility-triage/scripts/detect_rocm_env.sh b/skills/rocm-ds-smi-science-tools/compatibility-triage/scripts/detect_rocm_env.sh new file mode 100755 index 0000000..f65d8c0 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/compatibility-triage/scripts/detect_rocm_env.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +echo "Detecting ROCm Environment..." + +if command -v rocminfo &> /dev/null; then + rocminfo | grep "ROCm Version" +else + echo "rocminfo not found. ROCm may not be installed." +fi + +if command -v hipcc &> /dev/null; then + hipcc --version | grep "HIP version" +else + echo "hipcc not found." +fi + +python3 --version +cat /etc/os-release | grep PRETTY_NAME + +echo "GPU Architecture target:" +/opt/rocm/bin/rocm_agent_enumerator 2>/dev/null || echo "Could not enumerate agents." diff --git a/skills/rocm-ds-smi-science-tools/examples/routing_example.md b/skills/rocm-ds-smi-science-tools/examples/routing_example.md new file mode 100644 index 0000000..69c09a2 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/examples/routing_example.md @@ -0,0 +1,4 @@ +# Routing Example + +When a user asks "How do I do vector search with ROCm?", you can route them to `hipvs-ann`. +When a user asks "How do I port my pandas code?", route them to `hipdf-pandas-port`. diff --git a/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/SKILL.md b/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/SKILL.md new file mode 100644 index 0000000..4240da0 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/SKILL.md @@ -0,0 +1,23 @@ +--- +name: hipdf-pandas-port +description: Migrates pandas-like workflows to hipDF and cudf.pandas style acceleration, + auditing for unsupported features. +--- + + +# Purpose + +Accelerate tabular workflows by porting pandas code to hipDF. + +# When to use + +- When a task involves slow pandas ETL, joins, or aggregations. +- To implement GPU DataFrames for performance gains. + +# Procedure + +1. Audit existing pandas usage in the provided scripts. +2. Identify unsupported features in hipDF compared to pandas. +3. Rewrite compatible sections using hipDF or cudf.pandas style acceleration. +4. Run parity tests to ensure the output matches the original pandas logic. +5. Report on performance gains and any remaining pandas fallback operations. diff --git a/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/TOOLING.yaml b/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/TOOLING.yaml new file mode 100644 index 0000000..07d0915 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/TOOLING.yaml @@ -0,0 +1,27 @@ +toolification: + callable: true + safe_to_parallelize: false + preferred_runtimes: + - bash + - python + entrypoints: + - SKILL.md + wrappers: + sglang: + tool_name: rocm_ds_skill + mode: routed + io: json + langchain: + tool_name: rocm_ds_skill + mode: structured + io: pydantic + mcp: + tool_name: rocm_ds_skill + mode: stdio + io: jsonrpc + approval_gates: + required_for: + - destructive file changes + - dependency pin changes + - unsupported GPU claims + - benchmark claims without evidence diff --git a/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/examples/pandas-to-hipdf-port.md b/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/examples/pandas-to-hipdf-port.md new file mode 100644 index 0000000..533006c --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/examples/pandas-to-hipdf-port.md @@ -0,0 +1,16 @@ +# Porting Pandas to hipDF + +Original pandas code: +```python +import pandas as pd +df = pd.read_csv('data.csv') +res = df.groupby('category').sum() +``` + +hipDF / cudf.pandas equivalent: +```python +# Assuming hipDF is available +import hipdf.pandas as pd # Or using the cudf.pandas hook mechanism if supported on ROCm +df = pd.read_csv('data.csv') +res = df.groupby('category').sum() +``` diff --git a/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/references/hipdf-notes.md b/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/references/hipdf-notes.md new file mode 100644 index 0000000..23c41f2 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/references/hipdf-notes.md @@ -0,0 +1,7 @@ +Core hipDF notes: +- GPU DataFrames with pandas-like API +- Python and C++ APIs +- Targets tabular ETL, aggregation, joins, filters +- Supports cudf.pandas-style acceleration path +- Official support is narrower than generic ROCm support +- Audit unsupported features before porting diff --git a/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/scripts/scan-pandas.sh b/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/scripts/scan-pandas.sh new file mode 100755 index 0000000..b180574 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipdf-pandas-port/scripts/scan-pandas.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# Helper to find pandas usage for potential hipDF porting +TARGET_DIR=${1:-"."} +echo "Scanning for pandas imports in $TARGET_DIR..." +grep -rn "import pandas as pd" "$TARGET_DIR" || echo "No pandas imports found." diff --git a/skills/rocm-ds-smi-science-tools/hipgraph-analytics/SKILL.md b/skills/rocm-ds-smi-science-tools/hipgraph-analytics/SKILL.md new file mode 100644 index 0000000..1b4dee9 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipgraph-analytics/SKILL.md @@ -0,0 +1,41 @@ +--- +name: hipgraph-analytics +description: Leverages GPU acceleration to process and analyze complex graph structures using hipGRAPH. Note: hipGRAPH is early access. +tools: + - bash + - python +inputs: + - graph_data + - algorithm_target +outputs: + - analytics_report + - computed_metrics +tags: + - rocm + - rocm-ds + - hipgraph + - graph-analytics +--- + +# Purpose + +Utilize hipGRAPH for high-performance graph processing and analysis, while acknowledging its early-access status. + +# When to use + +- When a data science task involves complex network or graph structures. +- To execute diverse graph algorithms such as centrality, traversal, similarity, sampling, and labeling. +- When graph outputs need to integrate seamlessly with hipDF DataFrames across the ROCm-DS ecosystem. + +# When not to use + +- **Production Environments:** The hipGRAPH libraries are currently in an **early access state**. Running production workloads with these libraries is explicitly not recommended by AMD. +- If the workload is purely tabular (use `hipdf-pandas-port`) or purely vector search (use `hipvs-ann`). + +# Procedure + +1. Verify that the requested workload is a non-production, experimental, or benchmark task. +2. Formulate the graph using hipGRAPH APIs, loading data (potentially from hipDF). +3. Execute the target algorithm (e.g., centrality, traversal, PageRank, BFS, node2vec). +4. Analyze the results or pipe them back into hipDF. +5. Report on the execution, highlighting any early-access instability or API quirks. diff --git a/skills/rocm-ds-smi-science-tools/hipgraph-analytics/TOOLING.yaml b/skills/rocm-ds-smi-science-tools/hipgraph-analytics/TOOLING.yaml new file mode 100644 index 0000000..07d0915 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipgraph-analytics/TOOLING.yaml @@ -0,0 +1,27 @@ +toolification: + callable: true + safe_to_parallelize: false + preferred_runtimes: + - bash + - python + entrypoints: + - SKILL.md + wrappers: + sglang: + tool_name: rocm_ds_skill + mode: routed + io: json + langchain: + tool_name: rocm_ds_skill + mode: structured + io: pydantic + mcp: + tool_name: rocm_ds_skill + mode: stdio + io: jsonrpc + approval_gates: + required_for: + - destructive file changes + - dependency pin changes + - unsupported GPU claims + - benchmark claims without evidence diff --git a/skills/rocm-ds-smi-science-tools/hipgraph-analytics/examples/pagerank.md b/skills/rocm-ds-smi-science-tools/hipgraph-analytics/examples/pagerank.md new file mode 100644 index 0000000..56568e3 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipgraph-analytics/examples/pagerank.md @@ -0,0 +1,10 @@ +# PageRank Example + +```python +import hipgraph as hg + +# Note: hipGRAPH is early access +G = hg.Graph() +# ... load data ... +pr = hg.pagerank(G) +``` diff --git a/skills/rocm-ds-smi-science-tools/hipmm-memory-ops/SKILL.md b/skills/rocm-ds-smi-science-tools/hipmm-memory-ops/SKILL.md new file mode 100644 index 0000000..a04f0b6 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipmm-memory-ops/SKILL.md @@ -0,0 +1,24 @@ +--- +name: hipmm-memory-ops +description: Utilizes the HIP Memory Manager (hipMM) for advanced GPU memory pooling, + efficient allocation, and data movement. +--- + + +# Purpose + +Provide advanced GPU memory management utilities to support various libraries that form part of ROCm-DS, mitigating OOM errors and fragmentation. + +# When to use + +- When a ROCm-DS workflow crashes with Out-Of-Memory (OOM) errors. +- To optimize efficient memory allocation and pooling for long-running workflows. +- When data movement bottlenecks exist between different ROCm-DS components (e.g., passing data from hipDF to hipVS). + +# Procedure + +1. Profile the memory usage of the existing workflow. +2. Configure hipMM to establish a memory pool suitable for the workload. +3. Replace default allocators with hipMM routines to reduce fragmentation and allocation overhead. +4. Measure the before/after memory footprint and execution speed. +5. Provide an optimization report detailing the configuration changes. diff --git a/skills/rocm-ds-smi-science-tools/hipmm-memory-ops/TOOLING.yaml b/skills/rocm-ds-smi-science-tools/hipmm-memory-ops/TOOLING.yaml new file mode 100644 index 0000000..07d0915 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipmm-memory-ops/TOOLING.yaml @@ -0,0 +1,27 @@ +toolification: + callable: true + safe_to_parallelize: false + preferred_runtimes: + - bash + - python + entrypoints: + - SKILL.md + wrappers: + sglang: + tool_name: rocm_ds_skill + mode: routed + io: json + langchain: + tool_name: rocm_ds_skill + mode: structured + io: pydantic + mcp: + tool_name: rocm_ds_skill + mode: stdio + io: jsonrpc + approval_gates: + required_for: + - destructive file changes + - dependency pin changes + - unsupported GPU claims + - benchmark claims without evidence diff --git a/skills/rocm-ds-smi-science-tools/hipmm-memory-ops/examples/basic.md b/skills/rocm-ds-smi-science-tools/hipmm-memory-ops/examples/basic.md new file mode 100644 index 0000000..e3fd925 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipmm-memory-ops/examples/basic.md @@ -0,0 +1,8 @@ +# Basic Memory Ops + +Using hipMM for memory ops: + +```python +import hipmm +# example +``` diff --git a/skills/rocm-ds-smi-science-tools/hipraft-primitives/SKILL.md b/skills/rocm-ds-smi-science-tools/hipraft-primitives/SKILL.md new file mode 100644 index 0000000..f738531 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipraft-primitives/SKILL.md @@ -0,0 +1,23 @@ +--- +name: hipraft-primitives +description: Utilizes hipRAFT for foundational, reusable GPU-accelerated primitives + like clustering, dimensionality reduction, and statistical operations. +--- + + +# Purpose + +Deploy hipRAFT as the computational backbone for higher-level data science and AI applications. + +# When to use + +- When you need a foundational layer of reusable GPU-accelerated primitives. +- For tasks involving core machine learning math: clustering, dimensionality reduction, and statistical operations. +- When building new algorithms that require low-level computational building blocks on AMD GPUs. + +# Procedure + +1. Identify the core mathematical operations required for the workload. +2. Select the appropriate hipRAFT primitive (e.g., clustering algorithms, solvers, linear algebra ops). +3. Integrate the primitive into the broader pipeline (often serving as the backbone for custom tools or hipVS integrations). +4. Verify correctness against standard CPU implementations. diff --git a/skills/rocm-ds-smi-science-tools/hipraft-primitives/TOOLING.yaml b/skills/rocm-ds-smi-science-tools/hipraft-primitives/TOOLING.yaml new file mode 100644 index 0000000..07d0915 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipraft-primitives/TOOLING.yaml @@ -0,0 +1,27 @@ +toolification: + callable: true + safe_to_parallelize: false + preferred_runtimes: + - bash + - python + entrypoints: + - SKILL.md + wrappers: + sglang: + tool_name: rocm_ds_skill + mode: routed + io: json + langchain: + tool_name: rocm_ds_skill + mode: structured + io: pydantic + mcp: + tool_name: rocm_ds_skill + mode: stdio + io: jsonrpc + approval_gates: + required_for: + - destructive file changes + - dependency pin changes + - unsupported GPU claims + - benchmark claims without evidence diff --git a/skills/rocm-ds-smi-science-tools/hipraft-primitives/examples/clustering.md b/skills/rocm-ds-smi-science-tools/hipraft-primitives/examples/clustering.md new file mode 100644 index 0000000..ca340ab --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipraft-primitives/examples/clustering.md @@ -0,0 +1,8 @@ +# Clustering Example + +Using hipRAFT for clustering primitives: + +```python +import hipraft +# example +``` diff --git a/skills/rocm-ds-smi-science-tools/hipvs-ann/SKILL.md b/skills/rocm-ds-smi-science-tools/hipvs-ann/SKILL.md new file mode 100644 index 0000000..da0bc2e --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipvs-ann/SKILL.md @@ -0,0 +1,54 @@ +--- +name: hipvs-ann +description: Selects, builds, benchmarks, and validates hipVS ANN indexes and query + paths for ROCm-DS workloads. +--- + + +# Purpose + +Choose the correct hipVS path for vector search workloads and validate that the selected ANN method is appropriate for the data, constraints, and hardware. + +# When to use + +- Build or tune ANN/vector-search workflows on ROCm-DS +- Compare brute force, HNSW, IVF-Flat, IVF-PQ, CAGRA, or NN-Descent +- Validate query latency, throughput, and recall tradeoffs +- Design a GPU-native retrieval subsystem + +# When not to use + +- The workload is ordinary tabular ETL with no vector retrieval requirement +- The target GPU is outside supported or realistically testable configurations and no experimental mode is explicitly allowed +- There is no benchmark dataset or success criterion + +# Required inputs + +- Repository path +- Dataset shape and vector dimensionality +- Distance metric +- Recall / latency / throughput targets +- GPU and ROCm environment facts +- Whether source builds are allowed + +# Procedure + +1. Check compatibility assumptions first. +2. Classify the workload: + - exact k-NN + - high-recall ANN + - memory-constrained ANN + - high-throughput batch query +3. Pick candidate index families. +4. Build the minimal reproducible benchmark. +5. Compare build time, memory use, query latency, and recall. +6. Recommend the least-complex path that satisfies the target. +7. Document unsupported assumptions and fallback options. + +# Deliverables + +- Recommended index type and rationale +- Build and runtime notes +- Benchmark summary +- Validation evidence +- Risks and fallback path diff --git a/skills/rocm-ds-smi-science-tools/hipvs-ann/TOOLING.yaml b/skills/rocm-ds-smi-science-tools/hipvs-ann/TOOLING.yaml new file mode 100644 index 0000000..07d0915 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipvs-ann/TOOLING.yaml @@ -0,0 +1,27 @@ +toolification: + callable: true + safe_to_parallelize: false + preferred_runtimes: + - bash + - python + entrypoints: + - SKILL.md + wrappers: + sglang: + tool_name: rocm_ds_skill + mode: routed + io: json + langchain: + tool_name: rocm_ds_skill + mode: structured + io: pydantic + mcp: + tool_name: rocm_ds_skill + mode: stdio + io: jsonrpc + approval_gates: + required_for: + - destructive file changes + - dependency pin changes + - unsupported GPU claims + - benchmark claims without evidence diff --git a/skills/rocm-ds-smi-science-tools/hipvs-ann/examples/ann-index-selection.md b/skills/rocm-ds-smi-science-tools/hipvs-ann/examples/ann-index-selection.md new file mode 100644 index 0000000..0685f86 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/hipvs-ann/examples/ann-index-selection.md @@ -0,0 +1,5 @@ +# ANN Index Selection for hipVS + +1. **Exact k-NN**: Use brute force. +2. **High-recall**: Use IVF-PQ or HNSW. +3. **High-throughput batch**: Use CAGRA. diff --git a/skills/rocm-ds-smi-science-tools/install-build/SKILL.md b/skills/rocm-ds-smi-science-tools/install-build/SKILL.md new file mode 100644 index 0000000..34c5455 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/install-build/SKILL.md @@ -0,0 +1,24 @@ +--- +name: install-build +description: Handles installation and source compilation of ROCm-DS components via + conda, PyPI, or source builds. +--- + + +# Purpose + +Execute end-user installations (via conda/PyPI) or from-source builds for ROCm-DS components, handling architecture-specific flags. + +# When to use + +- When a component is missing and needs to be installed. +- When an early-access component (like hipGRAPH) requires a source build. +- To set up a reproducible environment. + +# Procedure + +1. Determine if an end-user package (conda/pip) is available for the component. +2. If available, construct and execute the installation command. +3. If source-build is required, clone the repository, apply necessary architecture flags (e.g., `--gpu-arch`), and compile. +4. Run basic smoke tests to verify the installation. +5. Record the build log and installation status. diff --git a/skills/rocm-ds-smi-science-tools/install-build/TOOLING.yaml b/skills/rocm-ds-smi-science-tools/install-build/TOOLING.yaml new file mode 100644 index 0000000..07d0915 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/install-build/TOOLING.yaml @@ -0,0 +1,27 @@ +toolification: + callable: true + safe_to_parallelize: false + preferred_runtimes: + - bash + - python + entrypoints: + - SKILL.md + wrappers: + sglang: + tool_name: rocm_ds_skill + mode: routed + io: json + langchain: + tool_name: rocm_ds_skill + mode: structured + io: pydantic + mcp: + tool_name: rocm_ds_skill + mode: stdio + io: jsonrpc + approval_gates: + required_for: + - destructive file changes + - dependency pin changes + - unsupported GPU claims + - benchmark claims without evidence diff --git a/skills/rocm-ds-smi-science-tools/install-build/scripts/create_conda_env.sh b/skills/rocm-ds-smi-science-tools/install-build/scripts/create_conda_env.sh new file mode 100755 index 0000000..b65a227 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/install-build/scripts/create_conda_env.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# Simple scaffold for conda creation +env_name=${1:-rocm_ds_env} +echo "Creating conda environment: $env_name" +conda create -n "$env_name" python=3.10 -y || echo "Conda not available, fallback to uv" diff --git a/skills/rocm-ds-smi-science-tools/pipeline-integration/SKILL.md b/skills/rocm-ds-smi-science-tools/pipeline-integration/SKILL.md new file mode 100644 index 0000000..eef549c --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/pipeline-integration/SKILL.md @@ -0,0 +1,46 @@ +--- +name: pipeline-integration +description: Guidelines and patterns for integrating multiple ROCm-DS components (hipDF, + hipVS, hipGRAPH, hipRAFT) into a cohesive, end-to-end data science pipeline on AMD + GPUs. Use this skill when building multi-stage workflows that require passing data + efficiently between different ROCm-DS tools. +--- + + +# Purpose + +This skill provides instructions on how to integrate disparate ROCm-DS components into a unified pipeline. It focuses on zero-copy data transfers and consistent environment usage when chaining tools like hipDF (tabular data), hipRAFT (clustering/primitives), and hipVS (vector search). + +# When to use + +- Use when you need to construct a multi-step data science workflow that spans multiple ROCm-DS libraries. +- Use when you need to ensure efficient data handoffs (avoiding GPU-to-CPU-to-GPU copies) between tools. + +# When not to use + +- Do not use when working with a single, isolated ROCm-DS component (refer to specific skills like `hipdf-pandas-port` or `hipraft-primitives` instead). +- Do not use for generic Python scripting unrelated to AMD GPU acceleration. + +# Required inputs + +- Repository path +- Relevant source files containing the pipeline logic +- Target environment facts (ROCm version, available GPUs) +- Desired outcome (e.g., "Build an end-to-end RAG pipeline using hipDF for ETL and hipVS for retrieval") + +# Procedure + +1. **Identify Components**: Determine which ROCm-DS libraries are required for the pipeline (e.g., data loading with hipDF, feature extraction with hipRAFT, indexing with hipVS). +2. **Plan Data Flow**: Map out how data will move between components. Prioritize keeping data on the GPU memory (`__device__` memory) across boundaries. +3. **Implement Integration**: + * Use CuPy or DLPack as the intermediate representation when passing data between components that do not natively support direct handoffs. + * Ensure all components are initialized within the same ROCm stream or context if necessary to avoid synchronization bottlenecks. +4. **Verify**: Test the pipeline with a small dataset to confirm data flows correctly and components interact without crashing. +5. **Benchmark**: Validate the performance to ensure the integrated pipeline is faster than its CPU counterpart and doesn't suffer from excessive memory transfers. + +# Deliverables + +- Concise summary of the pipeline architecture. +- Files changed (pipeline scripts). +- Validation and benchmarking results performed. +- Known limitations or bottlenecks in the integration. diff --git a/skills/rocm-ds-smi-science-tools/pipeline-integration/TOOLING.yaml b/skills/rocm-ds-smi-science-tools/pipeline-integration/TOOLING.yaml new file mode 100644 index 0000000..07d0915 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/pipeline-integration/TOOLING.yaml @@ -0,0 +1,27 @@ +toolification: + callable: true + safe_to_parallelize: false + preferred_runtimes: + - bash + - python + entrypoints: + - SKILL.md + wrappers: + sglang: + tool_name: rocm_ds_skill + mode: routed + io: json + langchain: + tool_name: rocm_ds_skill + mode: structured + io: pydantic + mcp: + tool_name: rocm_ds_skill + mode: stdio + io: jsonrpc + approval_gates: + required_for: + - destructive file changes + - dependency pin changes + - unsupported GPU claims + - benchmark claims without evidence diff --git a/skills/rocm-ds-smi-science-tools/pipeline-integration/examples/end_to_end_pipeline.py b/skills/rocm-ds-smi-science-tools/pipeline-integration/examples/end_to_end_pipeline.py new file mode 100644 index 0000000..94a8e95 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/pipeline-integration/examples/end_to_end_pipeline.py @@ -0,0 +1,59 @@ +# Assuming cudf acts as hipDF in the ROCm environment +try: + import cudf + import cupy as cp +except ImportError: + print( + "Warning: cudf or cupy not found. This script requires a ROCm-DS environment to execute." + ) + + +def run_pipeline(): + """ + Demonstrates a simple end-to-end pipeline integrating ROCm-DS components: + 1. hipDF (cudf) for data loading and ETL. + 2. CuPy for zero-copy data handoff. + 3. Mock hipRAFT/hipVS component for downstream processing. + """ + print("Starting ROCm-DS end-to-end pipeline example...") + + # 1. ETL with hipDF + print("Step 1: Data Loading with hipDF (cudf)...") + try: + # Create a sample dataframe directly on the GPU + df = cudf.DataFrame( + { + "feature1": [1.0, 2.0, 3.0, 4.0, 5.0], + "feature2": [5.0, 4.0, 3.0, 2.0, 1.0], + "label": [0, 1, 0, 1, 0], + } + ) + print(f"Loaded DataFrame shape: {df.shape}") + + # Simple ETL operation + df["combined_feature"] = df["feature1"] * df["feature2"] + + # 2. Zero-copy handoff using DLPack or CuPy + print("Step 2: Zero-copy handoff to CuPy...") + # Extract features for machine learning + features_df = df[["feature1", "feature2", "combined_feature"]] + + # Convert to CuPy array without copying back to host memory + features_cp = cp.from_dlpack(features_df.to_dlpack()) + print(f"CuPy array shape: {features_cp.shape}") + + # 3. Downstream Processing (e.g., hipRAFT clustering or hipVS indexing) + print("Step 3: Downstream processing (Mocking hipRAFT)...") + # In a real scenario, you would pass `features_cp` to a hipRAFT algorithm + # Example: kmeans = hipraft.cluster.KMeans(n_clusters=2); kmeans.fit(features_cp) + + # Performing a simple CuPy operation to represent GPU work + normalized_features = features_cp / cp.linalg.norm(features_cp, axis=0) + print("Pipeline execution completed successfully. Data remained on GPU.") + + except Exception as e: + print(f"Pipeline execution encountered an error: {e}") + + +if __name__ == "__main__": + run_pipeline() diff --git a/skills/rocm-ds-smi-science-tools/tool-router/SKILL.md b/skills/rocm-ds-smi-science-tools/tool-router/SKILL.md new file mode 100644 index 0000000..3d76542 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/tool-router/SKILL.md @@ -0,0 +1,26 @@ +--- +name: tool-router +description: Classifies and routes tasks to the appropriate ROCm-DS component (hipDF, + hipVS, hipGRAPH, hipRAFT, hipMM) based on workload requirements. +--- + + +# Purpose + +Act as the traffic cop to decide which ROCm-DS component applies to a given data science task. + +# When to use + +- When a new ROCm-DS task is received and the specific component is unknown. +- To map a generic request (e.g., "port pandas", "vector search") to a specific subsystem. + +# Procedure + +1. Read the task description and inspect source files if available. +2. Match keywords and operations to ROCm-DS components: + - Tabular ETL / pandas-like ops -> `hipdf-pandas-port` + - Vector search / embeddings / ANN -> `hipvs-ann` + - Community detection / PageRank / graph ops -> `hipgraph-analytics` + - Reusable kernels / clustering / low-level math -> `hipraft-primitives` + - Memory management / OOM issues -> `hipmm-memory-ops` +3. Document the routing decision and rationale. diff --git a/skills/rocm-ds-smi-science-tools/tool-router/TOOLING.yaml b/skills/rocm-ds-smi-science-tools/tool-router/TOOLING.yaml new file mode 100644 index 0000000..07d0915 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/tool-router/TOOLING.yaml @@ -0,0 +1,27 @@ +toolification: + callable: true + safe_to_parallelize: false + preferred_runtimes: + - bash + - python + entrypoints: + - SKILL.md + wrappers: + sglang: + tool_name: rocm_ds_skill + mode: routed + io: json + langchain: + tool_name: rocm_ds_skill + mode: structured + io: pydantic + mcp: + tool_name: rocm_ds_skill + mode: stdio + io: jsonrpc + approval_gates: + required_for: + - destructive file changes + - dependency pin changes + - unsupported GPU claims + - benchmark claims without evidence diff --git a/skills/rocm-ds-smi-science-tools/tool-router/references/rocm-ds-components.md b/skills/rocm-ds-smi-science-tools/tool-router/references/rocm-ds-components.md new file mode 100644 index 0000000..e950c5f --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/tool-router/references/rocm-ds-components.md @@ -0,0 +1,6 @@ +ROCm-DS components: +- hipDF: GPU DataFrames / pandas-like workloads +- hipMM: GPU memory management +- hipGRAPH: graph analytics +- hipRAFT: reusable ML/data science primitives +- hipVS: vector search / ANN diff --git a/skills/rocm-ds-smi-science-tools/tool-router/scripts/route_task.py b/skills/rocm-ds-smi-science-tools/tool-router/scripts/route_task.py new file mode 100755 index 0000000..646bd31 --- /dev/null +++ b/skills/rocm-ds-smi-science-tools/tool-router/scripts/route_task.py @@ -0,0 +1,34 @@ +import sys + + +def route_task(task_description): + task_description = task_description.lower() + if any(kw in task_description for kw in ["pandas", "dataframe", "tabular", "etl"]): + return "hipdf-pandas-port" + elif any( + kw in task_description for kw in ["vector search", "ann", "embedding", "knn"] + ): + return "hipvs-ann" + elif any( + kw in task_description + for kw in ["graph", "pagerank", "community detection", "bfs"] + ): + return "hipgraph-analytics" + elif any( + kw in task_description + for kw in ["clustering", "linear algebra", "primitive", "math"] + ): + return "hipraft-primitives" + elif any( + kw in task_description for kw in ["oom", "memory", "fragmentation", "pool"] + ): + return "hipmm-memory-ops" + else: + return "compatibility-triage" # Default safe fallback + + +if __name__ == "__main__": + if len(sys.argv) > 1: + print(f"Routed to: {route_task(sys.argv[1])}") + else: + print("Please provide a task description.") diff --git a/skills/rocm-vram-profiler-diagnostic/SKILL.md b/skills/rocm-vram-profiler-diagnostic/SKILL.md new file mode 100644 index 0000000..82d2edb --- /dev/null +++ b/skills/rocm-vram-profiler-diagnostic/SKILL.md @@ -0,0 +1,68 @@ +--- +name: rocm-vram-profiler-diagnostic +description: Core runbook for diagnosing memory ceiling limits on AMD's ROCm toolkit natively. Details mitigation parameters and context-limiting configurations explicitly tailored for the Radeon RX 6700 XT. +--- + +# ROCm System & VRAM Diagnostics + +Use this skill when the local LLM processes (vLLM, SGLang, PyTorch code) crash with out-of-memory errors on the AMD hardware, or when assessing parameters prior to model loading. + +## Execution Resources + +This skill bundle includes practical execution resources alongside this file: +- `scripts/monitor-vram.sh`: A wrapper to continuously monitor VRAM limits. +- `examples/vllm-safe-launch.sh`: Reference implementation for safe vLLM memory boundaries. +- `examples/sglang-safe-launch.sh`: Reference implementation for safe SGLang memory boundaries. +- `tests/verify-rocm-smi.sh`: A validation mechanism to ensure ROCm environment availability. + +## 1. Hardware Constriction Assessment + +The target device operates with **12 GB of GDDR6 VRAM**. +- OS Baseline (X11/Wayland + Chrome): ~1.2 GB. +- Container Overhead: ~0.5 GB. +- **Max Theoretical Free Bandwidth:** 10.3 GB. + +This forces a harsh boundary. A common Q5 quantized 8-billion parameter model takes exactly 5.5 to 6.3 GB just to sit idle. This leaves ~4.0 GB for the KV Cache. + +## 2. Debugging Native Commands + +If the user reports system freezing or agents outputting empty blocks, immediately run: +```bash +watch -d -n 1 rocm-smi +``` +*Tip: You can use the provided script at `scripts/monitor-vram.sh` to run this natively.* + +Watch the specific VRAM% output and Memory Temp fields. If VRAM exceeds 98%, the system driver will usually aggressively kill the python interpreter to prevent graphics server crashes. + +## 3. Context Length and KV Cache Slicing + +If generation length causes failure, you must limit the context windows. Memory for text inference works exponentially on context scales. + +**In vLLM Launch Strings:** +1. Decrease the max-model-len: `--max-model-len 4096` instead of `8192`. +2. Apply strict GPU utilization scaling: `--gpu-memory-utilization 0.85` forces the engine to cap RAM limits, returning clean `503 Service Unavailable` instead of halting the root shell. + +**In SGLang Launch Strings:** +```bash +SGLANG_USE_AITER=1 python3 -m sglang.launch_server \ + --model meta-llama/Llama-3-8B-Instruct \ + --dtype float16 \ + # backend unforced — native AITER attention works on patched gfx1030 (SGLANG_USE_AITER=1); + # the old "Aiter does NOT work on RDNA2" claim was false. Keep cuda-graph on triton until the + # aiter+hgb_decode_pool capture lane is wired. + --mem-fraction-static 0.8 \ + --context-length 4096 \ + --host 0.0.0.0 \ + --port 30000 +``` + +## 4. DType Fatalities + +The RX 6700 XT (gfx1030 / RDNA2) lacks the matrix instructions necessary for native `bfloat16`. +If a Python repository forces `bfloat16` under the hood without your knowledge, PyTorch will fallback to incredibly slow emulation modes or instantly crash producing an `Illegal instruction (core dumped)` error. + +Always inject the `--dtype float16` constraint whenever parsing any Transformers-based execution wrapper. + +## Verification + +Before asserting that ROCm constraints are causing the issue or assuming environment capabilities, run `tests/verify-rocm-smi.sh` to check tool availability and current VRAM usage boundaries. diff --git a/skills/rocm-vram-profiler-diagnostic/examples/sglang-safe-launch.sh b/skills/rocm-vram-profiler-diagnostic/examples/sglang-safe-launch.sh new file mode 100755 index 0000000..69616bb --- /dev/null +++ b/skills/rocm-vram-profiler-diagnostic/examples/sglang-safe-launch.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Example: Safe SGLang launch for RX 6700 XT (gfx1030 / RDNA2) +# Mitigation parameters for context-limiting and safe RAM ceilings. +# Native AITER attention WORKS on this patched gfx1030 (enable via SGLANG_USE_AITER=1); the old +# "Aiter does NOT work on RDNA2" note was wrong. Leaving the backend unforced lets sglang prefer +# aiter. (For capture, keep cuda-graph on the triton path until the aiter+hgb_decode_pool lane is wired.) + +echo "Starting SGLang server with strict VRAM mitigations for RDNA2..." + +SGLANG_USE_AITER=1 python3 -m sglang.launch_server \ + --model meta-llama/Llama-3-8B-Instruct \ + --dtype float16 \ + --mem-fraction-static 0.8 \ + --context-length 4096 \ + --host 0.0.0.0 \ + --port 30000 diff --git a/skills/rocm-vram-profiler-diagnostic/examples/vllm-safe-launch.sh b/skills/rocm-vram-profiler-diagnostic/examples/vllm-safe-launch.sh new file mode 100755 index 0000000..f3981c4 --- /dev/null +++ b/skills/rocm-vram-profiler-diagnostic/examples/vllm-safe-launch.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Example: Safe vLLM launch for RX 6700 XT (gfx1030 / RDNA2) +# Mitigation parameters for context-limiting and safe RAM ceilings. + +echo "Starting vLLM server with strict VRAM mitigations for RDNA2..." + +python3 -m vllm.entrypoints.openai.api_server \ + --model meta-llama/Llama-3-8B-Instruct \ + --dtype float16 \ + --max-model-len 4096 \ + --gpu-memory-utilization 0.85 \ + --host 0.0.0.0 \ + --port 8000 diff --git a/skills/rocm-vram-profiler-diagnostic/scripts/monitor-vram.sh b/skills/rocm-vram-profiler-diagnostic/scripts/monitor-vram.sh new file mode 100755 index 0000000..9302dd1 --- /dev/null +++ b/skills/rocm-vram-profiler-diagnostic/scripts/monitor-vram.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Monitor ROCm VRAM usage to detect potential out-of-memory states + +echo "Monitoring ROCm VRAM% output and Memory Temp fields." +echo "Press Ctrl+C to stop." +echo "Note: If VRAM exceeds 98%, the system driver will usually aggressively kill the python interpreter." + +watch -d -n 1 rocm-smi diff --git a/skills/rocm-vram-profiler-diagnostic/tests/verify-rocm-smi.sh b/skills/rocm-vram-profiler-diagnostic/tests/verify-rocm-smi.sh new file mode 100755 index 0000000..1bc5023 --- /dev/null +++ b/skills/rocm-vram-profiler-diagnostic/tests/verify-rocm-smi.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Verify rocm-smi is available in the environment + +echo "Verifying ROCm SMI availability..." + +if command -v rocm-smi >/dev/null 2>&1; then + echo "rocm-smi is installed and available." + rocm-smi --showmeminfo vram + exit 0 +else + echo "Error: rocm-smi is not found in the path. Please ensure ROCm is installed." + exit 1 +fi diff --git a/src/capture_compositor.hip b/src/capture_compositor.hip index c944aa2..ade8b85 100644 --- a/src/capture_compositor.hip +++ b/src/capture_compositor.hip @@ -180,7 +180,14 @@ hipError_t hgb_compose_launch( comp->last_stream = stream; + uint64_t launch_start_ns = hgb_monotonic_ns(); hipError_t err = hipGraphLaunch(comp->exec, stream); + hgb_profiler_record( + HGB_PROFILE_EVENT_COMPOSE_LAUNCH, + hgb_monotonic_ns() - launch_start_ns, + (uint64_t)(uintptr_t)comp->exec, + (uint64_t)comp->num_children + ); if (err != hipSuccess) { return err; } diff --git a/src/compat/cuda_intercept.c b/src/compat/cuda_intercept.c index dda9d20..f9350d3 100644 --- a/src/compat/cuda_intercept.c +++ b/src/compat/cuda_intercept.c @@ -4,32 +4,66 @@ * * Usage: LD_PRELOAD=libcudagraph_compat.so ./my_cuda_app * - * Routes 50 native CUDA Graph APIs to HIP equivalents and - * 4 gap APIs to the bridge library. + * Routes native CUDA Graph APIs to their HIP equivalents and provides + * low-latency pre-buffered pointer-swapping shortcuts to minimize FFI boundary crossings. */ #define _GNU_SOURCE #include +#include #include #include +#include +#include +#include #include #include "hipgraph_bridge.h" -/* Stub typedefs matching CUDA API signatures. - * Real CUDA headers are not available on ROCm systems, - * so we define minimal compatible signatures. */ - +/* Real CUDA headers are not available on ROCm systems, + * so we define compatible types matching the CUDA API signatures. */ typedef hipError_t cudaError_t; typedef hipGraph_t cudaGraph_t; typedef hipGraphExec_t cudaGraphExec_t; typedef hipGraphNode_t cudaGraphNode_t; typedef hipStream_t cudaStream_t; +typedef hipStreamCaptureMode cudaStreamCaptureMode; +typedef hipKernelNodeParams cudaKernelNodeParams; +typedef hipGraphInstantiateParams cudaGraphInstantiateParams; +typedef hipGraphNodeParams cudaGraphNodeParams; + +#define HGB_COMPAT_MAX_GRAPHS 1024 +#define HGB_COMPAT_MAX_CAPTURES 256 + +typedef struct { + cudaGraph_t graph; + cudaGraphExec_t exec; + unsigned long long flags; + cudaStream_t upload_stream; + uint64_t instantiate_seq; + uint64_t launch_count; + int in_use; +} compat_graph_entry_t; + +typedef struct { + cudaStream_t stream; + pthread_t owner; + cudaStreamCaptureMode mode; + int in_use; +} compat_capture_entry_t; static int compat_debug = -1; +static pthread_mutex_t compat_registry_lock = PTHREAD_MUTEX_INITIALIZER; +static compat_graph_entry_t compat_graphs[HGB_COMPAT_MAX_GRAPHS]; +static compat_capture_entry_t compat_captures[HGB_COMPAT_MAX_CAPTURES]; +static uint64_t compat_next_instantiate_seq = 1; +/** + * Internal logger for compatibility transitions. + * Evaluates the debug environment once on first print. + */ static void compat_log(const char* fmt, ...) { if (compat_debug < 0) { const char* dbg = getenv("HGB_DEBUG"); - compat_debug = (dbg && dbg[0] == '1') ? 1 : 0; + compat_debug = (dbg && (dbg[0] == '1' || strcmp(dbg, "debug") == 0)) ? 1 : 0; } if (!compat_debug) return; @@ -41,6 +75,131 @@ static void compat_log(const char* fmt, ...) { va_end(args); } +static void compat_registry_register_exec( + cudaGraph_t graph, + cudaGraphExec_t exec, + unsigned long long flags, + cudaStream_t upload_stream +) { + if (!exec) return; + + pthread_mutex_lock(&compat_registry_lock); + int free_index = -1; + for (int i = 0; i < HGB_COMPAT_MAX_GRAPHS; ++i) { + if (compat_graphs[i].in_use && compat_graphs[i].exec == exec) { + compat_graphs[i].graph = graph; + compat_graphs[i].flags = flags; + compat_graphs[i].upload_stream = upload_stream; + pthread_mutex_unlock(&compat_registry_lock); + return; + } + if (!compat_graphs[i].in_use && free_index < 0) { + free_index = i; + } + } + + if (free_index >= 0) { + compat_graphs[free_index].graph = graph; + compat_graphs[free_index].exec = exec; + compat_graphs[free_index].flags = flags; + compat_graphs[free_index].upload_stream = upload_stream; + compat_graphs[free_index].instantiate_seq = compat_next_instantiate_seq++; + compat_graphs[free_index].launch_count = 0; + compat_graphs[free_index].in_use = 1; + } else { + compat_log("registry full; exec %p is untracked", (void*)exec); + } + pthread_mutex_unlock(&compat_registry_lock); +} + +static void compat_registry_unregister_exec(cudaGraphExec_t exec) { + if (!exec) return; + + pthread_mutex_lock(&compat_registry_lock); + for (int i = 0; i < HGB_COMPAT_MAX_GRAPHS; ++i) { + if (compat_graphs[i].in_use && compat_graphs[i].exec == exec) { + memset(&compat_graphs[i], 0, sizeof(compat_graphs[i])); + break; + } + } + pthread_mutex_unlock(&compat_registry_lock); +} + +static void compat_registry_note_launch(cudaGraphExec_t exec) { + if (!exec) return; + + pthread_mutex_lock(&compat_registry_lock); + for (int i = 0; i < HGB_COMPAT_MAX_GRAPHS; ++i) { + if (compat_graphs[i].in_use && compat_graphs[i].exec == exec) { + compat_graphs[i].launch_count++; + break; + } + } + pthread_mutex_unlock(&compat_registry_lock); +} + +static cudaError_t compat_capture_begin( + cudaStream_t stream, + cudaStreamCaptureMode mode +) { + pthread_mutex_lock(&compat_registry_lock); + int free_index = -1; + for (int i = 0; i < HGB_COMPAT_MAX_CAPTURES; ++i) { + if (compat_captures[i].in_use && compat_captures[i].stream == stream) { + pthread_mutex_unlock(&compat_registry_lock); + compat_log("capture overlap rejected for stream %p", (void*)stream); + return (cudaError_t)hipErrorStreamCaptureMerge; + } + if (!compat_captures[i].in_use && free_index < 0) { + free_index = i; + } + } + if (free_index < 0) { + pthread_mutex_unlock(&compat_registry_lock); + compat_log("capture registry full"); + return (cudaError_t)hipErrorStreamCaptureUnsupported; + } + + cudaError_t err = (cudaError_t)hipStreamBeginCapture((hipStream_t)stream, mode); + if (err == hipSuccess) { + compat_captures[free_index].stream = stream; + compat_captures[free_index].owner = pthread_self(); + compat_captures[free_index].mode = mode; + compat_captures[free_index].in_use = 1; + } + pthread_mutex_unlock(&compat_registry_lock); + return err; +} + +static cudaError_t compat_capture_end(cudaStream_t stream, cudaGraph_t* graph) { + pthread_mutex_lock(&compat_registry_lock); + int index = -1; + for (int i = 0; i < HGB_COMPAT_MAX_CAPTURES; ++i) { + if (compat_captures[i].in_use && compat_captures[i].stream == stream) { + index = i; + break; + } + } + if (index < 0) { + pthread_mutex_unlock(&compat_registry_lock); + compat_log("capture end without matching begin for stream %p", (void*)stream); + return (cudaError_t)hipErrorStreamCaptureUnmatched; + } + if (!pthread_equal(compat_captures[index].owner, pthread_self())) { + pthread_mutex_unlock(&compat_registry_lock); + compat_log("capture end from wrong thread for stream %p", (void*)stream); + return (cudaError_t)hipErrorStreamCaptureWrongThread; + } + + cudaError_t err = (cudaError_t)hipStreamEndCapture((hipStream_t)stream, (hipGraph_t*)graph); + if (err == hipSuccess || err == hipErrorStreamCaptureInvalidated || + err == hipErrorStreamCaptureUnmatched) { + memset(&compat_captures[index], 0, sizeof(compat_captures[index])); + } + pthread_mutex_unlock(&compat_registry_lock); + return err; +} + /* ── 1:1 Native Mappings ────────────────────────────── */ cudaError_t cudaGraphCreate(cudaGraph_t* graph, unsigned int flags) { @@ -58,20 +217,60 @@ cudaError_t cudaGraphInstantiate( void* errNode, char* logBuf, size_t logLen ) { compat_log("cudaGraphInstantiate → hipGraphInstantiate"); - return (cudaError_t)hipGraphInstantiate( + cudaError_t err = (cudaError_t)hipGraphInstantiate( (hipGraphExec_t*)exec, (hipGraph_t)graph, (hipGraphNode_t*)errNode, logBuf, logLen ); + if (err == hipSuccess && exec) { + compat_registry_register_exec(graph, *exec, 0, NULL); + } + return err; +} + +cudaError_t cudaGraphInstantiateWithFlags( + cudaGraphExec_t* exec, cudaGraph_t graph, unsigned long long flags +) { + compat_log("cudaGraphInstantiateWithFlags → hipGraphInstantiateWithFlags flags=%llu", flags); + cudaError_t err = (cudaError_t)hipGraphInstantiateWithFlags( + (hipGraphExec_t*)exec, (hipGraph_t)graph, flags + ); + if (err == hipSuccess && exec) { + compat_registry_register_exec(graph, *exec, flags, NULL); + } + return err; +} + +cudaError_t cudaGraphInstantiateWithParams( + cudaGraphExec_t* exec, cudaGraph_t graph, cudaGraphInstantiateParams* params +) { + compat_log("cudaGraphInstantiateWithParams → hipGraphInstantiateWithParams"); + cudaError_t err = (cudaError_t)hipGraphInstantiateWithParams( + (hipGraphExec_t*)exec, (hipGraph_t)graph, (hipGraphInstantiateParams*)params + ); + if (err == hipSuccess && exec) { + unsigned long long flags = params ? params->flags : 0; + cudaStream_t upload_stream = params ? (cudaStream_t)params->uploadStream : NULL; + compat_registry_register_exec(graph, *exec, flags, upload_stream); + } + return err; } cudaError_t cudaGraphLaunch(cudaGraphExec_t exec, cudaStream_t stream) { compat_log("cudaGraphLaunch → hipGraphLaunch"); - return (cudaError_t)hipGraphLaunch((hipGraphExec_t)exec, (hipStream_t)stream); + cudaError_t err = (cudaError_t)hipGraphLaunch((hipGraphExec_t)exec, (hipStream_t)stream); + if (err == hipSuccess) { + compat_registry_note_launch(exec); + } + return err; } cudaError_t cudaGraphExecDestroy(cudaGraphExec_t exec) { compat_log("cudaGraphExecDestroy → hipGraphExecDestroy"); - return (cudaError_t)hipGraphExecDestroy((hipGraphExec_t)exec); + cudaError_t err = (cudaError_t)hipGraphExecDestroy((hipGraphExec_t)exec); + if (err == hipSuccess) { + compat_registry_unregister_exec(exec); + } + return err; } cudaError_t cudaGraphUpload(cudaGraphExec_t exec, cudaStream_t stream) { @@ -79,20 +278,84 @@ cudaError_t cudaGraphUpload(cudaGraphExec_t exec, cudaStream_t stream) { return (cudaError_t)hipGraphUpload((hipGraphExec_t)exec, (hipStream_t)stream); } -/* ── Additional native mappings follow the same pattern ── */ -/* TODO: Add remaining ~44 native 1:1 mappings */ +cudaError_t cudaGraphAddKernelNode( + cudaGraphNode_t* pGraphNode, cudaGraph_t graph, + const cudaGraphNode_t* pDependencies, size_t numDependencies, + const cudaKernelNodeParams* pNodeParams +) { + compat_log("cudaGraphAddKernelNode → hipGraphAddKernelNode"); + return (cudaError_t)hipGraphAddKernelNode( + (hipGraphNode_t*)pGraphNode, (hipGraph_t)graph, + (const hipGraphNode_t*)pDependencies, numDependencies, + (const hipKernelNodeParams*)pNodeParams + ); +} + +cudaError_t cudaGraphAddChildGraphNode( + cudaGraphNode_t* pGraphNode, cudaGraph_t graph, + const cudaGraphNode_t* pDependencies, size_t numDependencies, + cudaGraph_t childGraph +) { + compat_log("cudaGraphAddChildGraphNode → hipGraphAddChildGraphNode"); + return (cudaError_t)hipGraphAddChildGraphNode( + (hipGraphNode_t*)pGraphNode, (hipGraph_t)graph, + (const hipGraphNode_t*)pDependencies, numDependencies, + (hipGraph_t)childGraph + ); +} + +cudaError_t cudaGraphExecNodeSetParams( + cudaGraphExec_t hGraphExec, cudaGraphNode_t node, + cudaGraphNodeParams* nodeParams +) { + compat_log("cudaGraphExecNodeSetParams → hipGraphExecNodeSetParams"); + return (cudaError_t)hipGraphExecNodeSetParams( + (hipGraphExec_t)hGraphExec, (hipGraphNode_t)node, + (hipGraphNodeParams*)nodeParams + ); +} + +cudaError_t cudaGraphExecKernelNodeSetParams( + cudaGraphExec_t hGraphExec, cudaGraphNode_t node, + const cudaKernelNodeParams* pNodeParams +) { + compat_log("cudaGraphExecKernelNodeSetParams → hipGraphExecKernelNodeSetParams"); + return (cudaError_t)hipGraphExecKernelNodeSetParams( + (hipGraphExec_t)hGraphExec, (hipGraphNode_t)node, + (const hipKernelNodeParams*)pNodeParams + ); +} + +cudaError_t cudaGraphExecChildGraphNodeSetParams( + cudaGraphExec_t hGraphExec, cudaGraphNode_t node, + cudaGraph_t childGraph +) { + compat_log("cudaGraphExecChildGraphNodeSetParams → hipGraphExecChildGraphNodeSetParams"); + return (cudaError_t)hipGraphExecChildGraphNodeSetParams( + (hipGraphExec_t)hGraphExec, (hipGraphNode_t)node, (hipGraph_t)childGraph + ); +} -/* ── Gap Bridges (routed to Layer 1) ────────────────── */ +cudaError_t cudaGraphNodeSetEnabled( + cudaGraphExec_t hGraphExec, cudaGraphNode_t node, unsigned int isEnabled +) { + compat_log("cudaGraphNodeSetEnabled → hipGraphNodeSetEnabled"); + return (cudaError_t)hipGraphNodeSetEnabled( + (hipGraphExec_t)hGraphExec, (hipGraphNode_t)node, isEnabled + ); +} -/* Gap 51: Conditional — no direct CUDA equivalent mapping possible - * without full conditional handle infrastructure. Log and return error - * for now; users should use the Python bridge layer for this gap. */ +cudaError_t cudaStreamBeginCapture(cudaStream_t stream, cudaStreamCaptureMode mode) { + compat_log("cudaStreamBeginCapture → hipStreamBeginCapture"); + return compat_capture_begin(stream, mode); +} -/* Gap 52: Device launch flag is intercepted at instantiate level */ -/* TODO: Detect cudaGraphInstantiateFlagDeviceLaunch and route to - * hgb_pipeline_create */ +cudaError_t cudaStreamEndCapture(cudaStream_t stream, cudaGraph_t* pGraph) { + compat_log("cudaStreamEndCapture → hipStreamEndCapture"); + return compat_capture_end(stream, pGraph); +} -/* ── Initialization ─────────────────────────────────── */ +/* ── Constructor/Destructor hooks ───────────────────── */ __attribute__((constructor)) static void compat_init(void) { diff --git a/src/decode_pool.hip b/src/decode_pool.hip new file mode 100644 index 0000000..afd6c69 --- /dev/null +++ b/src/decode_pool.hip @@ -0,0 +1,230 @@ +/** + * @file decode_pool.hip + * @brief Capture-safe paged-decode pool — fixes decode-attention-under-hipGraph garble. + * + * The "aiter garbles under gfxGRAPH capture" report is decode-attn-under-graph REPLAY-DATA-UNSAFETY, + * not JIT-during-capture: a captured decode graph that bakes the per-step sequence length / block + * table BY VALUE attends the capture-time length on every replay, so output garbles as the sequence + * grows. (Confirmed on gfx1030: a stale-metadata replay tracks the capture-time answer; refreshing the + * persistent device buffer in place makes the same captured graph bit-exact at the live length.) + * + * This pool owns PERSISTENT device metadata buffers (seq_lens, block_tables) at fixed addresses. Each + * bucket's captured graph reads those buffers; replay = memcpy(live -> persistent) + hipGraphLaunch. + * No hipGraphExec*SetParams is needed — the kernel-node pointer args never change, only the buffer + * CONTENTS, so the captured node reads fresh data each replay. One graph per bucket (bucket-constant + * max-seq-len) replays correctly for every step. This wires the previously-vestigial + * hgb_shape_pool_t::static_bufs idea (allocated-but-never-written) the correct way. + * + * Mirrors shape_manager.hip's per-object-mutex thread-safety and event-tracked in-flight handling. + */ +#include "hipgraph_bridge.h" +#include +#include + +extern "C" void hgb_log(const char* fmt, ...); +extern "C" int hgb_is_initialized(void); + +namespace { + +struct DecodeMutexGuard { + pthread_mutex_t* m; + DecodeMutexGuard(pthread_mutex_t* mtx) : m(mtx) { pthread_mutex_lock(m); } + ~DecodeMutexGuard() { pthread_mutex_unlock(m); } +}; + +void decode_destroy_event(hipEvent_t* event) { + if (event && *event) { + hipEventDestroy(*event); + *event = nullptr; + } +} + +} // namespace + +hipError_t hgb_decode_pool_create( + hgb_decode_capture_fn fn, + void* ctx, + const int* buckets, + int num_buckets, + int max_num_seqs, + int max_blocks_per_seq, + hgb_decode_pool_t* out +) { + if (!hgb_is_initialized()) return hipErrorNotInitialized; + if (!fn || !buckets || num_buckets <= 0 || max_num_seqs <= 0 || max_blocks_per_seq <= 0 || !out) + return hipErrorInvalidValue; + + if (num_buckets > HGB_MAX_BUCKETS) { + hgb_log("ERROR: decode num_buckets %d exceeds max %d", num_buckets, HGB_MAX_BUCKETS); + return hipErrorInvalidValue; + } + + /* Buckets strictly ascending and positive (smallest-bucket-ge-size selection depends on it). */ + for (int i = 0; i < num_buckets; i++) { + if (buckets[i] <= 0) { + hgb_log("ERROR: decode bucket[%d] = %d must be positive", i, buckets[i]); + return hipErrorInvalidValue; + } + if (i > 0 && buckets[i] <= buckets[i - 1]) { + hgb_log("ERROR: decode buckets not ascending: [%d]=%d <= [%d]=%d", + i, buckets[i], i - 1, buckets[i - 1]); + return hipErrorInvalidValue; + } + } + + memset(out, 0, sizeof(*out)); + pthread_mutex_init(&out->lock, nullptr); + out->num_buckets = num_buckets; + out->max_num_seqs = max_num_seqs; + out->max_blocks_per_seq = max_blocks_per_seq; + hipGetDevice(&out->device_id); + + out->bucket_sizes = (int*)malloc(num_buckets * sizeof(int)); + out->graphs = (hipGraph_t*)calloc(num_buckets, sizeof(hipGraph_t)); + out->execs = (hipGraphExec_t*)calloc(num_buckets, sizeof(hipGraphExec_t)); + out->events = (hipEvent_t*)calloc(num_buckets, sizeof(hipEvent_t)); + if (!out->bucket_sizes || !out->graphs || !out->execs || !out->events) { + hgb_decode_pool_destroy(out); + return hipErrorOutOfMemory; + } + memcpy(out->bucket_sizes, buckets, num_buckets * sizeof(int)); + + /* Persistent metadata buffers — captured graphs read these by pointer; replay refreshes contents. */ + if (hipMalloc((void**)&out->d_seq_lens, (size_t)max_num_seqs * sizeof(int)) != hipSuccess) { + hgb_decode_pool_destroy(out); + return hipErrorOutOfMemory; + } + if (hipMalloc((void**)&out->d_block_tables, + (size_t)max_num_seqs * max_blocks_per_seq * sizeof(int)) != hipSuccess) { + hgb_decode_pool_destroy(out); + return hipErrorOutOfMemory; + } + hipMemset(out->d_seq_lens, 0, (size_t)max_num_seqs * sizeof(int)); + hipMemset(out->d_block_tables, 0, (size_t)max_num_seqs * max_blocks_per_seq * sizeof(int)); + + /* Capture + instantiate one graph per bucket, each reading the SAME persistent buffers. */ + for (int i = 0; i < num_buckets; i++) { + hgb_log("Capturing decode graph for bucket (max_seq_len) %d", buckets[i]); + + hipError_t err = fn(buckets[i], out->d_seq_lens, out->d_block_tables, &out->graphs[i], ctx); + if (err != hipSuccess) { + hgb_log("Decode capture failed for bucket %d: %d", buckets[i], (int)err); + hgb_decode_pool_destroy(out); + return err; + } + err = hipGraphInstantiate(&out->execs[i], out->graphs[i], nullptr, nullptr, 0); + if (err != hipSuccess) { + hgb_log("Decode instantiate failed for bucket %d: %d", buckets[i], (int)err); + hgb_decode_pool_destroy(out); + return err; + } + err = hipEventCreateWithFlags(&out->events[i], hipEventDisableTiming); + if (err != hipSuccess) { + hgb_log("Decode event create failed for bucket %d: %d", buckets[i], (int)err); + hgb_decode_pool_destroy(out); + return err; + } + } + + hgb_log("Decode pool created: %d buckets [%d..%d], max_num_seqs=%d max_blocks_per_seq=%d", + num_buckets, buckets[0], buckets[num_buckets - 1], max_num_seqs, max_blocks_per_seq); + return hipSuccess; +} + +hipError_t hgb_decode_pool_replay( + hgb_decode_pool_t* pool, + int input_size, + const int* h_seq_lens, + int num_seqs, + const int* h_block_tables, + hipStream_t stream, + int* actual_bucket +) { + if (!hgb_is_initialized()) return hipErrorNotInitialized; + if (!pool || !pool->execs || !h_seq_lens || input_size <= 0 || num_seqs <= 0) + return hipErrorInvalidValue; + if (num_seqs > pool->max_num_seqs) { + hgb_log("ERROR: decode replay num_seqs %d exceeds max_num_seqs %d", num_seqs, pool->max_num_seqs); + return hipErrorInvalidValue; + } + + DecodeMutexGuard guard(&pool->lock); + + int cur_dev; + hipGetDevice(&cur_dev); + if (cur_dev != pool->device_id) { + hgb_log("ERROR: decode pool on device %d, current is %d", pool->device_id, cur_dev); + return hipErrorInvalidDevice; + } + + /* Binary search for smallest bucket >= input_size. */ + int lo = 0, hi = pool->num_buckets - 1, best = -1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (pool->bucket_sizes[mid] >= input_size) { best = mid; hi = mid - 1; } + else { lo = mid + 1; } + } + if (best < 0) { + hgb_log("Decode input size %d exceeds largest bucket %d", + input_size, pool->bucket_sizes[pool->num_buckets - 1]); + return hipErrorInvalidValue; + } + if (actual_bucket) *actual_bucket = pool->bucket_sizes[best]; + + /* Refresh the persistent metadata IN PLACE on the launch stream (ordered before the graph). This + * is the fix: the captured graph reads these device buffers, so fresh contents => correct replay. */ + hipError_t err = hipMemcpyAsync(pool->d_seq_lens, h_seq_lens, (size_t)num_seqs * sizeof(int), + hipMemcpyHostToDevice, stream); + if (err != hipSuccess) return err; + if (h_block_tables) { + err = hipMemcpyAsync(pool->d_block_tables, h_block_tables, + (size_t)num_seqs * pool->max_blocks_per_seq * sizeof(int), + hipMemcpyHostToDevice, stream); + if (err != hipSuccess) return err; + } + + err = hipGraphLaunch(pool->execs[best], stream); + if (err != hipSuccess) return err; + + /* Record completion so a later replay/destroy can sync before reusing the persistent buffers. */ + if (pool->events && pool->events[best]) { + hipError_t rec = hipEventRecord(pool->events[best], stream); + if (rec != hipSuccess) { + hgb_log("WARNING: decode event record for bucket %d failed: %d", best, (int)rec); + decode_destroy_event(&pool->events[best]); + } + } + return hipSuccess; +} + +void hgb_decode_pool_destroy(hgb_decode_pool_t* pool) { + if (!pool) return; + + pthread_mutex_lock(&pool->lock); + + if (pool->device_id >= 0) { + int prev_dev; + hipGetDevice(&prev_dev); + if (prev_dev != pool->device_id) hipSetDevice(pool->device_id); + hipDeviceSynchronize(); + if (prev_dev != pool->device_id) hipSetDevice(prev_dev); + } + + for (int i = 0; i < pool->num_buckets; i++) { + if (pool->events) decode_destroy_event(&pool->events[i]); + if (pool->execs && pool->execs[i]) hipGraphExecDestroy(pool->execs[i]); + if (pool->graphs && pool->graphs[i]) hipGraphDestroy(pool->graphs[i]); + } + if (pool->d_seq_lens) hipFree(pool->d_seq_lens); + if (pool->d_block_tables) hipFree(pool->d_block_tables); + + free(pool->bucket_sizes); + free(pool->graphs); + free(pool->execs); + free(pool->events); + memset(pool, 0, sizeof(*pool)); + pool->device_id = -1; + + pthread_mutex_unlock(&pool->lock); + pthread_mutex_destroy(&pool->lock); +} diff --git a/src/launch_pipeline.hip b/src/launch_pipeline.hip index d7b39da..ae1d69a 100644 --- a/src/launch_pipeline.hip +++ b/src/launch_pipeline.hip @@ -61,7 +61,14 @@ hipError_t hgb_pipeline_create( return err; } + uint64_t upload_start_ns = hgb_monotonic_ns(); err = hipGraphUpload(out->exec[0], out->stream); + hgb_profiler_record( + HGB_PROFILE_EVENT_PIPELINE_UPLOAD, + hgb_monotonic_ns() - upload_start_ns, + (uint64_t)(uintptr_t)out->exec[0], + 0 + ); if (err == hipSuccess) { out->state[0] = HGB_EXEC_UPLOADED; } else { @@ -70,6 +77,12 @@ hipError_t hgb_pipeline_create( out->active = 0; out->launched = 0; + hgb_profiler_record( + HGB_PROFILE_EVENT_PIPELINE_CREATE, + 0, + (uint64_t)(uintptr_t)graph, + 2 + ); hgb_log("Pipeline created: serialized double-buffer, event-tracked"); return hipSuccess; } @@ -106,7 +119,14 @@ hipError_t hgb_pipeline_launch(hgb_pipeline_t* pipe) { } } + uint64_t launch_start_ns = hgb_monotonic_ns(); hipError_t err = hipGraphLaunch(pipe->exec[cur], pipe->stream); + hgb_profiler_record( + HGB_PROFILE_EVENT_PIPELINE_LAUNCH, + hgb_monotonic_ns() - launch_start_ns, + (uint64_t)(uintptr_t)pipe->exec[cur], + (uint64_t)cur + ); if (err != hipSuccess) return err; err = hipEventRecord(pipe->event, pipe->stream); @@ -143,15 +163,32 @@ hipError_t hgb_pipeline_update_kernel( int target = pipe->active; + uint64_t update_start_ns = hgb_monotonic_ns(); hipError_t err = hipGraphExecKernelNodeSetParams( pipe->exec[target], node, params ); + hgb_profiler_record( + HGB_PROFILE_EVENT_PIPELINE_UPDATE, + hgb_monotonic_ns() - update_start_ns, + (uint64_t)(uintptr_t)node, + (uint64_t)target + ); if (err != hipSuccess) return err; pipe->state[target] = HGB_EXEC_IDLE; return hipSuccess; } +hipError_t hgb_pipeline_update_and_launch( + hgb_pipeline_t* pipe, + hipGraphNode_t node, + hipKernelNodeParams* params +) { + hipError_t err = hgb_pipeline_update_kernel(pipe, node, params); + if (err != hipSuccess) return err; + return hgb_pipeline_launch(pipe); +} + void hgb_pipeline_destroy(hgb_pipeline_t* pipe) { if (!pipe) return; diff --git a/src/profiler.cpp b/src/profiler.cpp new file mode 100644 index 0000000..becf0bd --- /dev/null +++ b/src/profiler.cpp @@ -0,0 +1,113 @@ +/** + * @file profiler.cpp + * @brief Low-overhead native telemetry for gfxGRAPH runtime paths. + */ +#include "hipgraph_bridge.h" + +#include +#include +#include +#include + +namespace { + +struct ProfileSlot { + std::atomic published_seq; + hgb_profile_sample_t sample; +}; + +std::array g_slots{}; +std::atomic g_next_seq{1}; +std::atomic g_dropped{0}; + +uint32_t current_device_id() { + int device = -1; + if (hipGetDevice(&device) != hipSuccess || device < 0) { + return UINT32_MAX; + } + return static_cast(device); +} + +} // namespace + +extern "C" HGB_EXPORT uint64_t hgb_monotonic_ns(void) { + using clock = std::chrono::steady_clock; + return static_cast( + std::chrono::duration_cast( + clock::now().time_since_epoch() + ).count() + ); +} + +extern "C" HGB_EXPORT void hgb_profiler_reset(void) { + for (auto& slot : g_slots) { + slot.published_seq.store(0, std::memory_order_release); + std::memset(&slot.sample, 0, sizeof(slot.sample)); + } + g_next_seq.store(1, std::memory_order_release); + g_dropped.store(0, std::memory_order_release); +} + +extern "C" HGB_EXPORT uint64_t hgb_profiler_record( + uint32_t event, + uint64_t duration_ns, + uint64_t value0, + uint64_t value1 +) { + const uint64_t seq = g_next_seq.fetch_add(1, std::memory_order_acq_rel); + const uint64_t index = (seq - 1) % HGB_PROFILER_CAPACITY; + + if (seq > HGB_PROFILER_CAPACITY) { + g_dropped.fetch_add(1, std::memory_order_relaxed); + } + + hgb_profile_sample_t sample{}; + sample.seq = seq; + sample.timestamp_ns = hgb_monotonic_ns(); + sample.duration_ns = duration_ns; + sample.value0 = value0; + sample.value1 = value1; + sample.event = event; + sample.device_id = current_device_id(); + sample.stream_id = 0; + sample.flags = 0; + + g_slots[index].sample = sample; + g_slots[index].published_seq.store(seq, std::memory_order_release); + return seq; +} + +extern "C" HGB_EXPORT size_t hgb_profiler_snapshot( + hgb_profile_sample_t* out, + size_t max_samples, + hgb_profile_counters_t* counters +) { + const uint64_t next_seq = g_next_seq.load(std::memory_order_acquire); + const uint64_t written = next_seq > 0 ? next_seq - 1 : 0; + const uint64_t available = + written < HGB_PROFILER_CAPACITY ? written : HGB_PROFILER_CAPACITY; + const uint64_t to_copy = + max_samples < available ? max_samples : available; + const uint64_t first_seq = written >= to_copy ? written - to_copy + 1 : 1; + + if (counters) { + counters->written = written; + counters->dropped = g_dropped.load(std::memory_order_acquire); + counters->capacity = HGB_PROFILER_CAPACITY; + } + + if (!out || max_samples == 0 || to_copy == 0) { + return 0; + } + + size_t copied = 0; + for (uint64_t seq = first_seq; seq <= written; ++seq) { + const uint64_t index = (seq - 1) % HGB_PROFILER_CAPACITY; + const uint64_t published = + g_slots[index].published_seq.load(std::memory_order_acquire); + if (published == seq) { + out[copied++] = g_slots[index].sample; + } + } + return copied; +} diff --git a/src/runtime_handles.cpp b/src/runtime_handles.cpp new file mode 100644 index 0000000..7837f1b --- /dev/null +++ b/src/runtime_handles.cpp @@ -0,0 +1,178 @@ +/** + * @file runtime_handles.cpp + * @brief Opaque C ABI handles for native graph execution. + */ +#include "hipgraph_bridge.h" + +#include +#include + +struct hgb_pipeline_handle { + hgb_pipeline_t pipeline; +}; + +struct hgb_composed_graph_handle { + hgb_composed_graph_t composed; +}; + +struct hgb_decode_pool_handle { + hgb_decode_pool_t pool; +}; + +extern "C" HGB_EXPORT hipError_t hgb_pipeline_handle_create( + hipGraph_t graph, + hgb_pipeline_handle_t** out +) { + if (!out) return hipErrorInvalidValue; + *out = nullptr; + + auto* handle = static_cast( + std::calloc(1, sizeof(hgb_pipeline_handle_t)) + ); + if (!handle) return hipErrorOutOfMemory; + + hipError_t err = hgb_pipeline_create(graph, &handle->pipeline); + if (err != hipSuccess) { + std::free(handle); + return err; + } + + *out = handle; + return hipSuccess; +} + +extern "C" HGB_EXPORT hipError_t hgb_pipeline_handle_launch( + hgb_pipeline_handle_t* handle +) { + if (!handle) return hipErrorInvalidValue; + return hgb_pipeline_launch(&handle->pipeline); +} + +extern "C" HGB_EXPORT hipError_t hgb_pipeline_handle_update_kernel( + hgb_pipeline_handle_t* handle, + hipGraphNode_t node, + hipKernelNodeParams* params +) { + if (!handle) return hipErrorInvalidValue; + return hgb_pipeline_update_kernel(&handle->pipeline, node, params); +} + +extern "C" HGB_EXPORT hipError_t hgb_pipeline_handle_update_and_launch( + hgb_pipeline_handle_t* handle, + hipGraphNode_t node, + hipKernelNodeParams* params +) { + if (!handle) return hipErrorInvalidValue; + return hgb_pipeline_update_and_launch(&handle->pipeline, node, params); +} + +extern "C" HGB_EXPORT void hgb_pipeline_handle_destroy( + hgb_pipeline_handle_t* handle +) { + if (!handle) return; + hgb_pipeline_destroy(&handle->pipeline); + std::free(handle); +} + +extern "C" HGB_EXPORT hipError_t hgb_composed_handle_create( + hipGraph_t* sub_graphs, + int count, + const int* deps, + hgb_composed_graph_handle_t** out +) { + if (!out) return hipErrorInvalidValue; + *out = nullptr; + + auto* handle = static_cast( + std::calloc(1, sizeof(hgb_composed_graph_handle_t)) + ); + if (!handle) return hipErrorOutOfMemory; + + hipError_t err = hgb_compose_graphs(sub_graphs, count, deps, &handle->composed); + if (err != hipSuccess) { + std::free(handle); + return err; + } + + *out = handle; + return hipSuccess; +} + +extern "C" HGB_EXPORT hipError_t hgb_composed_handle_launch( + hgb_composed_graph_handle_t* handle, + hipStream_t stream +) { + if (!handle) return hipErrorInvalidValue; + return hgb_compose_launch(&handle->composed, stream); +} + +extern "C" HGB_EXPORT hipError_t hgb_composed_handle_update_child( + hgb_composed_graph_handle_t* handle, + int child_index, + hipGraph_t new_sub_graph +) { + if (!handle) return hipErrorInvalidValue; + return hgb_compose_update_child(&handle->composed, child_index, new_sub_graph); +} + +extern "C" HGB_EXPORT void hgb_composed_handle_destroy( + hgb_composed_graph_handle_t* handle +) { + if (!handle) return; + hgb_compose_destroy(&handle->composed); + std::free(handle); +} + +/* ── Capture-safe decode pool (opaque handle) ─────────── */ + +extern "C" HGB_EXPORT hipError_t hgb_decode_pool_handle_create( + hgb_decode_capture_fn fn, + void* ctx, + const int* buckets, + int num_buckets, + int max_num_seqs, + int max_blocks_per_seq, + hgb_decode_pool_handle_t** out +) { + if (!out) return hipErrorInvalidValue; + *out = nullptr; + + auto* handle = static_cast( + std::calloc(1, sizeof(hgb_decode_pool_handle_t)) + ); + if (!handle) return hipErrorOutOfMemory; + + hipError_t err = hgb_decode_pool_create( + fn, ctx, buckets, num_buckets, max_num_seqs, max_blocks_per_seq, &handle->pool + ); + if (err != hipSuccess) { + std::free(handle); + return err; + } + + *out = handle; + return hipSuccess; +} + +extern "C" HGB_EXPORT hipError_t hgb_decode_pool_handle_replay( + hgb_decode_pool_handle_t* handle, + int input_size, + const int* h_seq_lens, + int num_seqs, + const int* h_block_tables, + hipStream_t stream, + int* actual_bucket +) { + if (!handle) return hipErrorInvalidValue; + return hgb_decode_pool_replay( + &handle->pool, input_size, h_seq_lens, num_seqs, h_block_tables, stream, actual_bucket + ); +} + +extern "C" HGB_EXPORT void hgb_decode_pool_handle_destroy( + hgb_decode_pool_handle_t* handle +) { + if (!handle) return; + hgb_decode_pool_destroy(&handle->pool); + std::free(handle); +} diff --git a/src/shape_manager.hip b/src/shape_manager.hip index edb3a03..9cfc106 100644 --- a/src/shape_manager.hip +++ b/src/shape_manager.hip @@ -166,7 +166,14 @@ hipError_t hgb_shape_pool_launch( input_size, pool->bucket_sizes[best], best, pool->bucket_sizes[best] - input_size); + uint64_t launch_start_ns = hgb_monotonic_ns(); hipError_t err = hipGraphLaunch(pool->execs[best], stream); + hgb_profiler_record( + HGB_PROFILE_EVENT_SHAPE_LAUNCH, + hgb_monotonic_ns() - launch_start_ns, + (uint64_t)input_size, + (uint64_t)pool->bucket_sizes[best] + ); if (err != hipSuccess) return err; err = ensure_bucket_event(pool, best); diff --git a/tests/test_decode.hip b/tests/test_decode.hip new file mode 100644 index 0000000..685aabb --- /dev/null +++ b/tests/test_decode.hip @@ -0,0 +1,150 @@ +/** + * @file test_decode.hip + * @brief Capture-safe decode pool (hgb_decode_pool_*) — proves the fix for the + * decode-attn-under-hipGraph garble. + * + * A captured decode graph reads the pool's PERSISTENT device metadata buffers (seq_lens, + * block_tables). We capture ONE graph per bucket, then replay the SAME bucket graph at two different + * sequence lengths by refreshing seq_lens in place — and assert the output is correct at BOTH lengths + * (length-dependent), with a negative control that the two lengths genuinely differ. If the captured + * graph baked the length, the second replay would garble (track the first length). + */ +#include "hipgraph_bridge.h" +#include +#include +#include +#include + +// One thread per sequence. Walks the block table for `len` logical positions (len read from the +// DEVICE seq_lens buffer — not a launch arg) and sums the gathered content. With content==1.0 the +// result is exactly the (clamped) sequence length, so a stale-length replay is detectable. +__global__ void decode_sum_kernel(float* out, const float* content, const int* d_seq_lens, + const int* d_block_tables, int max_blocks_per_seq, int page_size, + int max_seq_len) { + int seq = blockIdx.x * blockDim.x + threadIdx.x; + int len = d_seq_lens[seq]; + if (len > max_seq_len) len = max_seq_len; // bucket clamp (mirrors real partition sizing) + float acc = 0.f; + for (int s = 0; s < len; s++) { + int blk = s / page_size; + int slot = s % page_size; + int phys = d_block_tables[seq * max_blocks_per_seq + blk]; + acc += content[phys * page_size + slot]; + } + out[seq] = acc; +} + +struct DecodeCtx { + float* out; + float* content; + int max_num_seqs; + int max_blocks_per_seq; + int page_size; +}; + +static hipError_t capture_decode(int bucket_max, const int* d_seq_lens, const int* d_block_tables, + hipGraph_t* graph, void* ctxv) { + DecodeCtx* c = (DecodeCtx*)ctxv; + hipStream_t stream; + hipStreamCreate(&stream); + hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal); + // grid = max_num_seqs threads (constant — capture-safe); reads the persistent metadata by pointer. + decode_sum_kernel<<<1, c->max_num_seqs, 0, stream>>>( + c->out, c->content, d_seq_lens, d_block_tables, + c->max_blocks_per_seq, c->page_size, bucket_max); + hipStreamEndCapture(stream, graph); + hipStreamDestroy(stream); + return hipSuccess; +} + +int main() { + printf("=== test_decode (capture-safe decode pool) ===\n"); + hipError_t err = hgb_init(); + assert(err == hipSuccess); + + const int MAX_NUM_SEQS = 4; + const int MAX_BLOCKS = 8; + const int PAGE_SIZE = 16; + const int NUM_PAGES = MAX_NUM_SEQS * MAX_BLOCKS; // distinct physical page per (seq, blk) + + // content == 1.0 everywhere -> out[seq] == (clamped) seq_len[seq]. + float* d_content; + hipMalloc(&d_content, (size_t)NUM_PAGES * PAGE_SIZE * sizeof(float)); + { + int n = NUM_PAGES * PAGE_SIZE; + float* h = (float*)malloc(n * sizeof(float)); + for (int i = 0; i < n; i++) h[i] = 1.0f; + hipMemcpy(d_content, h, (size_t)n * sizeof(float), hipMemcpyHostToDevice); + free(h); + } + float* d_out; + hipMalloc(&d_out, MAX_NUM_SEQS * sizeof(float)); + + DecodeCtx ctx{ d_out, d_content, MAX_NUM_SEQS, MAX_BLOCKS, PAGE_SIZE }; + + int buckets[] = {32, 64, 128}; + hgb_decode_pool_t pool; + err = hgb_decode_pool_create(capture_decode, &ctx, buckets, 3, MAX_NUM_SEQS, MAX_BLOCKS, &pool); + assert(err == hipSuccess); + printf(" Created decode pool: %d buckets, max_num_seqs=%d\n", pool.num_buckets, pool.max_num_seqs); + + // Identity-ish block table: logical (seq, blk) -> distinct physical page. num_seqs == MAX_NUM_SEQS. + int bt[MAX_NUM_SEQS * MAX_BLOCKS]; + for (int s = 0; s < MAX_NUM_SEQS; s++) + for (int b = 0; b < MAX_BLOCKS; b++) + bt[s * MAX_BLOCKS + b] = s * MAX_BLOCKS + b; // < NUM_PAGES + + hipStream_t stream; + hipStreamCreate(&stream); + float h_out[MAX_NUM_SEQS]; + int actual = 0; + + // Replay A and B BOTH map to bucket 32 -> they reuse the SAME captured graph. Different lengths, + // refreshed in place. (max length per call <= 32 so both land on bucket 32.) + int lensA[MAX_NUM_SEQS] = {10, 20, 5, 0}; + int lensB[MAX_NUM_SEQS] = {30, 25, 31, 28}; + + err = hgb_decode_pool_replay(&pool, 20, lensA, MAX_NUM_SEQS, bt, stream, &actual); + assert(err == hipSuccess); + hipStreamSynchronize(stream); + hipMemcpy(h_out, d_out, MAX_NUM_SEQS * sizeof(float), hipMemcpyDeviceToHost); + printf(" Replay A (bucket %d): out = [%.0f %.0f %.0f %.0f], expect [10 20 5 0]\n", + actual, h_out[0], h_out[1], h_out[2], h_out[3]); + assert(actual == 32); + for (int i = 0; i < MAX_NUM_SEQS; i++) assert(h_out[i] == (float)lensA[i]); + + err = hgb_decode_pool_replay(&pool, 31, lensB, MAX_NUM_SEQS, bt, stream, &actual); + assert(err == hipSuccess); + hipStreamSynchronize(stream); + hipMemcpy(h_out, d_out, MAX_NUM_SEQS * sizeof(float), hipMemcpyDeviceToHost); + printf(" Replay B (bucket %d, SAME graph): out = [%.0f %.0f %.0f %.0f], expect [30 25 31 28]\n", + actual, h_out[0], h_out[1], h_out[2], h_out[3]); + assert(actual == 32); // same bucket/graph as A + for (int i = 0; i < MAX_NUM_SEQS; i++) assert(h_out[i] == (float)lensB[i]); + + // Negative control: A and B answers genuinely differ, so a stale (un-refreshed) graph WOULD garble. + bool differ = false; + for (int i = 0; i < MAX_NUM_SEQS; i++) if (lensA[i] != lensB[i]) differ = true; + assert(differ); + printf(" Negative control: lengths differ -> a baked-length graph would have garbled ✓\n"); + + // Cross-bucket sanity: a longer length routes to bucket 64 and is also correct. + int lensC[MAX_NUM_SEQS] = {40, 60, 33, 50}; + err = hgb_decode_pool_replay(&pool, 60, lensC, MAX_NUM_SEQS, bt, stream, &actual); + assert(err == hipSuccess); + hipStreamSynchronize(stream); + hipMemcpy(h_out, d_out, MAX_NUM_SEQS * sizeof(float), hipMemcpyDeviceToHost); + printf(" Replay C (bucket %d): out = [%.0f %.0f %.0f %.0f], expect [40 60 33 50]\n", + actual, h_out[0], h_out[1], h_out[2], h_out[3]); + assert(actual == 64); + for (int i = 0; i < MAX_NUM_SEQS; i++) assert(h_out[i] == (float)lensC[i]); + + hgb_decode_pool_destroy(&pool); + hipFree(d_content); + hipFree(d_out); + hipStreamDestroy(stream); + hgb_shutdown(); + + printf(" PASSED\n"); + return 0; +} diff --git a/tests/test_gfxgraph_rs.py b/tests/test_gfxgraph_rs.py index ccfb2a4..a390e86 100644 --- a/tests/test_gfxgraph_rs.py +++ b/tests/test_gfxgraph_rs.py @@ -29,4 +29,5 @@ def test_rust_bucket_selector(): assert router.route(5) == (8, 2) # Error path test for invalid input (too large) - assert router.route(33) == (-1, 2) + with pytest.raises(ValueError, match="Input size 33 exceeds largest bucket 32. Add a larger bucket."): + router.route(33) diff --git a/tests/test_profiler.hip b/tests/test_profiler.hip new file mode 100644 index 0000000..6ad231a --- /dev/null +++ b/tests/test_profiler.hip @@ -0,0 +1,40 @@ +/** + * @file test_profiler.hip + * @brief Tests for native profiler ring buffer. + */ +#include "hipgraph_bridge.h" +#include +#include +#include + +int main() { + std::printf("=== test_profiler ===\n"); + hipError_t err = hgb_init(); + assert(err == hipSuccess); + + hgb_profiler_reset(); + uint64_t seq1 = hgb_profiler_record(HGB_PROFILE_EVENT_PIPELINE_CREATE, 10, 1, 2); + uint64_t seq2 = hgb_profiler_record(HGB_PROFILE_EVENT_PIPELINE_LAUNCH, 20, 3, 4); + assert(seq1 == 1); + assert(seq2 == 2); + + hgb_profile_counters_t counters{}; + hgb_profile_sample_t samples[8]; + size_t copied = hgb_profiler_snapshot(samples, 8, &counters); + + assert(copied == 2); + assert(counters.written == 2); + assert(counters.capacity == HGB_PROFILER_CAPACITY); + assert(samples[0].event == HGB_PROFILE_EVENT_PIPELINE_CREATE); + assert(samples[1].event == HGB_PROFILE_EVENT_PIPELINE_LAUNCH); + assert(samples[1].duration_ns == 20); + + std::printf(" copied=%zu written=%llu capacity=%llu\n", + copied, + (unsigned long long)counters.written, + (unsigned long long)counters.capacity); + + hgb_shutdown(); + std::printf(" PASSED\n"); + return 0; +} diff --git a/tests/test_routing.hip b/tests/test_routing.hip new file mode 100644 index 0000000..7f8e54d --- /dev/null +++ b/tests/test_routing.hip @@ -0,0 +1,113 @@ +/** + * @file test_routing.hip + * @brief Tests for shape bucket routing logic + */ +#include "hipgraph_bridge.h" +#include +#include +#include +#include + +__global__ void dummy_kernel(float* data, int n) { + int idx = blockIdx.x * blockDim.x + threadIdx.x; + if (idx < n) data[idx] = data[idx] + 1.0f; +} + +static float* g_data; + +static hipError_t capture_dummy(int size, hipGraph_t* graph, void* ctx) { + hipStream_t stream; + hipStreamCreate(&stream); + + hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal); + dummy_kernel<<<(size + 255) / 256, 256, 0, stream>>>(g_data, size); + hipStreamEndCapture(stream, graph); + + hipStreamDestroy(stream); + return hipSuccess; +} + +int main() { + printf("=== test_routing ===\n"); + hipError_t err = hgb_init(); + assert(err == hipSuccess); + + const int MAX_SIZE = 128; + hipMalloc(&g_data, MAX_SIZE * sizeof(float)); + + /* Create shape pool with buckets */ + int buckets[] = {1, 4, 8, 16, 32, 64}; + hgb_shape_pool_t pool; + err = hgb_shape_pool_create(capture_dummy, nullptr, buckets, 6, &pool); + assert(err == hipSuccess); + printf(" Created pool with %d buckets\n", pool.num_buckets); + + hipStream_t stream; + hipStreamCreate(&stream); + + int actual = 0; + + /* Test exact matches */ + err = hgb_shape_pool_launch(&pool, 1, stream, &actual); + assert(err == hipSuccess); + assert(actual == 1); + printf(" Input size 1 → bucket %d ✓\n", actual); + + err = hgb_shape_pool_launch(&pool, 4, stream, &actual); + assert(err == hipSuccess); + assert(actual == 4); + printf(" Input size 4 → bucket %d ✓\n", actual); + + err = hgb_shape_pool_launch(&pool, 16, stream, &actual); + assert(err == hipSuccess); + assert(actual == 16); + printf(" Input size 16 → bucket %d ✓\n", actual); + + err = hgb_shape_pool_launch(&pool, 64, stream, &actual); + assert(err == hipSuccess); + assert(actual == 64); + printf(" Input size 64 → bucket %d ✓\n", actual); + + /* Test intermediate sizes requiring rounding up */ + err = hgb_shape_pool_launch(&pool, 2, stream, &actual); + assert(err == hipSuccess); + assert(actual == 4); + printf(" Input size 2 → bucket %d ✓\n", actual); + + err = hgb_shape_pool_launch(&pool, 5, stream, &actual); + assert(err == hipSuccess); + assert(actual == 8); + printf(" Input size 5 → bucket %d ✓\n", actual); + + err = hgb_shape_pool_launch(&pool, 12, stream, &actual); + assert(err == hipSuccess); + assert(actual == 16); + printf(" Input size 12 → bucket %d ✓\n", actual); + + err = hgb_shape_pool_launch(&pool, 40, stream, &actual); + assert(err == hipSuccess); + assert(actual == 64); + printf(" Input size 40 → bucket %d ✓\n", actual); + + /* Test invalid size bounds */ + err = hgb_shape_pool_launch(&pool, 0, stream, &actual); + assert(err != hipSuccess); + printf(" Input size 0 → rejected ✓\n"); + + err = hgb_shape_pool_launch(&pool, -5, stream, &actual); + assert(err != hipSuccess); + printf(" Input size -5 → rejected ✓\n"); + + err = hgb_shape_pool_launch(&pool, 65, stream, &actual); + assert(err != hipSuccess); + printf(" Input size 65 → rejected ✓\n"); + + /* Cleanup */ + hgb_shape_pool_destroy(&pool); + hipFree(g_data); + hipStreamDestroy(stream); + hgb_shutdown(); + + printf(" PASSED\n"); + return 0; +} diff --git a/tests/test_runtime_handles.hip b/tests/test_runtime_handles.hip new file mode 100644 index 0000000..d6e5246 --- /dev/null +++ b/tests/test_runtime_handles.hip @@ -0,0 +1,107 @@ +/** + * @file test_runtime_handles.hip + * @brief Tests opaque native runtime handles for FFI callers. + */ +#include "hipgraph_bridge.h" +#include +#include +#include + +__global__ void add_kernel(float* data, int n, float value) { + int idx = blockIdx.x * blockDim.x + threadIdx.x; + if (idx < n) data[idx] += value; +} + +static hipError_t capture_add_graph(float* d_data, int n, float value, hipGraph_t* graph) { + hipStream_t stream = nullptr; + hipError_t err = hipStreamCreate(&stream); + if (err != hipSuccess) return err; + + err = hipStreamBeginCapture(stream, hipStreamCaptureModeGlobal); + if (err != hipSuccess) { + hipStreamDestroy(stream); + return err; + } + + add_kernel<<<(n + 255) / 256, 256, 0, stream>>>(d_data, n, value); + + err = hipStreamEndCapture(stream, graph); + hipStreamDestroy(stream); + return err; +} + +int main() { + std::printf("=== test_runtime_handles ===\n"); + hipError_t err = hgb_init(); + assert(err == hipSuccess); + + constexpr int N = 1024; + float* d_data = nullptr; + err = hipMalloc(&d_data, N * sizeof(float)); + assert(err == hipSuccess); + err = hipMemset(d_data, 0, N * sizeof(float)); + assert(err == hipSuccess); + + hipGraph_t pipeline_graph = nullptr; + err = capture_add_graph(d_data, N, 1.0f, &pipeline_graph); + assert(err == hipSuccess); + + hgb_pipeline_handle_t* pipeline = nullptr; + err = hgb_pipeline_handle_create(pipeline_graph, &pipeline); + assert(err == hipSuccess); + assert(pipeline != nullptr); + + for (int i = 0; i < 5; ++i) { + err = hgb_pipeline_handle_launch(pipeline); + assert(err == hipSuccess); + } + err = hipDeviceSynchronize(); + assert(err == hipSuccess); + + float h_data[4] = {}; + err = hipMemcpy(h_data, d_data, sizeof(h_data), hipMemcpyDeviceToHost); + assert(err == hipSuccess); + std::printf(" pipeline handle result %.1f (expected 5.0)\n", h_data[0]); + assert(h_data[0] == 5.0f); + + hgb_pipeline_handle_destroy(pipeline); + hipGraphDestroy(pipeline_graph); + + err = hipMemset(d_data, 0, N * sizeof(float)); + assert(err == hipSuccess); + + hipGraph_t sub_graphs[2] = {}; + err = capture_add_graph(d_data, N, 2.0f, &sub_graphs[0]); + assert(err == hipSuccess); + err = capture_add_graph(d_data, N, 3.0f, &sub_graphs[1]); + assert(err == hipSuccess); + + int deps[2] = {-1, 0}; + hgb_composed_graph_handle_t* composed = nullptr; + err = hgb_composed_handle_create(sub_graphs, 2, deps, &composed); + assert(err == hipSuccess); + assert(composed != nullptr); + + hipStream_t launch_stream = nullptr; + err = hipStreamCreate(&launch_stream); + assert(err == hipSuccess); + err = hgb_composed_handle_launch(composed, launch_stream); + assert(err == hipSuccess); + err = hipStreamSynchronize(launch_stream); + assert(err == hipSuccess); + + err = hipMemcpy(h_data, d_data, sizeof(h_data), hipMemcpyDeviceToHost); + assert(err == hipSuccess); + std::printf(" composed handle result %.1f (expected 5.0)\n", h_data[0]); + assert(h_data[0] == 5.0f); + + hgb_composed_handle_destroy(composed); + hipStreamDestroy(launch_stream); + hipGraphDestroy(sub_graphs[0]); + hipGraphDestroy(sub_graphs[1]); + hipFree(d_data); + hgb_shutdown(); + + std::printf(" PASSED\n"); + return 0; +} diff --git a/uv.lock b/uv.lock index 2201a3c..cb6f8f3 100644 --- a/uv.lock +++ b/uv.lock @@ -2,72 +2,6 @@ version = 1 revision = 3 requires-python = ">=3.12" -[[package]] -name = "cuda-bindings" -version = "13.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cuda-pathfinder" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/67/5e7dba1ba576dd73da5dee894ca076ca5e959450dfff66d6d510a255d1f7/cuda_bindings-13.3.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7855c4868aabc0cfae28abbe83d56734bdfbd08f08fc234ac1912a12858bf49", size = 6025351, upload-time = "2026-05-29T23:11:49.685Z" }, - { url = "https://files.pythonhosted.org/packages/39/2a/6d2e9047d1fb243dbaa364b01e0297534b9ed7fd27dba1c9f361519cf69b/cuda_bindings-13.3.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e32d08f71ebcdf00f0f41eab2eb37e8da94c8ed411cc9f7f7a019ce6b34abe3a", size = 6657965, upload-time = "2026-05-29T23:11:52.227Z" }, - { url = "https://files.pythonhosted.org/packages/cc/6e/2394f8163360f8391f8f1b7e72d300a82724edb81a7b7084c799fbd4c91f/cuda_bindings-13.3.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9efb21c1ee64981e184b9e0ba5eb3179e5ba3d4b51665a6cb52b8ef3d01a7cbf", size = 5920504, upload-time = "2026-05-29T23:11:56.883Z" }, - { url = "https://files.pythonhosted.org/packages/34/c2/ef9b6a63f7dc432712a462c816662e662e00d38caa9b861c8c2588195d03/cuda_bindings-13.3.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2732904099e0a4d4db774a5fc6d91ee95fae065b4d2ecabb4968c5fe2406c9d7", size = 6476660, upload-time = "2026-05-29T23:11:59.188Z" }, - { url = "https://files.pythonhosted.org/packages/b1/81/bff68ce829999c1e4209c761bbf903b1c06ec570416ddb25020864ad5907/cuda_bindings-13.3.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ab2f74ed65bfef4163ba07a8db16f1085e0729291db12a2423aff84ee8278b8", size = 6013639, upload-time = "2026-05-29T23:12:03.509Z" }, - { url = "https://files.pythonhosted.org/packages/d4/e0/c8a1f0c8f9ffdea4f5fe6dbab89b326cef4d85caf489dad39e209da89416/cuda_bindings-13.3.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd4c814d311ec08c981f6dded1dbe7d4b371067ee4f6c14cccec4bde9590f80", size = 6534419, upload-time = "2026-05-29T23:12:05.633Z" }, - { url = "https://files.pythonhosted.org/packages/52/b8/83b1f563925b290f2d11a01a77a84013ba56052fe3653a5bef3ccfbb43d6/cuda_bindings-13.3.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3c772dfff49681541d59630c90f858e173ac926b9c593a2b7123f2a1043cc76", size = 5809771, upload-time = "2026-05-29T23:12:10.422Z" }, - { url = "https://files.pythonhosted.org/packages/12/20/e79b4bfe98f075195afb6343d41c498f9dbd2d161d7021d4d28bceb83581/cuda_bindings-13.3.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36febb7c1079d68a981dbbd8d5a67235b399802b82075c9388624719607e52b9", size = 6358584, upload-time = "2026-05-29T23:12:12.767Z" }, -] - -[[package]] -name = "cuda-pathfinder" -version = "1.5.5" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/c8/26f2e4aae92f11522a96043892ba39a90eac610d5242523aa863212bc1c7/cuda_pathfinder-1.5.5-py3-none-any.whl", hash = "sha256:0228c023f95d1480f143ef5c8922d27a2ab052087a942e81dc289c9eb8f91689", size = 51671, upload-time = "2026-05-27T01:21:25.413Z" }, -] - -[[package]] -name = "cuda-toolkit" -version = "13.0.2" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/57/b2/453099f5f3b698d7d0eab38916aac44c7f76229f451709e2eb9db6615dcd/cuda_toolkit-13.0.2-py2.py3-none-any.whl", hash = "sha256:b198824cf2f54003f50d64ada3a0f184b42ca0846c1c94192fa269ecd97a66eb", size = 2364, upload-time = "2025-12-19T23:24:07.328Z" }, -] - -[package.optional-dependencies] -cudart = [ - { name = "nvidia-cuda-runtime", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, -] -cufft = [ - { name = "nvidia-cufft", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, -] -cufile = [ - { name = "nvidia-cufile", marker = "sys_platform == 'linux'" }, -] -cupti = [ - { name = "nvidia-cuda-cupti", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, -] -curand = [ - { name = "nvidia-curand", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, -] -cusolver = [ - { name = "nvidia-cusolver", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, -] -cusparse = [ - { name = "nvidia-cusparse", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, -] -nvjitlink = [ - { name = "nvidia-nvjitlink", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, -] -nvrtc = [ - { name = "nvidia-cuda-nvrtc", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, -] -nvtx = [ - { name = "nvidia-nvtx", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, -] - [[package]] name = "filelock" version = "3.29.3" @@ -88,7 +22,7 @@ wheels = [ [[package]] name = "gfxgraph" -version = "0.3.3" +version = "1.0.1" source = { editable = "." } dependencies = [ { name = "torch" }, @@ -190,158 +124,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, ] -[[package]] -name = "nvidia-cublas" -version = "13.1.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-cuda-nvrtc" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/a1/0bd24ee8c8d03adac032fd2909426a00c88f8c57961b1277ded97f91119f/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b7a210458267ac818974c53038fbec2e969d5c99f305ab15c72522fa9f001dd5", size = 542848918, upload-time = "2026-04-08T18:46:22.985Z" }, - { url = "https://files.pythonhosted.org/packages/3b/cd/154ca20c38269e05eff77c1464e6c1da89f50a6390b565e9d82e06bc11e1/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:37936a16db8fe4ac1f065c2139360608a543a09275cb1a1af612e08cfa065436", size = 423138758, upload-time = "2026-04-08T18:46:58.655Z" }, -] - -[[package]] -name = "nvidia-cuda-cupti" -version = "13.0.85" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/2a/80353b103fc20ce05ef51e928daed4b6015db4aaa9162ed0997090fe2250/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_aarch64.whl", hash = "sha256:796bd679890ee55fb14a94629b698b6db54bcfd833d391d5e94017dd9d7d3151", size = 10310827, upload-time = "2025-09-04T08:26:42.012Z" }, - { url = "https://files.pythonhosted.org/packages/33/6d/737d164b4837a9bbd202f5ae3078975f0525a55730fe871d8ed4e3b952b0/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_x86_64.whl", hash = "sha256:4eb01c08e859bf924d222250d2e8f8b8ff6d3db4721288cf35d14252a4d933c8", size = 10715597, upload-time = "2025-09-04T08:26:51.312Z" }, -] - -[[package]] -name = "nvidia-cuda-nvrtc" -version = "13.0.88" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/68/483a78f5e8f31b08fb1bb671559968c0ca3a065ac7acabfc7cee55214fd6/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:ad9b6d2ead2435f11cbb6868809d2adeeee302e9bb94bcf0539c7a40d80e8575", size = 90215200, upload-time = "2025-09-04T08:28:44.204Z" }, - { url = "https://files.pythonhosted.org/packages/b7/dc/6bb80850e0b7edd6588d560758f17e0550893a1feaf436807d64d2da040f/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d27f20a0ca67a4bb34268a5e951033496c5b74870b868bacd046b1b8e0c3267b", size = 43015449, upload-time = "2025-09-04T08:28:20.239Z" }, -] - -[[package]] -name = "nvidia-cuda-runtime" -version = "13.0.96" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/87/4f/17d7b9b8e285199c58ce28e31b5c5bbaa4d8271af06a89b6405258245de2/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ef9bcbe90493a2b9d810e43d249adb3d02e98dd30200d86607d8d02687c43f55", size = 2261060, upload-time = "2025-10-09T08:55:15.78Z" }, - { url = "https://files.pythonhosted.org/packages/2e/24/d1558f3b68b1d26e706813b1d10aa1d785e4698c425af8db8edc3dced472/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f82250d7782aa23b6cfe765ecc7db554bd3c2870c43f3d1821f1d18aebf0548", size = 2243632, upload-time = "2025-10-09T08:55:36.117Z" }, -] - -[[package]] -name = "nvidia-cudnn-cu13" -version = "9.20.0.48" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-cublas" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/c5/83384d846b2fd17c44bd499b36c75a45ed4f095fbbb2252294e89cea5c5c/nvidia_cudnn_cu13-9.20.0.48-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:e31454ae00094b0c55319d9d15b6fa2fc50a9e1c0f5c8c80fb75258234e731e1", size = 444574296, upload-time = "2026-03-09T19:28:27.751Z" }, - { url = "https://files.pythonhosted.org/packages/6e/5e/edb9c0ae051602c3ccaffe424256463636d639e27d7f302dde9975ef9e7a/nvidia_cudnn_cu13-9.20.0.48-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0c45dd8eeb50b603f07995b1b300c62ffe6a1980482b82b3bcf94a4ca9d49304", size = 366173588, upload-time = "2026-03-09T19:29:34.474Z" }, -] - -[[package]] -name = "nvidia-cufft" -version = "12.0.0.61" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-nvjitlink" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/ae/f417a75c0259e85c1d2f83ca4e960289a5f814ed0cea74d18c353d3e989d/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2708c852ef8cd89d1d2068bdbece0aa188813a0c934db3779b9b1faa8442e5f5", size = 214053554, upload-time = "2025-09-04T08:31:38.196Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2f/7b57e29836ea8714f81e9898409196f47d772d5ddedddf1592eadb8ab743/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6c44f692dce8fd5ffd3e3df134b6cdb9c2f72d99cf40b62c32dde45eea9ddad3", size = 214085489, upload-time = "2025-09-04T08:31:56.044Z" }, -] - -[[package]] -name = "nvidia-cufile" -version = "1.15.1.6" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/70/4f193de89a48b71714e74602ee14d04e4019ad36a5a9f20c425776e72cd6/nvidia_cufile-1.15.1.6-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:08a3ecefae5a01c7f5117351c64f17c7c62efa5fffdbe24fc7d298da19cd0b44", size = 1223672, upload-time = "2025-09-04T08:32:22.779Z" }, - { url = "https://files.pythonhosted.org/packages/ab/73/cc4a14c9813a8a0d509417cf5f4bdaba76e924d58beb9864f5a7baceefbf/nvidia_cufile-1.15.1.6-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:bdc0deedc61f548bddf7733bdc216456c2fdb101d020e1ab4b88d232d5e2f6d1", size = 1136992, upload-time = "2025-09-04T08:32:14.119Z" }, -] - -[[package]] -name = "nvidia-curand" -version = "10.4.0.35" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/72/7c2ae24fb6b63a32e6ae5d241cc65263ea18d08802aaae087d9f013335a2/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:133df5a7509c3e292aaa2b477afd0194f06ce4ea24d714d616ff36439cee349a", size = 61962106, upload-time = "2025-08-04T10:21:41.128Z" }, - { url = "https://files.pythonhosted.org/packages/a5/9f/be0a41ca4a4917abf5cb9ae0daff1a6060cc5de950aec0396de9f3b52bc5/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:1aee33a5da6e1db083fe2b90082def8915f30f3248d5896bcec36a579d941bfc", size = 59544258, upload-time = "2025-08-04T10:22:03.992Z" }, -] - -[[package]] -name = "nvidia-cusolver" -version = "12.0.4.66" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-cublas" }, - { name = "nvidia-cusparse" }, - { name = "nvidia-nvjitlink" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/c3/b30c9e935fc01e3da443ec0116ed1b2a009bb867f5324d3f2d7e533e776b/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:02c2457eaa9e39de20f880f4bd8820e6a1cfb9f9a34f820eb12a155aa5bc92d2", size = 223467760, upload-time = "2025-09-04T08:33:04.222Z" }, - { url = "https://files.pythonhosted.org/packages/5f/67/cba3777620cdacb99102da4042883709c41c709f4b6323c10781a9c3aa34/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0a759da5dea5c0ea10fd307de75cdeb59e7ea4fcb8add0924859b944babf1112", size = 200941980, upload-time = "2025-09-04T08:33:22.767Z" }, -] - -[[package]] -name = "nvidia-cusparse" -version = "12.6.3.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-nvjitlink" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/94/5c26f33738ae35276672f12615a64bd008ed5be6d1ebcb23579285d960a9/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:80bcc4662f23f1054ee334a15c72b8940402975e0eab63178fc7e670aa59472c", size = 162155568, upload-time = "2025-09-04T08:33:42.864Z" }, - { url = "https://files.pythonhosted.org/packages/fa/18/623c77619c31d62efd55302939756966f3ecc8d724a14dab2b75f1508850/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b3c89c88d01ee0e477cb7f82ef60a11a4bcd57b6b87c33f789350b59759360b", size = 145942937, upload-time = "2025-09-04T08:33:58.029Z" }, -] - -[[package]] -name = "nvidia-cusparselt-cu13" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/e1/cdc1797eadf82d3a9a575a19b33fdc871a97edbec42c00b5b5e914f4aff4/nvidia_cusparselt_cu13-0.8.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4dca476c50bf4780d46cd0bfbd82e2bc10a08e4fef7950917ce8d7578d22a23f", size = 221051344, upload-time = "2025-09-05T18:49:51.289Z" }, - { url = "https://files.pythonhosted.org/packages/34/7d/2661f2fb3ac4302f3a246f5fc030213ac60c1fe0bce84f9783dbd831dbb7/nvidia_cusparselt_cu13-0.8.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:786ce87568c303fadb5afcc7102d454cd3040d75f6f8626f5db460d1871f4dd0", size = 170148586, upload-time = "2025-09-05T18:50:50.248Z" }, -] - -[[package]] -name = "nvidia-nccl-cu13" -version = "2.29.7" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/0d/daf50d44177ee0cbc7ff0a0c91eb5ff676c82be42f9a970bc7597f440c3a/nvidia_nccl_cu13-2.29.7-py3-none-manylinux_2_18_aarch64.whl", hash = "sha256:674a12383e3c38a1bcccae7d4f3633b37852230b6047883cb2f4c2d1b36d9bf5", size = 206014712, upload-time = "2026-03-03T05:34:20.843Z" }, - { url = "https://files.pythonhosted.org/packages/67/f4/58e4e91b6919367c7aafb8e36fce9aad1a3047e536bf7e2fd560927d3a4c/nvidia_nccl_cu13-2.29.7-py3-none-manylinux_2_18_x86_64.whl", hash = "sha256:edd81538446786ec3b73972543e53bb43bcaf0bfc8ef76cb679fcc390ffe136d", size = 205976000, upload-time = "2026-03-03T05:36:24.472Z" }, -] - -[[package]] -name = "nvidia-nvjitlink" -version = "13.0.88" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/7a/123e033aaff487c77107195fa5a2b8686795ca537935a24efae476c41f05/nvidia_nvjitlink-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:13a74f429e23b921c1109976abefacc69835f2f433ebd323d3946e11d804e47b", size = 40713933, upload-time = "2025-09-04T08:35:43.553Z" }, - { url = "https://files.pythonhosted.org/packages/ab/2c/93c5250e64df4f894f1cbb397c6fd71f79813f9fd79d7cd61de3f97b3c2d/nvidia_nvjitlink-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e931536ccc7d467a98ba1d8b89ff7fa7f1fa3b13f2b0069118cd7f47bff07d0c", size = 38768748, upload-time = "2025-09-04T08:35:20.008Z" }, -] - -[[package]] -name = "nvidia-nvshmem-cu13" -version = "3.4.5" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/0f/05cc9c720236dcd2db9c1ab97fff629e96821be2e63103569da0c9b72f19/nvidia_nvshmem_cu13-3.4.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dc2a197f38e5d0376ad52cd1a2a3617d3cdc150fd5966f4aee9bcebb1d68fe9", size = 60215947, upload-time = "2025-09-06T00:32:20.022Z" }, - { url = "https://files.pythonhosted.org/packages/3c/35/a9bf80a609e74e3b000fef598933235c908fcefcef9026042b8e6dfde2a9/nvidia_nvshmem_cu13-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:290f0a2ee94c9f3687a02502f3b9299a9f9fe826e6d0287ee18482e78d495b80", size = 60412546, upload-time = "2025-09-06T00:32:41.564Z" }, -] - -[[package]] -name = "nvidia-nvtx" -version = "13.0.85" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/f3/d86c845465a2723ad7e1e5c36dcd75ddb82898b3f53be47ebd429fb2fa5d/nvidia_nvtx-13.0.85-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4936d1d6780fbe68db454f5e72a42ff64d1fd6397df9f363ae786930fd5c1cd4", size = 148047, upload-time = "2025-09-04T08:29:01.761Z" }, - { url = "https://files.pythonhosted.org/packages/a8/64/3708a90d1ebe202ffdeb7185f878a3c84d15c2b2c31858da2ce0583e2def/nvidia_nvtx-13.0.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb7780edb6b14107373c835bf8b72e7a178bac7367e23da7acb108f973f157a6", size = 148878, upload-time = "2025-09-04T08:28:53.627Z" }, -] - [[package]] name = "setuptools" version = "81.0.0" @@ -365,63 +147,19 @@ wheels = [ [[package]] name = "torch" -version = "2.12.0" -source = { registry = "https://pypi.org/simple" } +version = "2.13.0a0+git53bbebe" +source = { registry = "/home/local/packages/simple" } dependencies = [ - { name = "cuda-bindings", marker = "sys_platform == 'linux'" }, - { name = "cuda-toolkit", extra = ["cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"], marker = "sys_platform == 'linux'" }, { name = "filelock" }, { name = "fsspec" }, { name = "jinja2" }, { name = "networkx" }, - { name = "nvidia-cublas", marker = "sys_platform == 'linux'" }, - { name = "nvidia-cudnn-cu13", marker = "sys_platform == 'linux'" }, - { name = "nvidia-cusparselt-cu13", marker = "sys_platform == 'linux'" }, - { name = "nvidia-nccl-cu13", marker = "sys_platform == 'linux'" }, - { name = "nvidia-nvshmem-cu13", marker = "sys_platform == 'linux'" }, { name = "setuptools" }, { name = "sympy" }, - { name = "triton", marker = "sys_platform == 'linux'" }, { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/bb/285d643f254731294c9b595a007eac39db4600a98682d7bca688f42ca164/torch-2.12.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b41339df93d491435e790ff8bcbae1c0ce777175889bfd1281d119862793e6a2", size = 88010197, upload-time = "2026-05-13T14:55:35.414Z" }, - { url = "https://files.pythonhosted.org/packages/79/81/76debf1db1343bd929bbb5d74c89fb437c2ed88eb144712557e7bd3eea45/torch-2.12.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8fbef9f108a863e7722a73740998967e3b074742a834fc5be3a535a2befa7057", size = 426376751, upload-time = "2026-05-13T14:55:03.353Z" }, - { url = "https://files.pythonhosted.org/packages/de/f0/80026028b603c4650ff270fc3785bdef4bd6738765a9cc5a0f5a637d65a2/torch-2.12.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4b4f64c2c2b11f7510d93dd6412b87025ff6eddd6bb61c3b5a3d892ea20c4756", size = 532261691, upload-time = "2026-05-13T14:52:54.453Z" }, - { url = "https://files.pythonhosted.org/packages/b9/c2/64b06cbb7830fb3cd9be13e1158b31a3f36b68e6a209105ee3c9d9480be0/torch-2.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:8b958caff4a14d3a3b0b2dfc6a378f64dda9728a9dad28c08a0db9ce4dafb549", size = 122988114, upload-time = "2026-05-13T14:54:42.153Z" }, - { url = "https://files.pythonhosted.org/packages/86/ca/01896c80ba921676aa45886b2c5b8d774912de2a1f719de48169c6f755cd/torch-2.12.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:90dd587a5f61bfe1307148b581e2084fc5bc4a06e2b90a20e9a36b81087ff16b", size = 88009511, upload-time = "2026-05-13T14:54:47.411Z" }, - { url = "https://files.pythonhosted.org/packages/a5/04/52bdaf4787eab6ac7d7f5851dff934e4def0bc8ead9c8fd2b69b3e529699/torch-2.12.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:864392c73b7654f4d2b3ae712f607937d0dbb1101c4555fbb41848106b297f39", size = 426383231, upload-time = "2026-05-13T14:53:32.129Z" }, - { url = "https://files.pythonhosted.org/packages/49/8a/94bdecd13f5aaa90d45920b89789d9fe7c6f4af8c3cdd7ce01fcb59908fc/torch-2.12.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5d6b560dfa7d56291c07d615c3bb73e8d9943d9b6d87f76cd0d9d570c4797fa6", size = 532269288, upload-time = "2026-05-13T14:53:49.423Z" }, - { url = "https://files.pythonhosted.org/packages/3e/2f/bdbaaa267de519ef1b73054bf590d8c93c37a266c9a4e24a01bd38b6918f/torch-2.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:3fee918902090ade827643e758e98363278815de583c75d111fdd665ebffde9f", size = 122987706, upload-time = "2026-05-13T14:54:00.335Z" }, - { url = "https://files.pythonhosted.org/packages/9b/ad/e95e822f3538171e22640a7fbe839a1fdb666600bf6487025de2ff03b11a/torch-2.12.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:10ee1448a9f304d3b987eb4656f664ba6e4d7b410ca7a5a7c642199777a2cf88", size = 88319556, upload-time = "2026-05-13T14:54:05.574Z" }, - { url = "https://files.pythonhosted.org/packages/b7/07/055d06d985b445d67422d25b033c11cf55bbb81785d4c4e68e28bca5820e/torch-2.12.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:af68dbf403439cae9ceaeaaf92f8352b460787dcd27b92aa05c40dd4a19c0f1e", size = 426397656, upload-time = "2026-05-13T14:52:38.84Z" }, - { url = "https://files.pythonhosted.org/packages/43/94/b0b4fdc3014122e0a7302fb90086d352aa48f2576f0b252561ebb38c01a8/torch-2.12.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:a6a2eebb237d3b1d9ad3b378e86d9b9e0782afdea8b1e0eba6a13646b9b49c07", size = 532183124, upload-time = "2026-05-13T14:53:16.178Z" }, - { url = "https://files.pythonhosted.org/packages/d8/c8/052405e6ad05d3237bfe5a4df78f917773956f8e17813a2d44c059068b74/torch-2.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2140e373e9a51a3e22ef62e8d14366d0b470d18f0adf19fdc757368077133a34", size = 123232462, upload-time = "2026-05-13T14:52:27.26Z" }, - { url = "https://files.pythonhosted.org/packages/67/dc/ac069f8d6e8be701535921141055293b0d4819d3d7f224a4612cf157c7f9/torch-2.12.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f7dfae4a519197dfa050e98d8e36378a0fb5899625a875c2b54445005a2e404e", size = 88027282, upload-time = "2026-05-13T14:53:05.258Z" }, - { url = "https://files.pythonhosted.org/packages/33/c3/1c1eb00e34555b536dddf792676026a988d710ed36981aa00499b36b0620/torch-2.12.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:891c769072637c74e9a5a77a3bc782894696d8ffec83b938df8536dee7f0ba78", size = 426386961, upload-time = "2026-05-13T14:51:28.406Z" }, - { url = "https://files.pythonhosted.org/packages/cd/d4/7e730dba0c7032a4154dc9056b76cf9625515e030e269cfbf8098fcfee7d/torch-2.12.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:e2ad3eb85d39c3cab62dfa93ed5a73516e6a53c6713cb97d004004fe089f0f1f", size = 532272265, upload-time = "2026-05-13T14:51:59.308Z" }, - { url = "https://files.pythonhosted.org/packages/f1/b4/92c80d1bbfee1c0036c06d1d2155a3065bd2423134c83bf8a47e65cd6b9b/torch-2.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:c66696857e987efb8bc1777a37357ec4f60ab5e8af6250b83d6034437fa2d8f3", size = 122987138, upload-time = "2026-05-13T14:51:45.942Z" }, - { url = "https://files.pythonhosted.org/packages/7b/78/2e12b37ce50a19a037d7bc62d652a5a8f27385a7b05859d6bc9204f20cfe/torch-2.12.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:b4556715c8572758625d62b6e0ae3b1f76c440221913a6fb5e100f321fb4fb02", size = 88320100, upload-time = "2026-05-13T14:51:39.955Z" }, - { url = "https://files.pythonhosted.org/packages/56/5e/83c450ec7b0bb40a7b74611c1b5440f9260e33c54c90d556fd4a1f0fd955/torch-2.12.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:a43ac605a5e13116c72b64c359644cce0229f213dde48d2ae0ae5eb5becf7feb", size = 426391871, upload-time = "2026-05-13T14:52:14.989Z" }, - { url = "https://files.pythonhosted.org/packages/c9/e9/1a0b575d98d0afedd8f157d23fa3d2759421483660448e60d0a4b10b6daa/torch-2.12.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6a7512adfdd7f6732e40de1c620831e3c75b39b98cef60b11d0c5f0a76473ec5", size = 532192241, upload-time = "2026-05-13T14:51:07.795Z" }, - { url = "https://files.pythonhosted.org/packages/88/21/afadd25ecd81b3cea1e11c73cf1ab41a983a50271548c3ec7ec3b9efc3e9/torch-2.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:5f96b63f8287f66a005dd1b5a6abba2920f11156c5e5c4d815f3e2050fd1aa16", size = 123231092, upload-time = "2026-05-13T14:51:18.854Z" }, -] - -[[package]] -name = "triton" -version = "3.7.0" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/13/ec05adfcd87311d532ba61e3af143e8be59fcd26675884c4682841406a20/triton-3.7.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4bf49b00a7a377a68a6da603a876e797614e6455a80e9021669c476a953ad9a", size = 188505104, upload-time = "2026-05-07T19:05:09.843Z" }, - { url = "https://files.pythonhosted.org/packages/62/7b/468a576e35beef1426e0828e28e9ba9e65f5474d496f16ee126c15646324/triton-3.7.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f111161d49bf903c0eaedde3962353a3d841c08a836839b7cc1025b8426efcf", size = 201457567, upload-time = "2026-05-07T18:46:13.505Z" }, - { url = "https://files.pythonhosted.org/packages/01/e1/a59a583de59b8f62c495d67c80ee3ea97d09e91ac80c4c6e76456ed8d8ac/triton-3.7.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:abdf6beaa89b1bcfb9a43cd990536ce66091a997841a4814b260b7bee4c88c3c", size = 188503209, upload-time = "2026-05-07T19:05:17.935Z" }, - { url = "https://files.pythonhosted.org/packages/30/b1/b7507bb9815d403927c8dd51d4158ed2e11751a92dbc118a044f247b6848/triton-3.7.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a35d7afe3f3f058e7ec49fcce09794049e0ffc5c59019ac25ec3413741b8c4e7", size = 201453566, upload-time = "2026-05-07T18:46:20.427Z" }, - { url = "https://files.pythonhosted.org/packages/a6/8f/0bea7a6a0c989315c9135a1d7fb37e41905cfb3a17cbc1f10044ebd4cc3a/triton-3.7.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc1d61c172d257db80ddf42595131fb196ad2e9bdd751e90fe2ef13531734e8b", size = 188612899, upload-time = "2026-05-07T19:05:24.955Z" }, - { url = "https://files.pythonhosted.org/packages/e1/02/d96f57828d0912aec733b9bc7e0e7dbfd2c6f079a8fa433ac25cb93d1a30/triton-3.7.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70fb9bbdc9f400afc54bbf6eb2670af28829a6ae3996863317964783141daf56", size = 201553816, upload-time = "2026-05-07T18:46:27.49Z" }, - { url = "https://files.pythonhosted.org/packages/40/fb/82a802dac4689f2a2fb2e69302e6a138eecc3e175bbe976ba3cfc717683a/triton-3.7.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a44a8476d0d3571eac4e4d1048e1ff75aad81a09ff4602ccfc56c6dea1672e", size = 188507879, upload-time = "2026-05-07T19:05:32.209Z" }, - { url = "https://files.pythonhosted.org/packages/8f/af/9904ec6d3c93d9b24e5ec360445bbdf758b7f00bfbeedb89cb0eb64eb8bb/triton-3.7.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b9b85e72968a9d8bba5ddb24e9b64aaabaf48affb042f2755cb7cfa92b7531ce", size = 201460637, upload-time = "2026-05-07T18:46:34.749Z" }, - { url = "https://files.pythonhosted.org/packages/a1/f9/4835a8ea746b88727d8899f4e3ccce4f9cacb38abfc3bb0a638266c53111/triton-3.7.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18a160de426fd99f92b0baf509045360afbd3bfaa0b4a5171dde800ec9f09684", size = 188608706, upload-time = "2026-05-07T19:05:39.218Z" }, - { url = "https://files.pythonhosted.org/packages/c1/68/fa86e5a39608000f645535b2c124920126327ab731f8c4fafd5b07ff8d4b/triton-3.7.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce061073102714b725f3660ec6939d94a1da7984b3aa99c921417cae273672f5", size = 201546766, upload-time = "2026-05-07T18:46:42.088Z" }, + { path = "/home/local/packages/wheels/torch-2.13.0a0+git53bbebe-cp312-cp312-linux_x86_64.whl" }, ] [[package]]