use std::fs;
use std::io::Write as _;
use std::os::unix::io::AsRawFd;
use std::time::Duration;
const MAPPING_GIB: usize = 1;
const MAPPING_SIZE: usize = MAPPING_GIB * 1024 * 1024 * 1024;
const N_WORKERS: usize = 4;
const TEMP_PATH: &str = "/tmp/repro_rss_mmap_data";
fn worker_main() {
let file = fs::File::open(TEMP_PATH).expect("worker: cannot open temp file");
let ptr = unsafe {
libc::mmap(
std::ptr::null_mut(),
MAPPING_SIZE,
libc::PROT_READ,
libc::MAP_PRIVATE,
file.as_raw_fd(),
0,
)
};
assert_ne!(ptr, libc::MAP_FAILED, "worker: mmap failed");
let slice = unsafe { std::slice::from_raw_parts(ptr as *const u8, MAPPING_SIZE) };
let mut checksum = 0u64;
for offset in (0..MAPPING_SIZE).step_by(4096) {
checksum = checksum.wrapping_add(slice[offset] as u64);
}
let _ = checksum;
std::thread::sleep(Duration::from_secs(20));
unsafe { libc::munmap(ptr, MAPPING_SIZE) };
}
fn main() {
if std::env::args().nth(1).as_deref() == Some("--worker") {
worker_main();
return;
}
std::thread::sleep(Duration::from_secs(5));
{
let mut f = fs::File::create(TEMP_PATH).expect("cannot create temp file");
let chunk = vec![0xABu8; 1024 * 1024];
for _ in 0..(MAPPING_SIZE / chunk.len()) {
f.write_all(&chunk).expect("write failed");
}
}
let file = fs::File::open(TEMP_PATH).expect("cannot open temp file");
let parent_ptr = unsafe {
libc::mmap(
std::ptr::null_mut(),
MAPPING_SIZE,
libc::PROT_READ,
libc::MAP_PRIVATE,
file.as_raw_fd(),
0,
)
};
assert_ne!(parent_ptr, libc::MAP_FAILED, "parent mmap failed");
let parent_slice = unsafe { std::slice::from_raw_parts(parent_ptr as *const u8, MAPPING_SIZE) };
let mut checksum = 0u64;
for offset in (0..MAPPING_SIZE).step_by(4096) {
checksum = checksum.wrapping_add(parent_slice[offset] as u64);
}
let _ = checksum;
let exe = std::env::current_exe().expect("cannot resolve executable");
let mut children: Vec<_> = (0..N_WORKERS)
.map(|_| {
std::process::Command::new(&exe)
.arg("--worker")
.spawn()
.expect("failed to spawn worker")
})
.collect();
std::thread::sleep(Duration::from_secs(15));
for c in &mut children {
let _ = c.kill();
let _ = c.wait();
}
unsafe { libc::munmap(parent_ptr, MAPPING_SIZE) };
fs::remove_file(TEMP_PATH).ok();
}