A file write finishes quickly, but storage continues working afterward. That is often the normal behavior of buffered I/O: the application changed cached pages, and the kernel still has dirty data to write back.
The page cache is not a trick that makes a disk faster. It changes when storage access is needed and which work an application waits for. A benchmark must name those boundaries before its throughput numbers mean anything.
Read hits and write completion answer different questions
A cached read can copy data from memory without another device read. Repeating the same workload therefore changes its conditions: the second pass may measure memory access and copying rather than the original storage path.
A buffered write generally updates cached pages and marks them dirty. The kernel can write them back later, and the application may eventually be throttled when dirty memory or backing-device pressure grows. A short run can finish before steady-state writeback becomes the dominant constraint.
application write -> dirty cached pages -> writeback -> filesystem/device
application fsync ---------------------> required synchronization boundary
This is a conceptual path. Filesystems, direct I/O, network filesystems, and storage hardware have different implementation details and guarantees.
Dirty-page controls are policies, not throughput multipliers
Linux exposes byte- and ratio-based dirty thresholds, including background writeback and thresholds that can involve writing tasks in writeback. A byte threshold and its corresponding ratio are alternative forms, not independent limits to maximize together.
The denominator for a dirty ratio is not simply all installed RAM. Available memory and kernel accounting matter. Kernel documentation should be consulted for the running version; a value copied from another machine can represent a very different absolute commitment.
Allowing more dirty data can absorb a burst while increasing later stalls, memory pressure, and the amount of data awaiting persistence. Reducing it can make backpressure appear sooner. Neither direction is universally an optimization.
Observe the phases without dropping global caches
On an authorized Linux host:
grep -E '^(Cached|Dirty|Writeback|MemAvailable):' /proc/meminfo
vmstat 1 5
sysctl vm.dirty_background_bytes vm.dirty_background_ratio
sysctl vm.dirty_bytes vm.dirty_ratio
These are host observations, not attribution to one process. The first vmstat line and later interval samples have different timing meaning. Pair them with application timestamps and device or filesystem measurements.
For a lab experiment, use disposable data and record dataset size relative to memory. Compare buffered completion with explicit synchronization as separate measurements. Do not flush caches system-wide on a shared host merely to label a run “cold.”
Synchronization belongs in the application contract
fsync requests synchronization of file data and relevant metadata according to filesystem semantics. Durably creating a directory entry may additionally require synchronizing the containing directory. Correct ordering depends on the operation being implemented.
Check return values: errors from earlier buffered work can surface at a later synchronization point. A successful write does not promise that a power failure immediately afterward preserves the bytes.
For NFS, client caching and the server’s stable-write or commit behavior add another boundary. A local page-cache observation is not proof of remote durable storage.
Report what the benchmark actually measured
Record filesystem, mount options, device, OS/kernel, dataset, access pattern, concurrency, duration, synchronization policy, warmup, and run count. Report sustained behavior long enough to encounter writeback, not just a cache-absorbed burst.
Use those boundaries to ask a sharper question: did the change improve application-visible latency, durable throughput, or the amount of work absorbed by memory? Those can move in different directions.
Further reading
Primary references behind this explanation. Consult documentation for the version and environment you actually run.