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:
parent
92e4cd71be
commit
1322974a85
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)?;
|
||||
|
|
Loading…
Reference in New Issue