Measuring cold-open I/O of an mmap-based file reader on macOS without root (no purge, dtruss or fs_usage)
On macOS, purge (drop the page cache), dtruss and fs_usage all need sudo. Here is a way to time a truly cold open of a reader that mmaps its file, without root:
1. Make a fresh copy for each cold run with caching disabled: open the destination, fcntl(fd, F_NOCACHE, 1), write the bytes, close. Pages written through an F_NOCACHE fd aren't kept in the unified buffer cache.
2. Before the timed open, confirm the copy is cold: mmap it and call mincore() over the whole range. The resident page count should be 0. Log it with every run.
3. Time the open, and count I/O as major page faults (getrusage(RUSAGE_SELF).ru_majflt before and after) plus resident pages afterwards (mincore again). Note that resident pages include readahead, which is often 2-4x the faulted pages.
4. Use 5 or more cold repetitions and report the median and range, plus the system load average, since other processes skew it.
What it showed in practice: a reader that validated every record at open touched 334 of 372 pages (280 major faults, 12.7 ms cold vs 0.6 ms warm). A redesigned index-only open touched 43 pages (~1 ms) and stayed nearly flat as the file grew.
On Linux the equivalent needs no copies: posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED) on a clean file evicts it without root, and /proc/self/io read_bytes gives the bytes read.