Fix ROCm backend (target MIGraphX EP) and add CUDA support
ROCm silently fell back to CPU: the code targeted ONNX Runtime's classic ROCMExecutionProvider, but distro ROCm-enabled ONNX Runtime builds (e.g. Arch's onnxruntime-rocm) are commonly compiled with --use_migraphx instead, and registration failures were invisible since breadmill never installed a tracing subscriber. Switches the rocm feature to target MIGraphX, adds a default tracing subscriber so EP registration success/failure is always visible, and fixes a real crash where MIGraphX's output sequence padding could index the attention mask out of bounds during mean-pooling. Also adds a CUDA backend (--cuda / backend = "cuda") mirroring the same ort execution-provider pattern, for NVIDIA hardware. Version bump: 0.1.0 -> 0.2.0.
This commit is contained in:
parent
d3843f3131
commit
2618a33fd5
10 changed files with 227 additions and 96 deletions
171
Cargo.lock
generated
171
Cargo.lock
generated
|
|
@ -25,7 +25,7 @@ checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cipher",
|
"cipher",
|
||||||
"cpufeatures 0.2.17",
|
"cpufeatures",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -111,15 +111,6 @@ dependencies = [
|
||||||
"generic-array",
|
"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]]
|
[[package]]
|
||||||
name = "block-padding"
|
name = "block-padding"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
|
@ -142,7 +133,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "breadmill"
|
name = "breadmill"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"breadsearch-shared",
|
"breadsearch-shared",
|
||||||
"hex",
|
"hex",
|
||||||
|
|
@ -154,8 +145,9 @@ dependencies = [
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2 0.11.0",
|
"sha2",
|
||||||
"tokenizers",
|
"tokenizers",
|
||||||
|
"tracing-subscriber",
|
||||||
"ureq 2.12.1",
|
"ureq 2.12.1",
|
||||||
"usearch",
|
"usearch",
|
||||||
"zip",
|
"zip",
|
||||||
|
|
@ -163,7 +155,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "breadsearch"
|
name = "breadsearch"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bread-theme",
|
"bread-theme",
|
||||||
"breadsearch-shared",
|
"breadsearch-shared",
|
||||||
|
|
@ -174,7 +166,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "breadsearch-shared"
|
name = "breadsearch-shared"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
@ -315,7 +307,7 @@ version = "0.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crypto-common 0.1.7",
|
"crypto-common",
|
||||||
"inout",
|
"inout",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -383,12 +375,6 @@ dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"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]]
|
[[package]]
|
||||||
name = "constant_time_eq"
|
name = "constant_time_eq"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|
@ -420,15 +406,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cpufeatures"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc"
|
name = "crc"
|
||||||
version = "3.4.0"
|
version = "3.4.0"
|
||||||
|
|
@ -497,15 +474,6 @@ dependencies = [
|
||||||
"typenum",
|
"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]]
|
[[package]]
|
||||||
name = "cxx"
|
name = "cxx"
|
||||||
version = "1.0.194"
|
version = "1.0.194"
|
||||||
|
|
@ -688,22 +656,11 @@ version = "0.10.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer 0.10.4",
|
"block-buffer",
|
||||||
"crypto-common 0.1.7",
|
"crypto-common",
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[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]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "5.0.1"
|
version = "5.0.1"
|
||||||
|
|
@ -779,7 +736,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1350,7 +1307,7 @@ version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest 0.10.7",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1375,15 +1332,6 @@ version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hybrid-array"
|
|
||||||
version = "0.4.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da"
|
|
||||||
dependencies = [
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
|
|
@ -1624,6 +1572,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.186"
|
version = "0.2.186"
|
||||||
|
|
@ -1708,7 +1662,7 @@ dependencies = [
|
||||||
"nom_locate",
|
"nom_locate",
|
||||||
"rand",
|
"rand",
|
||||||
"rangemap",
|
"rangemap",
|
||||||
"sha2 0.10.9",
|
"sha2",
|
||||||
"stringprep",
|
"stringprep",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"ttf-parser",
|
"ttf-parser",
|
||||||
|
|
@ -1758,6 +1712,15 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"
|
checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matrixmultiply"
|
name = "matrixmultiply"
|
||||||
version = "0.3.10"
|
version = "0.3.10"
|
||||||
|
|
@ -1775,7 +1738,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"digest 0.10.7",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1924,6 +1887,15 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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]]
|
[[package]]
|
||||||
name = "num-complex"
|
name = "num-complex"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
|
|
@ -2104,7 +2076,7 @@ version = "0.12.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest 0.10.7",
|
"digest",
|
||||||
"hmac",
|
"hmac",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -2416,7 +2388,7 @@ dependencies = [
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2587,8 +2559,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures 0.2.17",
|
"cpufeatures",
|
||||||
"digest 0.10.7",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2598,19 +2570,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures 0.2.17",
|
"cpufeatures",
|
||||||
"digest 0.10.7",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sharded-slab"
|
||||||
version = "0.11.0"
|
version = "0.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4"
|
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"lazy_static",
|
||||||
"cpufeatures 0.3.0",
|
|
||||||
"digest 0.11.3",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2758,7 +2728,7 @@ dependencies = [
|
||||||
"getrandom 0.3.4",
|
"getrandom 0.3.4",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2810,6 +2780,15 @@ dependencies = [
|
||||||
"syn",
|
"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]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.51"
|
version = "0.3.51"
|
||||||
|
|
@ -2997,6 +2976,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"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-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",
|
||||||
|
"sharded-slab",
|
||||||
|
"smallvec",
|
||||||
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3167,6 +3176,12 @@ version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
|
|
||||||
|
|
@ -80,3 +80,7 @@ Start from `breadbox/breadbox/src/main.rs`. **Reuse verbatim:** the gtk4-layer-s
|
||||||
- nomic prefixes + mean-pool + normalize must match between index and query or recall collapses.
|
- nomic prefixes + mean-pool + normalize must match between index and query or recall collapses.
|
||||||
- `ort` linking: prefer the crate's downloaded/bundled ONNX Runtime to avoid version skew with Arch's `onnxruntime`.
|
- `ort` linking: prefer the crate's downloaded/bundled ONNX Runtime to avoid version skew with Arch's `onnxruntime`.
|
||||||
- Office formats (docx/odt) are best-effort in v1; md/txt/org/pdf are the reliable path.
|
- Office formats (docx/odt) are best-effort in v1; md/txt/org/pdf are the reliable path.
|
||||||
|
- GPU EPs (ROCm/CUDA) fail to register silently at the ONNX Runtime level and fall back to CPU — always check
|
||||||
|
startup logs for `Successfully registered` before trusting a GPU build is actually accelerating. See
|
||||||
|
[README: GPU backend notes](README.md#gpu-backend-notes) for the MIGraphX-vs-ROCMExecutionProvider distinction
|
||||||
|
and the per-shape JIT-compile-and-cache behavior that matters for interactive query latency.
|
||||||
|
|
|
||||||
50
README.md
50
README.md
|
|
@ -22,13 +22,27 @@ Optional features:
|
||||||
| Feature | What it adds |
|
| Feature | What it adds |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `npu` | AMD XDNA NPU via VitisAI ONNX Runtime EP (requires Ryzen AI SDK) |
|
| `npu` | AMD XDNA NPU via VitisAI ONNX Runtime EP (requires Ryzen AI SDK) |
|
||||||
| `rocm` | AMD iGPU via ROCm ONNX Runtime EP |
|
| `rocm` | AMD iGPU via the MIGraphX ONNX Runtime EP (ROCm-backed) |
|
||||||
|
| `cuda` | NVIDIA GPU via the CUDA ONNX Runtime EP |
|
||||||
|
|
||||||
```
|
```
|
||||||
# NPU build
|
# NPU build
|
||||||
cargo build --release -p breadmill --features npu
|
cargo build --release -p breadmill --features npu
|
||||||
|
|
||||||
|
# ROCm (AMD iGPU/dGPU) build
|
||||||
|
cargo build --release -p breadmill --features rocm
|
||||||
|
|
||||||
|
# CUDA (NVIDIA GPU) build
|
||||||
|
cargo build --release -p breadmill --features cuda
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`rocm`/`cuda`/`npu` all use `ort`'s `load-dynamic` mode: at runtime, breadmill
|
||||||
|
dlopens whatever `libonnxruntime.so` the dynamic linker resolves (or
|
||||||
|
`ORT_DYLIB_PATH` if set). GPU acceleration only works if that ONNX Runtime
|
||||||
|
build actually has the matching execution provider compiled in — breadmill
|
||||||
|
logs a clear `Successfully registered` / `not enabled in this build` line for
|
||||||
|
this at startup (see [GPU backend notes](#gpu-backend-notes) below).
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
**1. Fetch the embedding model** (~550 MB, downloaded once from Hugging Face):
|
**1. Fetch the embedding model** (~550 MB, downloaded once from Hugging Face):
|
||||||
|
|
@ -89,6 +103,7 @@ breadmill status
|
||||||
# Backend flags (requires the matching Cargo feature)
|
# Backend flags (requires the matching Cargo feature)
|
||||||
breadmill --npu
|
breadmill --npu
|
||||||
breadmill --rocm
|
breadmill --rocm
|
||||||
|
breadmill --cuda
|
||||||
```
|
```
|
||||||
|
|
||||||
## Config
|
## Config
|
||||||
|
|
@ -109,7 +124,7 @@ snippet_len = 200 # max characters in result snippet
|
||||||
[model]
|
[model]
|
||||||
name = "nomic-embed-text-v1.5"
|
name = "nomic-embed-text-v1.5"
|
||||||
dim = 768
|
dim = 768
|
||||||
backend = "cpu" # "cpu", "npu", or "rocm"
|
backend = "cpu" # "cpu", "npu", "rocm", or "cuda"
|
||||||
```
|
```
|
||||||
|
|
||||||
`roots` and `excludes` support `~/` expansion. The index respects `.gitignore` files found during the walk.
|
`roots` and `excludes` support `~/` expansion. The index respects `.gitignore` files found during the walk.
|
||||||
|
|
@ -124,6 +139,37 @@ Set `backend = "npu"` in config (or pass `--npu`) when running a build compiled
|
||||||
4. `/etc/vaip_config.json`
|
4. `/etc/vaip_config.json`
|
||||||
5. `/opt/xilinx/vaip_config.json`
|
5. `/opt/xilinx/vaip_config.json`
|
||||||
|
|
||||||
|
### GPU backend notes
|
||||||
|
|
||||||
|
Both `rocm` and `cuda` need a system ONNX Runtime that was actually built with
|
||||||
|
the matching execution provider — the crate's own downloaded binary is CPU-only.
|
||||||
|
Point `ORT_DYLIB_PATH` at one, or install a distro package that provides
|
||||||
|
`libonnxruntime.so` with the EP baked in and let the dynamic linker find it.
|
||||||
|
|
||||||
|
**ROCm (`--rocm` / `backend = "rocm"`)** targets ONNX Runtime's **MIGraphX**
|
||||||
|
execution provider, not the classic `ROCMExecutionProvider`. Distro
|
||||||
|
ROCm-enabled ONNX Runtime packages (e.g. Arch's `onnxruntime-rocm`) are
|
||||||
|
commonly built with `--use_migraphx` rather than `--use_rocm`, so this is the
|
||||||
|
EP that's actually available in practice; the classic ROCm EP needs a bespoke
|
||||||
|
`--use_rocm` build most distros don't package. Startup logs a
|
||||||
|
`Successfully registered `MIGraphXExecutionProvider`` line when it's really
|
||||||
|
active — check for it if in doubt, since a failed GPU EP registration falls
|
||||||
|
back to CPU silently at the ONNX Runtime level (breadmill's own log line is
|
||||||
|
only a statement of intent, not a confirmation).
|
||||||
|
|
||||||
|
MIGraphX JIT-compiles the model per distinct input sequence length and caches
|
||||||
|
the compiled kernel to disk (each compile takes ~60–120s and produces a
|
||||||
|
~500MB `.mxr` file). Set `ORT_MIGRAPHX_MODEL_CACHE_PATH=/path/to/cache` so
|
||||||
|
that cost is paid once per shape instead of on every daemon restart. Because
|
||||||
|
query text length varies, expect an occasional multi-second stall the first
|
||||||
|
time a new token length is seen — fine for background document indexing,
|
||||||
|
noticeable for interactive query embedding.
|
||||||
|
|
||||||
|
**CUDA (`--cuda` / `backend = "cuda"`)** targets the standard
|
||||||
|
`CUDAExecutionProvider` and needs a CUDA-enabled ONNX Runtime + a working
|
||||||
|
CUDA/cuDNN install. Unverified on real NVIDIA hardware in this repo — only
|
||||||
|
compile-checked, since development happened on an AMD-only machine.
|
||||||
|
|
||||||
## Runtime paths
|
## Runtime paths
|
||||||
|
|
||||||
| Purpose | Path |
|
| Purpose | Path |
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,19 @@
|
||||||
[package]
|
[package]
|
||||||
name = "breadmill"
|
name = "breadmill"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
npu = ["ort/vitis", "ort/load-dynamic"]
|
npu = ["ort/vitis", "ort/load-dynamic"]
|
||||||
rocm = ["ort/rocm", "ort/load-dynamic"]
|
# "rocm" targets the MIGraphX execution provider, not ONNX Runtime's classic
|
||||||
|
# ROCMExecutionProvider (--use_rocm build). Distro ROCm-enabled ONNX Runtime
|
||||||
|
# packages (e.g. Arch's onnxruntime-rocm) are commonly built with --use_migraphx
|
||||||
|
# instead; the classic ROCm EP needs a bespoke --use_rocm build that ships
|
||||||
|
# libonnxruntime_providers_rocm.so, which most distros don't package.
|
||||||
|
rocm = ["ort/migraphx", "ort/load-dynamic"]
|
||||||
|
cuda = ["ort/cuda", "ort/load-dynamic"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "breadmill"
|
name = "breadmill"
|
||||||
|
|
@ -26,6 +32,10 @@ breadsearch-shared = { path = "../breadsearch-shared" }
|
||||||
ort = { version = "2.0.0-rc.12", default-features = false, features = ["std", "tracing", "download-binaries", "tls-native", "copy-dylibs", "api-23"] }
|
ort = { version = "2.0.0-rc.12", default-features = false, features = ["std", "tracing", "download-binaries", "tls-native", "copy-dylibs", "api-23"] }
|
||||||
tokenizers = "0"
|
tokenizers = "0"
|
||||||
|
|
||||||
|
# Surfaces ort's own EP-registration tracing (e.g. a GPU EP silently failing to
|
||||||
|
# register and falling back to CPU) as visible log output instead of nowhere.
|
||||||
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|
||||||
# Vector index
|
# Vector index
|
||||||
usearch = "2"
|
usearch = "2"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,14 @@ pub enum Backend {
|
||||||
/// AMD XDNA NPU via the VitisAI ONNX Runtime execution provider.
|
/// AMD XDNA NPU via the VitisAI ONNX Runtime execution provider.
|
||||||
/// `cache_dir` is used to store the compiled NPU model between runs.
|
/// `cache_dir` is used to store the compiled NPU model between runs.
|
||||||
Npu { cache_dir: PathBuf },
|
Npu { cache_dir: PathBuf },
|
||||||
/// AMD iGPU via the ROCm ONNX Runtime execution provider.
|
/// AMD iGPU via the MIGraphX ONNX Runtime execution provider (ROCm-backed).
|
||||||
|
/// Distro ROCm ONNX Runtime builds (e.g. Arch's onnxruntime-rocm) are
|
||||||
|
/// commonly compiled with `--use_migraphx`, not `--use_rocm`, so this
|
||||||
|
/// targets `MIGraphXExecutionProvider` rather than the classic
|
||||||
|
/// `ROCMExecutionProvider`.
|
||||||
Rocm,
|
Rocm,
|
||||||
|
/// NVIDIA GPU via the CUDA ONNX Runtime execution provider.
|
||||||
|
Cuda,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OrtEmbedder {
|
pub struct OrtEmbedder {
|
||||||
|
|
@ -108,11 +114,14 @@ impl OrtEmbedder {
|
||||||
let actual_seq = shape[1] as usize;
|
let actual_seq = shape[1] as usize;
|
||||||
let actual_dim = shape[2] as usize;
|
let actual_dim = shape[2] as usize;
|
||||||
|
|
||||||
// Mean-pool over non-padding positions
|
// Mean-pool over non-padding positions. Some execution providers (e.g.
|
||||||
|
// MIGraphX) pad the output sequence dimension for kernel efficiency, so
|
||||||
|
// actual_seq can exceed mask.len() — only positions covered by our own
|
||||||
|
// attention mask are meaningful, so cap the loop at whichever is shorter.
|
||||||
let mut result = vec![0.0f32; actual_dim];
|
let mut result = vec![0.0f32; actual_dim];
|
||||||
let mut count = 0usize;
|
let mut count = 0usize;
|
||||||
|
|
||||||
for t in 0..actual_seq {
|
for t in 0..actual_seq.min(mask.len()) {
|
||||||
if mask[t] > 0 {
|
if mask[t] > 0 {
|
||||||
for d in 0..actual_dim {
|
for d in 0..actual_dim {
|
||||||
result[d] += data[t * actual_dim + d];
|
result[d] += data[t * actual_dim + d];
|
||||||
|
|
@ -155,6 +164,7 @@ fn configure_eps(builder: SessionBuilder, backend: &Backend) -> Result<SessionBu
|
||||||
Backend::Cpu => Ok(builder),
|
Backend::Cpu => Ok(builder),
|
||||||
Backend::Npu { cache_dir } => npu_session(builder, cache_dir),
|
Backend::Npu { cache_dir } => npu_session(builder, cache_dir),
|
||||||
Backend::Rocm => rocm_session(builder),
|
Backend::Rocm => rocm_session(builder),
|
||||||
|
Backend::Cuda => cuda_session(builder),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,14 +205,19 @@ fn build_vitis_ep(cache_dir: &Path) -> Result<ort::ep::ExecutionProviderDispatch
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- ROCm EP (AMD iGPU) -----------------------------------------------------
|
// ---- MIGraphX EP (AMD iGPU, ROCm-backed) -------------------------------------
|
||||||
|
|
||||||
#[cfg(feature = "rocm")]
|
#[cfg(feature = "rocm")]
|
||||||
fn rocm_session(builder: SessionBuilder) -> Result<SessionBuilder, String> {
|
fn rocm_session(builder: SessionBuilder) -> Result<SessionBuilder, String> {
|
||||||
eprintln!("breadmill: using ROCm execution provider (device 0)");
|
eprintln!("breadmill: using MIGraphX execution provider (device 0)");
|
||||||
|
eprintln!(
|
||||||
|
"breadmill: note — check the log line above/below for \"Successfully registered \
|
||||||
|
`MIGraphXExecutionProvider`\"; if it's missing, the ONNX Runtime in use wasn't built \
|
||||||
|
with MIGraphX support and inference silently fell back to CPU"
|
||||||
|
);
|
||||||
builder
|
builder
|
||||||
.with_execution_providers([
|
.with_execution_providers([
|
||||||
ort::execution_providers::ROCmExecutionProvider::default().build(),
|
ort::ep::MIGraphX::default().with_device_id(0).build(),
|
||||||
ort::ep::CPU::default().build(),
|
ort::ep::CPU::default().build(),
|
||||||
])
|
])
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
|
|
@ -214,6 +229,30 @@ fn rocm_session(builder: SessionBuilder) -> Result<SessionBuilder, String> {
|
||||||
Ok(builder)
|
Ok(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- CUDA EP (NVIDIA GPU) ----------------------------------------------------
|
||||||
|
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
fn cuda_session(builder: SessionBuilder) -> Result<SessionBuilder, String> {
|
||||||
|
eprintln!("breadmill: using CUDA execution provider (device 0)");
|
||||||
|
eprintln!(
|
||||||
|
"breadmill: note — check the log line above/below for \"Successfully registered \
|
||||||
|
`CUDAExecutionProvider`\"; if it's missing, the ONNX Runtime in use wasn't built \
|
||||||
|
with CUDA support and inference silently fell back to CPU"
|
||||||
|
);
|
||||||
|
builder
|
||||||
|
.with_execution_providers([
|
||||||
|
ort::ep::CUDA::default().with_device_id(0).build(),
|
||||||
|
ort::ep::CPU::default().build(),
|
||||||
|
])
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "cuda"))]
|
||||||
|
fn cuda_session(builder: SessionBuilder) -> Result<SessionBuilder, String> {
|
||||||
|
eprintln!("breadmill: CUDA backend requested but not compiled in (rebuild with --features cuda); using CPU");
|
||||||
|
Ok(builder)
|
||||||
|
}
|
||||||
|
|
||||||
/// Locate the VitisAI EP config file required by the AMD Ryzen AI SDK.
|
/// Locate the VitisAI EP config file required by the AMD Ryzen AI SDK.
|
||||||
///
|
///
|
||||||
/// Search order:
|
/// Search order:
|
||||||
|
|
|
||||||
|
|
@ -24,17 +24,27 @@ const TOKENIZER_URL: &str =
|
||||||
"https://huggingface.co/nomic-ai/nomic-embed-text-v1.5/resolve/main/tokenizer.json";
|
"https://huggingface.co/nomic-ai/nomic-embed-text-v1.5/resolve/main/tokenizer.json";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
// Surfaces ort's EP-registration warnings/errors (e.g. a GPU EP silently
|
||||||
|
// falling back to CPU) by default, without requiring RUST_LOG to be set.
|
||||||
|
tracing_subscriber::fmt()
|
||||||
|
.with_env_filter(
|
||||||
|
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||||
|
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn,ort=info")),
|
||||||
|
)
|
||||||
|
.init();
|
||||||
|
|
||||||
let raw_args: Vec<String> = std::env::args().collect();
|
let raw_args: Vec<String> = std::env::args().collect();
|
||||||
|
|
||||||
// Extract global flags before command dispatch.
|
// Extract global flags before command dispatch.
|
||||||
let use_npu = raw_args.iter().any(|a| a == "--npu");
|
let use_npu = raw_args.iter().any(|a| a == "--npu");
|
||||||
let use_rocm = raw_args.iter().any(|a| a == "--rocm");
|
let use_rocm = raw_args.iter().any(|a| a == "--rocm");
|
||||||
|
let use_cuda = raw_args.iter().any(|a| a == "--cuda");
|
||||||
|
|
||||||
// Build a view of argv without backend flags for command matching.
|
// Build a view of argv without backend flags for command matching.
|
||||||
let args: Vec<&str> = raw_args
|
let args: Vec<&str> = raw_args
|
||||||
.iter()
|
.iter()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.filter(|a| a.as_str() != "--npu" && a.as_str() != "--rocm")
|
.filter(|a| a.as_str() != "--npu" && a.as_str() != "--rocm" && a.as_str() != "--cuda")
|
||||||
.map(|s| s.as_str())
|
.map(|s| s.as_str())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
@ -49,7 +59,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some("--reindex") | Some("reindex") => {
|
Some("--reindex") | Some("reindex") => {
|
||||||
if let Err(e) = run_daemon(true, use_npu, use_rocm) {
|
if let Err(e) = run_daemon(true, use_npu, use_rocm, use_cuda) {
|
||||||
eprintln!("breadmill: {}", e);
|
eprintln!("breadmill: {}", e);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +76,7 @@ fn main() {
|
||||||
cli_status();
|
cli_status();
|
||||||
}
|
}
|
||||||
None | Some("serve") | Some("--serve") => {
|
None | Some("serve") | Some("--serve") => {
|
||||||
if let Err(e) = run_daemon(false, use_npu, use_rocm) {
|
if let Err(e) = run_daemon(false, use_npu, use_rocm, use_cuda) {
|
||||||
eprintln!("breadmill: {}", e);
|
eprintln!("breadmill: {}", e);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +84,7 @@ fn main() {
|
||||||
Some(cmd) => {
|
Some(cmd) => {
|
||||||
eprintln!("breadmill: unknown command: {}", cmd);
|
eprintln!("breadmill: unknown command: {}", cmd);
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"usage: breadmill [serve|reindex|fetch-model|query <text>|status] [--npu|--rocm] [--version]"
|
"usage: breadmill [serve|reindex|fetch-model|query <text>|status] [--npu|--rocm|--cuda] [--version]"
|
||||||
);
|
);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +93,7 @@ fn main() {
|
||||||
|
|
||||||
// ---- Daemon -----------------------------------------------------------------
|
// ---- Daemon -----------------------------------------------------------------
|
||||||
|
|
||||||
fn run_daemon(force_reindex: bool, use_npu: bool, use_rocm: bool) -> Result<(), String> {
|
fn run_daemon(force_reindex: bool, use_npu: bool, use_rocm: bool, use_cuda: bool) -> Result<(), String> {
|
||||||
let config = breadsearch_shared::Config::load();
|
let config = breadsearch_shared::Config::load();
|
||||||
let state_dir = breadsearch_shared::state_dir();
|
let state_dir = breadsearch_shared::state_dir();
|
||||||
let cache_dir = breadsearch_shared::cache_dir();
|
let cache_dir = breadsearch_shared::cache_dir();
|
||||||
|
|
@ -101,6 +111,9 @@ fn run_daemon(force_reindex: bool, use_npu: bool, use_rocm: bool) -> Result<(),
|
||||||
} else if use_rocm || config.model.backend == "rocm" {
|
} else if use_rocm || config.model.backend == "rocm" {
|
||||||
eprintln!("breadmill: ROCm backend selected");
|
eprintln!("breadmill: ROCm backend selected");
|
||||||
Backend::Rocm
|
Backend::Rocm
|
||||||
|
} else if use_cuda || config.model.backend == "cuda" {
|
||||||
|
eprintln!("breadmill: CUDA backend selected");
|
||||||
|
Backend::Cuda
|
||||||
} else {
|
} else {
|
||||||
Backend::Cpu
|
Backend::Cpu
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "breadsearch-shared"
|
name = "breadsearch-shared"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ pub struct ModelConfig {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[serde(default = "default_dim")]
|
#[serde(default = "default_dim")]
|
||||||
pub dim: usize,
|
pub dim: usize,
|
||||||
/// Compute backend: "cpu" or "npu" (VitisAI/XDNA).
|
/// Compute backend: "cpu", "npu" (VitisAI/XDNA), "rocm" (MIGraphX/AMD GPU), or "cuda" (NVIDIA GPU).
|
||||||
#[serde(default = "default_backend")]
|
#[serde(default = "default_backend")]
|
||||||
pub backend: String,
|
pub backend: String,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "breadsearch"
|
name = "breadsearch"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,10 @@ After=default.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
|
# Uncomment if built with --features rocm: persists MIGraphX's compiled-kernel
|
||||||
|
# cache across restarts (each new sequence length otherwise costs a ~60-120s
|
||||||
|
# recompile). See README.md#gpu-backend-notes.
|
||||||
|
#Environment=ORT_MIGRAPHX_MODEL_CACHE_PATH=%h/.cache/breadsearch/migraphx-cache
|
||||||
ExecStart=%h/.cargo/bin/breadmill
|
ExecStart=%h/.cargo/bin/breadmill
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue