use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use notify::{RecursiveMode, TargetMode, WatchMode, Watcher};
use std::fs::File;
use std::hint::black_box;
use std::path::PathBuf;
use tempfile::TempDir;
fn create_temp_files(dir: &std::path::Path, count: usize) -> Vec<PathBuf> {
let mut paths = Vec::with_capacity(count);
for i in 0..count {
let file_path = match i % 10 {
0..=3 => {
dir.join(format!("file_{i}.txt"))
}
4..=6 => {
let subdir = dir.join(format!("dir{}", i % 3));
std::fs::create_dir_all(&subdir).expect("Failed to create subdirectory");
subdir.join(format!("file_{i}.txt"))
}
_ => {
let nested_dir = dir.join("nested").join(format!("deep{}", i % 2));
std::fs::create_dir_all(&nested_dir).expect("Failed to create nested directory");
nested_dir.join(format!("file_{i}.txt"))
}
};
File::create(&file_path).expect("Failed to create temp file");
paths.push(file_path);
}
paths
}
fn create_sibling_subdirs(dir: &std::path::Path, count: usize) -> Vec<PathBuf> {
let mut paths = Vec::with_capacity(count);
for i in 0..count {
let sub = dir.join(format!("c{i:04}"));
std::fs::create_dir(&sub).expect("Failed to create subdirectory");
paths.push(sub);
}
paths
}
fn bench_paths_mut<W: Watcher>(watcher: &mut W, paths: &[PathBuf], mode: RecursiveMode) {
let mut paths_mut = watcher.paths_mut();
for path in paths {
paths_mut
.add(
path,
WatchMode {
recursive_mode: mode,
target_mode: TargetMode::TrackPath,
},
)
.expect("Failed to add path");
}
paths_mut.commit().expect("Failed to commit paths");
}
#[cfg(target_os = "linux")]
fn bench_inotify_paths_mut(c: &mut Criterion) {
use notify::INotifyWatcher;
let mut group = c.benchmark_group("inotify_paths_mut");
for file_count in [100, 200, 400] {
for mode in [RecursiveMode::NonRecursive, RecursiveMode::Recursive] {
let mode_str = match mode {
RecursiveMode::Recursive => "recursive",
RecursiveMode::NonRecursive => "nonrecursive",
};
group.bench_with_input(
BenchmarkId::new(mode_str, file_count),
&file_count,
|b, &count| {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let paths = create_temp_files(temp_dir.path(), count);
b.iter(|| {
use std::hint::black_box;
let mut watcher =
INotifyWatcher::new(move |_res| {}, notify::Config::default())
.expect("Failed to create watcher");
bench_paths_mut(&mut watcher, black_box(&paths), mode);
});
},
);
}
}
group.finish();
}
#[cfg(target_os = "linux")]
fn bench_inotify_sibling_subdirs(c: &mut Criterion) {
use notify::INotifyWatcher;
let mut group = c.benchmark_group("inotify_sibling_subdirs");
for count in [10, 100, 300] {
for mode in [RecursiveMode::NonRecursive, RecursiveMode::Recursive] {
let mode_str = match mode {
RecursiveMode::Recursive => "recursive",
RecursiveMode::NonRecursive => "nonrecursive",
};
group.bench_with_input(BenchmarkId::new(mode_str, count), &count, |b, &count| {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let paths = create_sibling_subdirs(temp_dir.path(), count);
b.iter(|| {
let mut watcher =
INotifyWatcher::new(move |_res| {}, notify::Config::default())
.expect("Failed to create watcher");
bench_paths_mut(&mut watcher, black_box(&paths), mode);
});
});
}
}
group.finish();
}
#[cfg(all(target_os = "macos", not(feature = "macos_kqueue")))]
fn bench_fsevent_paths_mut(c: &mut Criterion) {
use notify::FsEventWatcher;
let mut group = c.benchmark_group("fsevent_paths_mut");
for file_count in [100, 200, 400] {
for mode in [RecursiveMode::NonRecursive, RecursiveMode::Recursive] {
let mode_str = match mode {
RecursiveMode::Recursive => "recursive",
RecursiveMode::NonRecursive => "nonrecursive",
};
group.bench_with_input(
BenchmarkId::new(mode_str, file_count),
&file_count,
|b, &count| {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let paths = create_temp_files(temp_dir.path(), count);
b.iter(|| {
let mut watcher =
FsEventWatcher::new(move |_res| {}, notify::Config::default())
.expect("Failed to create watcher");
bench_paths_mut(&mut watcher, black_box(&paths), mode);
});
},
);
}
}
group.finish();
}
#[cfg(all(target_os = "macos", not(feature = "macos_kqueue")))]
fn bench_fsevent_sibling_subdirs(c: &mut Criterion) {
use notify::FsEventWatcher;
let mut group = c.benchmark_group("fsevent_sibling_subdirs");
for count in [10, 100, 300] {
for mode in [RecursiveMode::NonRecursive, RecursiveMode::Recursive] {
let mode_str = match mode {
RecursiveMode::Recursive => "recursive",
RecursiveMode::NonRecursive => "nonrecursive",
};
group.bench_with_input(BenchmarkId::new(mode_str, count), &count, |b, &count| {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let paths = create_sibling_subdirs(temp_dir.path(), count);
b.iter(|| {
let mut watcher =
FsEventWatcher::new(move |_res| {}, notify::Config::default())
.expect("Failed to create watcher");
bench_paths_mut(&mut watcher, black_box(&paths), mode);
});
});
}
}
group.finish();
}
#[cfg(any(
all(target_os = "macos", feature = "macos_kqueue"),
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "ios"
))]
fn bench_kqueue_paths_mut(c: &mut Criterion) {
use notify::KqueueWatcher;
let mut group = c.benchmark_group("kqueue_paths_mut");
for file_count in [100, 200, 400] {
for mode in [RecursiveMode::NonRecursive, RecursiveMode::Recursive] {
let mode_str = match mode {
RecursiveMode::Recursive => "recursive",
RecursiveMode::NonRecursive => "nonrecursive",
};
group.bench_with_input(
BenchmarkId::new(mode_str, file_count),
&file_count,
|b, &count| {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let paths = create_temp_files(temp_dir.path(), count);
b.iter(|| {
let mut watcher =
KqueueWatcher::new(move |_res| {}, notify::Config::default())
.expect("Failed to create watcher");
bench_paths_mut(&mut watcher, black_box(&paths), mode);
});
},
);
}
}
group.finish();
}
#[cfg(any(
all(target_os = "macos", feature = "macos_kqueue"),
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "ios"
))]
fn bench_kqueue_sibling_subdirs(c: &mut Criterion) {
use notify::KqueueWatcher;
let mut group = c.benchmark_group("kqueue_sibling_subdirs");
for count in [10, 100, 300] {
for mode in [RecursiveMode::NonRecursive, RecursiveMode::Recursive] {
let mode_str = match mode {
RecursiveMode::Recursive => "recursive",
RecursiveMode::NonRecursive => "nonrecursive",
};
group.bench_with_input(BenchmarkId::new(mode_str, count), &count, |b, &count| {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let paths = create_sibling_subdirs(temp_dir.path(), count);
b.iter(|| {
let mut watcher = KqueueWatcher::new(move |_res| {}, notify::Config::default())
.expect("Failed to create watcher");
bench_paths_mut(&mut watcher, black_box(&paths), mode);
});
});
}
}
group.finish();
}
#[cfg(target_os = "windows")]
fn bench_windows_paths_mut(c: &mut Criterion) {
use notify::ReadDirectoryChangesWatcher;
let mut group = c.benchmark_group("windows_paths_mut");
for file_count in [100, 200, 400] {
for mode in [RecursiveMode::NonRecursive, RecursiveMode::Recursive] {
let mode_str = match mode {
RecursiveMode::Recursive => "recursive",
RecursiveMode::NonRecursive => "nonrecursive",
};
group.bench_with_input(
BenchmarkId::new(mode_str, file_count),
&file_count,
|b, &count| {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let paths = create_temp_files(temp_dir.path(), count);
b.iter(|| {
let mut watcher = ReadDirectoryChangesWatcher::new(
move |_res| {},
notify::Config::default(),
)
.expect("Failed to create watcher");
bench_paths_mut(&mut watcher, black_box(&paths), mode);
});
},
);
}
}
group.finish();
}
#[cfg(target_os = "windows")]
fn bench_windows_sibling_subdirs(c: &mut Criterion) {
use notify::ReadDirectoryChangesWatcher;
let mut group = c.benchmark_group("windows_sibling_subdirs");
for count in [10, 100, 300] {
for mode in [RecursiveMode::NonRecursive, RecursiveMode::Recursive] {
let mode_str = match mode {
RecursiveMode::Recursive => "recursive",
RecursiveMode::NonRecursive => "nonrecursive",
};
group.bench_with_input(BenchmarkId::new(mode_str, count), &count, |b, &count| {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let paths = create_sibling_subdirs(temp_dir.path(), count);
b.iter(|| {
let mut watcher =
ReadDirectoryChangesWatcher::new(move |_res| {}, notify::Config::default())
.expect("Failed to create watcher");
bench_paths_mut(&mut watcher, black_box(&paths), mode);
});
});
}
}
group.finish();
}
fn bench_poll_paths_mut(c: &mut Criterion) {
use notify::PollWatcher;
let mut group = c.benchmark_group("poll_paths_mut");
for file_count in [100, 200, 400] {
for mode in [RecursiveMode::NonRecursive, RecursiveMode::Recursive] {
let mode_str = match mode {
RecursiveMode::Recursive => "recursive",
RecursiveMode::NonRecursive => "nonrecursive",
};
group.bench_with_input(
BenchmarkId::new(mode_str, file_count),
&file_count,
|b, &count| {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let paths = create_temp_files(temp_dir.path(), count);
b.iter(|| {
let mut watcher =
PollWatcher::new(move |_res| {}, notify::Config::default())
.expect("Failed to create watcher");
bench_paths_mut(&mut watcher, black_box(&paths), mode);
});
},
);
}
}
group.finish();
}
fn bench_poll_sibling_subdirs(c: &mut Criterion) {
use notify::PollWatcher;
let mut group = c.benchmark_group("poll_sibling_subdirs");
for count in [10, 100, 300] {
for mode in [RecursiveMode::NonRecursive, RecursiveMode::Recursive] {
let mode_str = match mode {
RecursiveMode::Recursive => "recursive",
RecursiveMode::NonRecursive => "nonrecursive",
};
group.bench_with_input(BenchmarkId::new(mode_str, count), &count, |b, &count| {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let paths = create_sibling_subdirs(temp_dir.path(), count);
b.iter(|| {
let mut watcher = PollWatcher::new(move |_res| {}, notify::Config::default())
.expect("Failed to create watcher");
bench_paths_mut(&mut watcher, black_box(&paths), mode);
});
});
}
}
group.finish();
}
#[cfg(target_os = "linux")]
criterion_group!(
benches,
bench_inotify_paths_mut,
bench_inotify_sibling_subdirs,
bench_poll_paths_mut,
bench_poll_sibling_subdirs
);
#[cfg(all(
target_os = "macos",
feature = "macos_fsevent",
not(feature = "macos_kqueue")
))]
criterion_group!(
benches,
bench_fsevent_paths_mut,
bench_fsevent_sibling_subdirs,
bench_poll_paths_mut,
bench_poll_sibling_subdirs
);
#[cfg(all(target_os = "macos", feature = "macos_kqueue"))]
criterion_group!(
benches,
bench_kqueue_paths_mut,
bench_kqueue_sibling_subdirs,
bench_poll_paths_mut,
bench_poll_sibling_subdirs
);
#[cfg(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "ios"
))]
criterion_group!(
benches,
bench_kqueue_paths_mut,
bench_kqueue_sibling_subdirs,
bench_poll_paths_mut,
bench_poll_sibling_subdirs
);
#[cfg(target_os = "windows")]
criterion_group!(
benches,
bench_windows_paths_mut,
bench_windows_sibling_subdirs,
bench_poll_paths_mut,
bench_poll_sibling_subdirs
);
#[cfg(not(any(
target_os = "linux",
target_os = "macos",
target_os = "windows",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "ios"
)))]
criterion_group!(benches, bench_poll_paths_mut, bench_poll_sibling_subdirs);
criterion_main!(benches);