diff --git a/Cargo.lock b/Cargo.lock index ed2666f4e8..6e38b96e17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6050,6 +6050,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memmap2" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deaba38d7abf1d4cca21cc89e932e542ba2b9258664d2a9ef0e61512039c9375" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.6.5" @@ -11143,6 +11152,7 @@ dependencies = [ "jemallocator", "jsonrpsee", "lru 0.10.0", + "memmap2 0.9.0", "parity-scale-codec", "parking_lot 0.12.1", "rand 0.8.5", diff --git a/crates/subspace-farmer/Cargo.toml b/crates/subspace-farmer/Cargo.toml index 8bc5583ee7..2f1c3ea36c 100644 --- a/crates/subspace-farmer/Cargo.toml +++ b/crates/subspace-farmer/Cargo.toml @@ -59,3 +59,6 @@ zeroize = "1.6.0" # The only triple tested and confirmed as working in `jemallocator` crate is `x86_64-unknown-linux-gnu` [target.'cfg(all(target_arch = "x86_64", target_vendor = "unknown", target_os = "linux", target_env = "gnu"))'.dependencies] jemallocator = "0.5.0" + +[target.'cfg(windows)'.dependencies] +memmap2 = "0.9.0" diff --git a/crates/subspace-farmer/src/single_disk_farm/farming.rs b/crates/subspace-farmer/src/single_disk_farm/farming.rs index 5f2e5831de..9b5237f0f1 100644 --- a/crates/subspace-farmer/src/single_disk_farm/farming.rs +++ b/crates/subspace-farmer/src/single_disk_farm/farming.rs @@ -3,6 +3,8 @@ use crate::node_client::NodeClient; use crate::single_disk_farm::Handlers; use futures::channel::mpsc; use futures::StreamExt; +#[cfg(windows)] +use memmap2::{Mmap, MmapOptions}; use parking_lot::{Mutex, RwLock}; use rayon::prelude::*; use rayon::{ThreadPoolBuildError, ThreadPoolBuilder}; @@ -27,6 +29,16 @@ use tracing::{debug, error, trace, warn}; /// many solutions. const SOLUTIONS_LIMIT: usize = 1; +#[cfg(windows)] +struct MmapWrapper(Mmap); + +#[cfg(windows)] +impl ReadAt for MmapWrapper { + fn read_at(&self, buf: &mut [u8], offset: usize) -> io::Result<()> { + self.0.read_at(buf, offset) + } +} + /// Errors that happen during farming #[derive(Debug, Error)] pub enum FarmingError { @@ -136,7 +148,27 @@ where .into_par_iter() .zip(&*sectors_metadata) .filter_map(|(sector_index, sector_metadata)| { + #[cfg(not(windows))] let sector = plot_file.offset(sector_index * sector_size); + // On Windows random read is horrible in terms of performance, memory-mapped I/O + // helps + // TODO: Remove this once https://internals.rust-lang.org/t/introduce-write-all-at-read-exact-at-on-windows/19649 + // or similar exists in standard library + #[cfg(windows)] + let maybe_sector = unsafe { + MmapOptions::new() + .offset(sector_index as u64 * sector_size as u64) + .len(sector_size) + .map(plot_file) + }; + #[cfg(windows)] + let sector = match maybe_sector { + Ok(sector) => MmapWrapper(sector), + Err(error) => { + warn!(%error, %sector_index, "Failed to memory-map sector"); + return None; + } + }; let sector_index = sector_index as u16; if maybe_sector_being_modified == Some(sector_index) {