Skip to content

Commit

Permalink
feat: limit thread number to 1 when HDD is detected
Browse files Browse the repository at this point in the history
On HDD, multi-threaded du won't provide any performance benefit over
the single-threaded one. Therefore, when HDD is detected on one of
the files, limit the thread number to 1.

This PR fixes issue KSXGitHub#257.
  • Loading branch information
Integral-Tech committed Nov 24, 2024
1 parent ce88bd4 commit 0e7a836
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 1 deletion.
105 changes: 105 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ clap_complete = { version = "^4.5.36", optional = true }
clap-utilities = { version = "^0.2.0", optional = true }
serde = { version = "^1.0.214", optional = true }
serde_json = { version = "^1.0.132", optional = true }
sysinfo = "0.32.0"

[dev-dependencies]
build-fs-tree = "^0.7.1"
Expand Down
42 changes: 41 additions & 1 deletion src/app/sub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ use crate::{
visualizer::{BarAlignment, ColumnWidthDistribution, Direction, Visualizer},
};
use serde::Serialize;
use std::{io::stdout, iter::once, num::NonZeroUsize, path::PathBuf};
use std::{
fs,
io::stdout,
iter::once,
num::NonZeroUsize,
path::{Path, PathBuf},
};
use sysinfo::{DiskKind, Disks};

/// The sub program of the main application.
pub struct Sub<Size, SizeGetter, Report>
Expand Down Expand Up @@ -69,6 +76,29 @@ where
no_sort,
} = self;

// If one of the files is on HDD, set thread number to 1
let disks = Disks::new_with_refreshed_list();

if files
.iter()
.filter_map(|file| fs::canonicalize(&file).ok())
.any(|path| {
let mount_points: Vec<_> = disks.iter().map(|disk| disk.mount_point()).collect();
if let Some(mount_point) = find_mountpoint(&path, &mount_points) {
disks.iter().any(|disk| {
matches!(disk.kind(), DiskKind::HDD) && disk.mount_point() == mount_point
})
} else {
false
}
})
{
rayon::ThreadPoolBuilder::new()
.num_threads(1)
.build_global()
.unwrap();
}

let mut iter = files
.into_iter()
.map(|root| -> DataTree<OsStringDisplay, Size> {
Expand Down Expand Up @@ -149,3 +179,13 @@ where
Ok(())
}
}

pub fn find_mountpoint(path: &Path, mount_points: &[&Path]) -> Option<PathBuf> {
let path = path.to_string_lossy();

mount_points
.iter()
.filter(|mnt| path.starts_with(&*mnt.to_string_lossy()))
.max_by_key(|mnt| mnt.to_string_lossy().len())
.map(|mnt| mnt.to_path_buf())
}
26 changes: 26 additions & 0 deletions tests/find_mountpoint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use parallel_disk_usage::app::sub::find_mountpoint;
use std::path::Path;

#[test]
fn test_mountpoint() {
let mount_points = &[
Path::new("/"),
Path::new("/home"),
Path::new("/mnt/data"),
Path::new("/mnt/data/repo"),
Path::new("/mnt/repo"),
];

for (path, mount_point) in &[
("/etc/fstab", "/"),
("/home/user", "/home"),
("/mnt/data/repo/test", "/mnt/data/repo"),
("/mnt/data/test/test", "/mnt/data/"),
("/mnt/repo/test/test", "/mnt/repo/"),
] {
assert_eq!(
find_mountpoint(Path::new(path), mount_points).unwrap(),
Path::new(mount_point)
);
}
}

0 comments on commit 0e7a836

Please sign in to comment.