A comprehensive C++20 benchmark suite for analyzing sequential vs sparse file reading performance, with a focus on "time to end" metrics for large files.
This benchmark suite was created to test the hypothesis that sparse file reading can reach the end of large files faster than sequential reading, despite having lower overall data throughput. The results confirm this hypothesis with dramatic performance improvements for file scanning operations.
Test Environment:
- CPU: AMD Ryzen 9 5900X
- RAM: 128GB DDR4 @ 1648MHz
- Storage: Samsung MZVL22T0HBLB-00B00 (NVMe SSD)
- OS: WSL2 (Ubuntu 24.04) on Windows 11
- Compiler: GCC 13.3.0 with -O3 optimization
- Date: October 5, 2025
Testing Environment: AMD Ryzen 9 5900X, 128GB DDR4, Samsung NVMe SSD
| Spacing | Time to End (10GB file) | Speedup vs Sequential |
|---|---|---|
| Sequential | 14.13 seconds | baseline |
| 8MB spacing | 0.22 seconds | 98.5% faster ⚡ |
| 4MB spacing | 0.43 seconds | 97.0% faster |
| 2MB spacing | 0.87 seconds | 93.9% faster |
| 16KB spacing | 9.86 seconds | 30.2% faster |
| 32KB spacing | 55.32 seconds | 291% slower ❌ |
| Category | Spacing Range | Performance vs Sequential | Recommendation |
|---|---|---|---|
| Small Winners | 4KB - 16KB | 24% - 30% FASTER | ✅ Use for dense sampling |
| Performance Valley | 32KB - 64KB | 94% - 291% SLOWER | ❌ Avoid completely |
| Recovery Zone | 128KB | 2.5% FASTER | ⚡ Breaking even point |
| Optimal Range | 256KB - 8MB | 51% - 98.5% FASTER | 🚀 Best for file scanning |
git clone <repository>
cd file_read_benchmark
./build.sh./demo.shsudo ./run_full_benchmark.shsudo ./build/time_to_end_benchmarkfile_read_benchmark/
├── src/
│ ├── main.cpp # Full 10GB benchmark
│ ├── test_main.cpp # Quick 100MB test
│ ├── time_to_end_main.cpp # Time-to-end focused
│ ├── benchmark.cpp # Core implementation
│ ├── file_generator.cpp # File generation
│ └── cache_control.cpp # Cache management
├── include/
│ └── benchmark.h # API definitions
├── build.sh # Build script
├── demo.sh # Quick demo
├── run_full_benchmark.sh # Full benchmark runner
├── CMakeLists.txt # Build configuration
├── BENCHMARK_REPORT.md # Detailed analysis
└── README.md # This file
After building, you'll find these executables in build/:
file_benchmark- Full benchmark with 10GB filetest_benchmark- Quick 100MB test versiontime_to_end_benchmark- Focuses on time-to-end metrics
The benchmark reveals a surprising performance valley where mid-range spacings (32-64KB) perform dramatically worse than both smaller and larger spacings:
-
Small Spacings (4-16KB): 24-30% faster than sequential
- Cache-friendly with sequential locality benefits
- Good for dense sampling applications
-
Performance Valley (32-64KB): 94-291% slower than sequential
- Cache-unfriendly seek patterns
- Worst of both worlds: all seeks, no benefits
-
Optimal Range (256KB-8MB): 51-98.5% faster than sequential
- Minimal seeks with fast file area coverage
- Perfect for file scanning and validation
- Coverage Speed: How fast we scan through file area (GB/s)
- Data Throughput: Actual bytes read per second (MB/s)
For file scanning operations, coverage speed is the critical metric.
- File validation and integrity checks (use 2-8MB spacing)
- Metadata discovery and structure analysis (use 256KB-1MB spacing)
- Progress monitoring for large files (use 512KB-1MB spacing)
- Database/log file sampling (use 8-16KB spacing)
- Quick file format detection (use 4-8MB spacing)
- 32-64KB range: Creates performance nightmare
- Any spacing generating >100K seeks per file
- Cache Control: Clears OS page cache between runs (requires root)
- Statistical Analysis: Multiple runs with standard deviation
- Data Integrity: Checksum verification prevents compiler optimization
- Comprehensive Output: Console tables and CSV export
- Configurable: Easy to modify file sizes and spacing ranges
# Quick test (no root required)
cd build
./test_benchmark
# Full test with cache clearing (root required)
sudo ./file_benchmark
# Time-to-end analysis
sudo ./time_to_end_benchmarkFor most accurate results, run with sudo to enable:
- OS page cache clearing between runs
- Filesystem sync operations
- Direct I/O hints
- File Renaming: Between runs to avoid metadata caching
- Page Cache Clearing:
echo 3 > /proc/sys/vm/drop_caches - Direct I/O Hints:
posix_fadvise(POSIX_FADV_DONTNEED) - Filesystem Sync: Ensures data written to disk
- OS: Linux (tested on Ubuntu 24.04/WSL2)
- Compiler: GCC with C++20 support
- RAM: Minimum 4GB (16GB+ recommended for large tests)
- Storage: 15GB+ free space for full 10GB benchmark
- Privileges: Root access recommended for cache clearing
The benchmark conclusively validates that sparse reading can be dramatically faster for reaching the end of large files, with the optimal 8MB spacing achieving 98.5% faster performance than sequential reading. However, spacing selection is critical - wrong choices can be significantly slower than sequential access.
This research provides actionable insights for optimizing large file operations in production systems, particularly for file validation, metadata discovery, and progress monitoring applications.
For complete analysis and detailed results, see BENCHMARK_REPORT.md