aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack O'Connor <[email protected]>2025-03-09 11:29:19 -0700
committerJack O'Connor <[email protected]>2025-03-09 16:15:39 -0700
commit063dda6837e1e944c5bb57b8405bf68cae196012 (patch)
tree084eaf5c83dd690390cd171b59275685bc6b45d5
parent6d0531352bd9352fab9d78c8a8670a9979c30ba3 (diff)
llfio support in blake3_c_rust_bindingsrust_bindings_tbb_llfio
Requires a CPLUS_INCLUDE_PATH setting similar to: export CPLUS_INCLUDE_PATH=/tmp/llfio/include:/tmp/outcome/include:/tmp/quickcpplib/include
-rw-r--r--.github/workflows/ci.yml1
-rw-r--r--c/blake3_c_rust_bindings/Cargo.toml3
-rw-r--r--c/blake3_c_rust_bindings/build.rs17
-rw-r--r--c/blake3_c_rust_bindings/src/lib.rs41
-rw-r--r--c/blake3_c_rust_bindings/src/test.rs46
-rw-r--r--c/blake3_llfio.cpp14
6 files changed, 115 insertions, 7 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0c5d6a9..2315afd 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -150,6 +150,7 @@ jobs:
- name: cargo test C bindings with TBB
run: cargo test --features=tbb
working-directory: ./c/blake3_c_rust_bindings
+ # TODO: How to fetch LLFIO for testing here?
# Reference impl doc test.
- name: reference impl doc test
run: cargo test
diff --git a/c/blake3_c_rust_bindings/Cargo.toml b/c/blake3_c_rust_bindings/Cargo.toml
index 4c3a252..7d03643 100644
--- a/c/blake3_c_rust_bindings/Cargo.toml
+++ b/c/blake3_c_rust_bindings/Cargo.toml
@@ -18,6 +18,8 @@ prefer_intrinsics = []
neon = []
# Enable TBB-based multithreading.
tbb = []
+# Enable LLFIO-based memory mapping.
+llfio = []
[dev-dependencies]
arrayref = "0.3.5"
@@ -26,6 +28,7 @@ page_size = "0.6.0"
rand = "0.9.0"
rand_chacha = "0.9.0"
reference_impl = { path = "../../reference_impl" }
+tempfile = "3.18.0"
[build-dependencies]
cc = "1.0.48"
diff --git a/c/blake3_c_rust_bindings/build.rs b/c/blake3_c_rust_bindings/build.rs
index e176dac..24991ff 100644
--- a/c/blake3_c_rust_bindings/build.rs
+++ b/c/blake3_c_rust_bindings/build.rs
@@ -86,16 +86,33 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if cfg!(feature = "tbb") {
base_build.define("BLAKE3_USE_TBB", "1");
}
+ if cfg!(feature = "llfio") {
+ base_build.define("BLAKE3_USE_LLFIO", "1");
+ }
base_build.compile("blake3_base");
if cfg!(feature = "tbb") {
let mut tbb_build = new_cpp_build();
tbb_build.define("BLAKE3_USE_TBB", "1");
+ if cfg!(feature = "llfio") {
+ tbb_build.define("BLAKE3_USE_LLFIO", "1");
+ }
tbb_build.file(c_dir_path("blake3_tbb.cpp"));
tbb_build.compile("blake3_tbb");
println!("cargo::rustc-link-lib=tbb");
}
+ if cfg!(feature = "llfio") {
+ let mut llfio_build = new_cpp_build();
+ llfio_build.define("BLAKE3_USE_LLFIO", "1");
+ llfio_build.define("LLFIO_EXPERIMENTAL_STATUS_CODE", "2");
+ if cfg!(feature = "tbb") {
+ llfio_build.define("BLAKE3_USE_TBB", "1");
+ }
+ llfio_build.file(c_dir_path("blake3_llfio.cpp"));
+ llfio_build.compile("blake3_llfio");
+ }
+
if is_x86_64() && !defined("CARGO_FEATURE_PREFER_INTRINSICS") {
// On 64-bit, use the assembly implementations, unless the
// "prefer_intrinsics" feature is enabled.
diff --git a/c/blake3_c_rust_bindings/src/lib.rs b/c/blake3_c_rust_bindings/src/lib.rs
index c2b3989..b82794f 100644
--- a/c/blake3_c_rust_bindings/src/lib.rs
+++ b/c/blake3_c_rust_bindings/src/lib.rs
@@ -6,6 +6,11 @@
use std::ffi::{c_void, CString};
use std::mem::MaybeUninit;
+#[cfg(feature = "llfio")]
+use std::ffi::c_char;
+#[cfg(feature = "llfio")]
+use std::path::Path;
+
#[cfg(test)]
mod test;
@@ -93,6 +98,32 @@ impl Hasher {
}
}
+ // TODO: This should return a Result.
+ #[cfg(feature = "llfio")]
+ pub fn update_mmap(&mut self, path: impl AsRef<Path>) {
+ if !path.as_ref().as_os_str().is_ascii() {
+ unimplemented!("non-ASCII path support is TODO");
+ }
+ let path_str = path.as_ref().to_str().unwrap();
+ let path_cstring = CString::new(path_str.as_bytes()).expect("no null characters allowed");
+ unsafe {
+ ffi::blake3_hasher_update_mmap(&mut self.0, path_cstring.as_ptr() as *const c_char);
+ }
+ }
+
+ // TODO: This should return a Result.
+ #[cfg(all(feature = "tbb", feature = "llfio"))]
+ pub fn update_mmap_tbb(&mut self, path: impl AsRef<Path>) {
+ if !path.as_ref().as_os_str().is_ascii() {
+ unimplemented!("non-ASCII path support is TODO");
+ }
+ let path_str = path.as_ref().to_str().unwrap();
+ let path_cstring = CString::new(path_str.as_bytes()).expect("no null characters allowed");
+ unsafe {
+ ffi::blake3_hasher_update_mmap_tbb(&mut self.0, path_cstring.as_ptr() as *const c_char);
+ }
+ }
+
pub fn finalize(&self, output: &mut [u8]) {
unsafe {
ffi::blake3_hasher_finalize(&self.0, output.as_mut_ptr(), output.len());
@@ -157,6 +188,16 @@ pub mod ffi {
input: *const ::std::os::raw::c_void,
input_len: usize,
);
+ #[cfg(feature = "llfio")]
+ pub fn blake3_hasher_update_mmap(
+ self_: *mut blake3_hasher,
+ path: *const ::std::os::raw::c_char,
+ );
+ #[cfg(all(feature = "tbb", feature = "llfio"))]
+ pub fn blake3_hasher_update_mmap_tbb(
+ self_: *mut blake3_hasher,
+ path: *const ::std::os::raw::c_char,
+ );
pub fn blake3_hasher_finalize(self_: *const blake3_hasher, out: *mut u8, out_len: usize);
pub fn blake3_hasher_finalize_seek(
self_: *const blake3_hasher,
diff --git a/c/blake3_c_rust_bindings/src/test.rs b/c/blake3_c_rust_bindings/src/test.rs
index 6ff61ec..b78a2e4 100644
--- a/c/blake3_c_rust_bindings/src/test.rs
+++ b/c/blake3_c_rust_bindings/src/test.rs
@@ -694,3 +694,49 @@ fn test_reset() {
assert_eq!(reference_hash, output);
}
}
+
+#[test]
+#[cfg(feature = "llfio")]
+fn test_mmap() -> Result<(), std::io::Error> {
+ // This is a brief test, since update_mmap_rayon() is mostly a wrapper around update(),
+ // which already has substantial testing.
+ use std::io::prelude::*;
+ let mut input = vec![0; 1_000_000];
+ paint_test_input(&mut input);
+ let mut reference_hasher = reference_impl::Hasher::new();
+ reference_hasher.update(&input);
+ let mut reference_hash = [0; 32];
+ reference_hasher.finalize(&mut reference_hash);
+ let mut tempfile = tempfile::NamedTempFile::new()?;
+ tempfile.write_all(&input)?;
+ tempfile.flush()?;
+ let mut hasher = crate::Hasher::new();
+ hasher.update_mmap(tempfile.path());
+ let mut hash = [0; 32];
+ hasher.finalize(&mut hash);
+ assert_eq!(hash, reference_hash);
+ Ok(())
+}
+
+#[test]
+#[cfg(all(feature = "llfio", feature = "tbb"))]
+fn test_mmap_tbb() -> Result<(), std::io::Error> {
+ // This is a brief test, since update_mmap_rayon() is mostly a wrapper around update_rayon(),
+ // which already has substantial testing.
+ use std::io::prelude::*;
+ let mut input = vec![0; 1_000_000];
+ paint_test_input(&mut input);
+ let mut reference_hasher = reference_impl::Hasher::new();
+ reference_hasher.update(&input);
+ let mut reference_hash = [0; 32];
+ reference_hasher.finalize(&mut reference_hash);
+ let mut tempfile = tempfile::NamedTempFile::new()?;
+ tempfile.write_all(&input)?;
+ tempfile.flush()?;
+ let mut hasher = crate::Hasher::new();
+ hasher.update_mmap_tbb(tempfile.path());
+ let mut hash = [0; 32];
+ hasher.finalize(&mut hash);
+ assert_eq!(hash, reference_hash);
+ Ok(())
+}
diff --git a/c/blake3_llfio.cpp b/c/blake3_llfio.cpp
index 1d5ba33..e2adac8 100644
--- a/c/blake3_llfio.cpp
+++ b/c/blake3_llfio.cpp
@@ -13,10 +13,9 @@ template <class... Ts> struct overloads : Ts... {
// NOTE: deduction guide only needed for Apple Clang now.
template <class... Ts> overloads(Ts...) -> overloads<Ts...>;
-INLINE auto copy_wide(blake3_hasher *self, llfio::path_view path,
- llfio::file_handle &file) noexcept
+INLINE auto copy_wide(blake3_hasher *self, llfio::file_handle &file) noexcept
-> llfio::result<std::uint64_t> {
- std::array<std::byte, 65535> buffer{};
+ std::array<std::byte, 65536> buffer{};
std::uint64_t total = 0;
while (true) {
auto result = llfio::read(file, total, {buffer});
@@ -75,7 +74,7 @@ INLINE void blake3_hasher_update_mmap_base(blake3_hasher *self,
return llfio::success();
},
[=](llfio::file_handle &file) -> llfio::result<void> {
- OUTCOME_TRY(copy_wide(self, path, file));
+ OUTCOME_TRY(copy_wide(self, file));
return llfio::success();
},
},
@@ -89,14 +88,15 @@ INLINE void blake3_hasher_update_mmap_base(blake3_hasher *self,
}
}
-void blake3_hasher_update_mmap(blake3_hasher *self, char const *path) noexcept {
+extern "C" void blake3_hasher_update_mmap(blake3_hasher *self,
+ char const *path) noexcept {
bool use_tbb = false;
blake3_hasher_update_mmap_base(self, path, use_tbb);
}
#if defined(BLAKE3_USE_TBB)
-void blake3_hasher_update_mmap_tbb(blake3_hasher *self,
- char const *path) noexcept {
+extern "C" void blake3_hasher_update_mmap_tbb(blake3_hasher *self,
+ char const *path) noexcept {
bool use_tbb = true;
blake3_hasher_update_mmap_base(self, path, use_tbb);
}