- Add files_per_second field to BenchmarkResult struct - Implement calculate_files_per_second() method - Implement save_to_file() method for JSON baseline recording - Update run_benchmark() to calculate files_per_second metric - Update main() to display and save files_per_second Acceptance criteria: ✅ Timing code measures wall-clock time accurately (Instant::now) ✅ Throughput (MB/s) calculated correctly (bytes_total / duration) ✅ Files per second calculated correctly (files_total / duration_sec) ✅ Commit hash extraction works (git rev-parse HEAD) ✅ Timestamp produces ISO 8601 (chrono::Utc::now().to_rfc3339) ✅ Ready to output metrics to JSON (save_to_file method) See notes/bf-54zad.md for verification details.
3.5 KiB
3.5 KiB
bf-54zad: Benchmark Timing and Throughput Measurement
Summary
Implemented timing instrumentation and throughput measurement logic for the grep benchmark.
Changes Made
File: crates/pdftract-cli/benches/grep_1000.rs
-
Added
files_per_secondfield toBenchmarkResultstruct (line 103)- Stores the calculated files per second metric
-
Implemented
calculate_files_per_second()method (lines 118-125)- Calculates files/second:
files_total / duration_sec - Handles division by zero (returns 0.0 if duration_ms == 0)
- Formula:
files_total / (duration_ms / 1000.0)
- Calculates files/second:
-
Implemented
save_to_file()method (lines 147-180)- Creates
benches/results/directory if it doesn't exist - Saves benchmark result as
<commit-sha>.json(8-char short SHA) - Uses
serde_json::to_string_pretty()for readable JSON output - Provides user feedback on file save location
- Creates
-
Updated
run_benchmark()function (lines 260-280)- Calculates
files_per_secondmetric after benchmark execution - Creates updated
BenchmarkResultwith calculated metrics
- Calculates
-
Updated
main()function (lines 354-374)- Displays
files_per_secondmetric alongside throughput - Calls
save_to_file()to persist results to JSON - Provides warning if file save fails (non-fatal)
- Displays
Acceptance Criteria Status
| Criterion | Status | Notes |
|---|---|---|
| Timing code measures wall-clock time accurately | ✅ PASS | Uses Instant::now() and .elapsed().as_millis() |
| Throughput (MB/s) calculated correctly | ✅ PASS | calculate_throughput() method: (bytes * 1000) / duration_ms / (1024*1024) |
| Files per second calculated correctly | ✅ PASS | calculate_files_per_second() method: files / (duration_ms / 1000) |
| Commit hash extraction works | ✅ PASS | get_commit_sha() uses git rev-parse HEAD |
| Timestamp generation produces ISO 8601 | ✅ PASS | Uses chrono::Utc::now().to_rfc3339() |
| Ready to output metrics to JSON | ✅ PASS | save_to_file() method outputs to benches/results/<sha>.json |
Technical Details
Wall-clock timing
- Uses
std::time::Instant::now()for start time - Measures elapsed milliseconds with
.elapsed().as_millis() - High-resolution monotonic clock suitable for benchmarking
Throughput calculation (MB/s)
let bytes_per_sec = (bytes_total as f64 * 1000.0) / duration_ms as f64;
bytes_per_sec / (1024.0 * 1024.0)
- Converts duration from ms to seconds
- Calculates bytes per second
- Divides by 1024² for binary MB (MiB/s)
Files per second calculation
let duration_sec = duration_ms as f64 / 1000.0;
files_total as f64 / duration_sec
- Simple linear scaling from files per duration_ms to files per second
JSON output format
{
"commit": "abc12345...",
"started_at": "2026-07-06T10:30:45+00:00",
"files_total": 1000,
"bytes_total": 104857600,
"duration_ms": 2000,
"matches_total": 5000,
"throughput_mb_s": 50.0,
"files_per_second": 500.0,
"peak_rss_mb": null
}
Testing
Compile check
cargo check --bench grep_1000
✅ No compilation errors
Manual test (corpus not yet populated)
The benchmark handles empty corpus gracefully - returns placeholder result and skips CI gate validation during development.
Next Steps
The benchmark infrastructure is now ready. Once the grep subcommand is complete (7.8.x beads):
- Populate
tests/fixtures/grep-corpus/with 1000 PDFs - Wire up actual grep execution
- Run full benchmark and validate 50 MB/s CI gate