1
0
Fork 0
mirror of https://github.com/BLAKE3-team/BLAKE3 synced 2024-05-28 01:16:02 +02:00

Improve performance of `--no-mmap` mode by enabling multithread.

This uses a double buffer of 1MiB each, reading to one buffer while
hashing the other in parallel. This is around 2x as fast as hashing
singlethreadedly on my machine (ryzen 2600) with an in memory benchmark.

This is still 2x slower than using memmap.
This commit is contained in:
ultrabear 2023-11-05 21:21:47 -08:00
parent 92e4cd71be
commit 1322974a85
No known key found for this signature in database
GPG Key ID: 6A5BDAF57DFFD6A0
3 changed files with 57 additions and 1 deletions

7
b3sum/Cargo.lock generated
View File

@ -85,6 +85,7 @@ dependencies = [
"hex",
"memmap2",
"rayon",
"read_chunks",
"tempfile",
"wild",
]
@ -362,6 +363,12 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "read_chunks"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dda95aba172630718d3dffb3c2a3c316848fd9f2725898f56af81fdfcd3c8abf"
[[package]]
name = "redox_syscall"
version = "0.3.5"

View File

@ -20,8 +20,17 @@ clap = { version = "4.0.8", features = ["derive", "wrap_help"] }
hex = "0.4.0"
memmap2 = "0.7.0"
rayon = "1.2.1"
read_chunks = "0.2.0"
wild = "2.0.3"
[dev-dependencies]
duct = "0.13.3"
tempfile = "3.1.0"
[profile.dev]
opt-level = 1
[profile.release]
overflow-checks = true
lto = "thin"

View File

@ -163,6 +163,44 @@ impl Args {
}
}
fn hash_reader_parallel(
hasher: &mut blake3::Hasher,
reader: &mut (impl Read + Send),
len: Option<u64>,
) -> Result<()> {
use read_chunks::ReadExt;
const BUF_SIZE: usize = 1024 * 1024;
const MIN_SIZE: u64 = BUF_SIZE as u64;
if len.is_some_and(|s| s < MIN_SIZE) {
hasher.update_reader(reader)?;
return Ok(());
}
let mut hashing = vec![0; BUF_SIZE];
let mut hashing_res = reader.keep_reading(&mut *hashing)?;
let mut reading_to = vec![0; BUF_SIZE];
let mut reading_res = None::<io::Result<usize>>;
while hashing_res != 0 {
rayon::scope(|s| {
s.spawn(|_| {
reading_res = Some(reader.keep_reading(&mut *reading_to));
});
s.spawn(|_| {
hasher.update_rayon(&hashing[..hashing_res]);
});
});
hashing_res = reading_res.take().unwrap()?;
(hashing, reading_to) = (reading_to, hashing);
}
Ok(())
}
fn hash_path(args: &Args, path: &Path) -> Result<blake3::OutputReader> {
let mut hasher = args.base_hasher.clone();
if path == Path::new("-") {
@ -171,7 +209,9 @@ fn hash_path(args: &Args, path: &Path) -> Result<blake3::OutputReader> {
}
hasher.update_reader(io::stdin().lock())?;
} else if args.no_mmap() {
hasher.update_reader(File::open(path)?)?;
let length = std::fs::metadata(path)?.len();
hash_reader_parallel(&mut hasher, &mut File::open(path)?, Some(length))?;
} else {
// The fast path: Try to mmap the file and hash it with multiple threads.
hasher.update_mmap_rayon(path)?;