use std::{
env,
ffi::CString,
fs::{self, File},
io::Write,
path::{Path, PathBuf},
time::SystemTime,
};
use brunch::{benches, Bench};
use libc::{close, open, read, O_RDONLY};
use nix::unistd::unlink;
struct XorShift32 {
state: u32,
}
impl XorShift32 {
fn new(seed: u32) -> Self {
Self { state: seed }
}
fn next_u32(&mut self) -> u32 {
let mut x = self.state;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
self.state = x;
x
}
}
fn create_files_with_content(count: usize) -> (PathBuf, Vec<PathBuf>) {
let mut dir = env::temp_dir();
let unique = format!(
"open_read_close_bench_{}_{}",
count,
SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
);
dir.push(unique);
fs::create_dir_all(&dir).unwrap_or_else(|_| panic!("Failed to create directory: {:?}", &dir));
let mut paths = Vec::with_capacity(count);
for i in 0..count {
let path = dir.join(format!("file_{}", i));
let mut file =
File::create(&path).unwrap_or_else(|_| panic!("Failed to create file: {:?}", &path));
file.write_all(b"some content")
.unwrap_or_else(|_| panic!("Failed to write content: {:?}", &path));
paths.push(path);
}
(dir, paths)
}
fn open_read_close(files: &[PathBuf], rng: &mut XorShift32) {
let chosen_idx = (rng.next_u32() as usize) % files.len();
let c_path = CString::new(files[chosen_idx].to_string_lossy().as_bytes())
.expect("Failed to convert path to CString");
let fd = unsafe { open(c_path.as_ptr(), O_RDONLY) };
if fd < 0 {
panic!("open() failed for {:?}", files[chosen_idx]);
}
let mut buf = [0u8; 1];
let result = unsafe { read(fd, buf.as_mut_ptr() as *mut _, 1) };
if result != 1 {
panic!("read() failed to read 1 byte (got {})", result);
}
unsafe {
close(fd);
}
}
fn cleanup_temp_dir(dir: &Path, files: &[PathBuf]) {
for f in files {
let _ = unlink(f);
}
let _ = fs::remove_dir_all(dir);
}
fn main() {
let file_counts = [1000, 16384];
let mut setups = Vec::new();
for &count in &file_counts {
let (dir, paths) = create_files_with_content(count);
setups.push((count, dir, paths));
}
benches!(
inline:
Bench::new("OpenReadClose(1000)").run(|| {
static SEED: u32 = 1;
let mut rng = XorShift32::new(SEED);
open_read_close(&setups[0].2, &mut rng);
}),
Bench::new("OpenReadClose(16384)").run(|| {
static SEED: u32 = 1;
let mut rng = XorShift32::new(SEED);
open_read_close(&setups[1].2, &mut rng);
}),
);
for (_, dir, paths) in setups {
cleanup_temp_dir(&dir, &paths);
}
}