#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(crate) enum Evidence {
Measured,
#[allow(dead_code)]
Inherited,
}
impl Evidence {
#[allow(dead_code)]
pub(crate) const fn is_measured(self) -> bool {
matches!(self, Self::Measured)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(crate) struct Tuned<T> {
value: T,
evidence: Evidence,
}
impl<T: Copy> Tuned<T> {
#[allow(dead_code)]
pub(crate) const fn measured(value: T) -> Self {
Self { value, evidence: Evidence::Measured }
}
#[allow(dead_code)]
pub(crate) const fn inherited(value: T) -> Self {
Self { value, evidence: Evidence::Inherited }
}
pub(crate) const fn get(self) -> T {
self.value
}
#[allow(dead_code)]
pub(crate) const fn evidence(self) -> Evidence {
self.evidence
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Tuning {
pub(crate) scan_threads_cap: Tuned<usize>,
pub(crate) adaptive_scan_threads_cap: Tuned<usize>,
pub(crate) adaptive_scan_parallelism_multiplier: Tuned<usize>,
pub(crate) adaptive_scan_calibration_entries: Tuned<u64>,
pub(crate) adaptive_scan_slow_work_ns_per_entry: Tuned<u64>,
pub(crate) reconcile_threads_cap: Tuned<usize>,
pub(crate) reconcile_wave_directories: Tuned<usize>,
pub(crate) batch_size: Tuned<usize>,
}
#[allow(dead_code)]
const MACOS: Tuning = Tuning {
scan_threads_cap: Tuned::measured(6),
adaptive_scan_threads_cap: Tuned::measured(16),
adaptive_scan_parallelism_multiplier: Tuned::measured(2),
adaptive_scan_calibration_entries: Tuned::measured(16 * 1024),
adaptive_scan_slow_work_ns_per_entry: Tuned::measured(30_000),
reconcile_threads_cap: Tuned::measured(4),
reconcile_wave_directories: Tuned::measured(1_024),
batch_size: Tuned::measured(1_024),
};
#[allow(dead_code)]
const PORTABLE: Tuning = Tuning {
scan_threads_cap: Tuned::inherited(6),
adaptive_scan_threads_cap: Tuned::inherited(16),
adaptive_scan_parallelism_multiplier: Tuned::inherited(2),
adaptive_scan_calibration_entries: Tuned::inherited(16 * 1024),
adaptive_scan_slow_work_ns_per_entry: Tuned::inherited(30_000),
reconcile_threads_cap: Tuned::inherited(4),
reconcile_wave_directories: Tuned::inherited(1_024),
batch_size: Tuned::inherited(1_024),
};
const _: () = {
assert!(MACOS.scan_threads_cap.get() >= 1);
assert!(MACOS.adaptive_scan_threads_cap.get() >= MACOS.scan_threads_cap.get());
assert!(MACOS.reconcile_threads_cap.get() >= 1);
assert!(MACOS.reconcile_wave_directories.get() >= 1);
assert!(MACOS.batch_size.get() >= 1);
assert!(MACOS.adaptive_scan_slow_work_ns_per_entry.get() > 0);
assert!(MACOS.scan_threads_cap.evidence().is_measured(), "macOS measured its own");
assert!(PORTABLE.scan_threads_cap.get() >= 1);
assert!(PORTABLE.adaptive_scan_threads_cap.get() >= PORTABLE.scan_threads_cap.get());
assert!(PORTABLE.reconcile_threads_cap.get() >= 1);
assert!(PORTABLE.reconcile_wave_directories.get() >= 1);
assert!(PORTABLE.batch_size.get() >= 1);
assert!(PORTABLE.adaptive_scan_slow_work_ns_per_entry.get() > 0);
assert!(
!PORTABLE.scan_threads_cap.evidence().is_measured(),
"promote this to Tuned::measured in the same change that lands the sweep"
);
};
pub(crate) const fn tuning() -> Tuning {
#[cfg(target_os = "macos")]
{
MACOS
}
#[cfg(not(target_os = "macos"))]
{
PORTABLE
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_platform_table_is_usable_from_every_platform() {
for table in [MACOS, PORTABLE] {
assert!(table.scan_threads_cap.get() >= 1, "a scan needs at least one worker");
assert!(
table.adaptive_scan_threads_cap.get() >= table.scan_threads_cap.get(),
"the adaptive ceiling cannot sit below the starting pool"
);
assert!(table.adaptive_scan_parallelism_multiplier.get() >= 1);
assert!(table.adaptive_scan_calibration_entries.get() > 0);
assert!(table.adaptive_scan_slow_work_ns_per_entry.get() > 0);
assert!(table.reconcile_threads_cap.get() >= 1);
assert!(table.reconcile_wave_directories.get() >= 1);
assert!(table.batch_size.get() >= 1);
}
}
#[test]
fn the_portable_table_admits_that_it_inherits() {
assert_eq!(MACOS.scan_threads_cap.evidence(), Evidence::Measured);
assert_eq!(MACOS.adaptive_scan_slow_work_ns_per_entry.evidence(), Evidence::Measured);
assert_eq!(MACOS.reconcile_wave_directories.evidence(), Evidence::Measured);
assert_eq!(PORTABLE.scan_threads_cap.evidence(), Evidence::Inherited);
assert_eq!(PORTABLE.adaptive_scan_slow_work_ns_per_entry.evidence(), Evidence::Inherited);
assert_eq!(PORTABLE.reconcile_wave_directories.evidence(), Evidence::Inherited);
}
#[test]
fn every_platform_table_produces_the_same_index() {
let dir = tempfile::Builder::new().prefix("fdu-tuning-").tempdir().expect("tempdir");
let root = dir.path();
for directory in 0..12 {
for file in 0..24 {
let path = root.join(format!("d{directory}/nested/f{file}.rs"));
std::fs::create_dir_all(path.parent().expect("parent")).expect("dirs");
std::fs::write(&path, vec![b'x'; directory * 16 + file]).expect("write");
}
std::fs::write(root.join(format!("d{directory}/top.md")), b"# top").expect("write");
}
let image_for = |threads: usize, batch_size: usize| {
let config = crate::ScanConfig {
threads: Some(threads),
batch_size,
..crate::ScanConfig::default()
};
let (index, report) = crate::scan::scan_into_index(root, &config).expect("scan");
assert!(report.is_complete(), "the fixture scan must be complete");
let total = index.total();
let mut entries: Vec<(std::path::PathBuf, String, u64)> = Vec::new();
let mut stack = vec![crate::index::EntryId::ROOT];
while let Some(id) = stack.pop() {
let path = index.path_of(id).expect("path");
let kind = format!("{:?}", index.kind_of(id).expect("kind"));
let size = index.attrs_of(id).expect("attrs").size;
entries.push((path, kind, size));
if let Some(children) = index.children_of(id) {
stack.extend(children.map(|(_, child)| child));
}
}
entries.sort();
(
index.len(),
total.files,
total.dirs,
total.bytes,
total.newest_mtime_ns,
total.by_ext,
entries,
)
};
let mut settings: Vec<(usize, usize)> = vec![(1, 1)];
for table in [MACOS, PORTABLE] {
settings.push((table.scan_threads_cap.get(), table.batch_size.get()));
settings.push((table.reconcile_threads_cap.get(), table.batch_size.get()));
settings.push((table.adaptive_scan_threads_cap.get(), table.batch_size.get()));
}
settings.sort_unstable();
settings.dedup();
let reference = image_for(settings[0].0, settings[0].1);
for &(threads, batch_size) in &settings[1..] {
assert_eq!(
image_for(threads, batch_size),
reference,
"a scan with {threads} workers and a batch size of {batch_size} \
disagreed with the serial reference; a tuning value may change speed \
but never the answer"
);
}
}
#[test]
fn the_selected_table_matches_the_target() {
let selected = tuning();
#[cfg(target_os = "macos")]
assert_eq!(selected.scan_threads_cap.evidence(), Evidence::Measured);
#[cfg(not(target_os = "macos"))]
assert_eq!(selected.scan_threads_cap.evidence(), Evidence::Inherited);
}
}