diff options
| -rw-r--r-- | .github/workflows/ci.yml | 1 | ||||
| -rw-r--r-- | c/blake3_c_rust_bindings/Cargo.toml | 3 | ||||
| -rw-r--r-- | c/blake3_c_rust_bindings/build.rs | 17 | ||||
| -rw-r--r-- | c/blake3_c_rust_bindings/src/lib.rs | 41 | ||||
| -rw-r--r-- | c/blake3_c_rust_bindings/src/test.rs | 46 | ||||
| -rw-r--r-- | c/blake3_llfio.cpp | 14 |
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); } |
