fio — Reporting¶
This guide covers how fio results are collected, normalized, and rendered into reports.
Result Collection¶
Collect-FioResults.ps1 retrieves and normalizes fio output from each node:
.\tools\fio\scripts\Collect-FioResults.ps1 `
-ClusterName "hci01.corp.infiniteimprobability.com" `
-Nodes @("hci01-node1", "hci01-node2", "hci01-node3") `
-RunId "<run-id>"
What It Does¶
- SCP-copies
/tmp/fio-results/<RunId>/fio-results.jsonfrom each node - Parses the fio JSON structure (
jobs[].readandjobs[].write) - Normalizes units — latency from nanoseconds to milliseconds, bandwidth from bytes/s to MB/s
- Aggregates per-node results into cluster totals
- Writes two output files and removes remote result files
Output Files¶
Results land in logs\fio\<RunId>\:
| File | Contents |
|---|---|
<RunId>-aggregate.json |
Cluster-level summary metrics |
<RunId>-per-job.json |
Per-node, per-job detail |
Aggregate JSON Schema¶
{
"run_id": "fio-20260324-143012",
"timestamp": "2026-03-24T14:30:12Z",
"cluster_name": "hci01.corp.infiniteimprobability.com",
"profile": "random-read",
"nodes_tested": ["hci01-node1", "hci01-node2"],
"aggregate": {
"read_iops": 98234,
"write_iops": 0,
"total_iops": 98234,
"read_throughput_mbps": 384.5,
"write_throughput_mbps": 0,
"read_lat_mean_ms": 1.32,
"read_lat_p99_ms": 4.87,
"write_lat_mean_ms": null,
"write_lat_p99_ms": null
},
"threshold_violations": []
}
Key Metric Fields¶
| Field | Unit | Source |
|---|---|---|
read_iops |
IOPS | jobs[].read.iops |
write_iops |
IOPS | jobs[].write.iops |
total_iops |
IOPS | read + write combined |
read_throughput_mbps |
MB/s | jobs[].read.bw_bytes ÷ 1,048,576 |
write_throughput_mbps |
MB/s | jobs[].write.bw_bytes ÷ 1,048,576 |
read_lat_mean_ms |
ms | jobs[].read.lat_ns.mean ÷ 1,000,000 |
read_lat_p99_ms |
ms | jobs[].read.lat_ns.percentile["99.000000"] ÷ 1,000,000 |
Report Generation¶
Reports are generated from the AsciiDoc templates in tools/fio/reports/templates/:
# Generate PDF from collected results
asciidoctor-pdf `
tools/fio/reports/templates/report-template.adoc `
-a run-id="<RunId>" `
-a results-dir="logs/fio/<RunId>" `
-o reports/fio-<RunId>.pdf
Template Placeholders¶
The report template uses these attribute substitutions:
| Placeholder | Value Source |
|---|---|
{run-id} |
RunId parameter |
{cluster-name} |
cluster_name in aggregate JSON |
{profile-name} |
profile in aggregate JSON |
{fio-block-size} |
Profile block_size |
{fio-rw} |
Profile rw pattern |
{total-read-iops} |
aggregate.read_iops |
{total-write-iops} |
aggregate.write_iops |
{read-throughput-mbps} |
aggregate.read_throughput_mbps |
{read-lat-mean-ms} |
aggregate.read_lat_mean_ms |
{read-lat-p99-ms} |
aggregate.read_lat_p99_ms |
Reviewing Threshold Violations¶
# Check if any thresholds were violated
$results = Get-Content "logs\fio\<RunId>\<RunId>-aggregate.json" | ConvertFrom-Json
if ($results.threshold_violations.Count -gt 0) {
$results.threshold_violations | Format-Table -AutoSize
}
A threshold violation does not fail the run — it is recorded in the output and surfaced in the log for human review.