I measured X. Published is Y. Why?
Method version 1.0 · Last updated: September 2026
Benchmark Reality Check takes a number you measured on your own board and compares it with the expected range the Benchmark Explorer derives from the normalised benchmark database for the same hardware, model, variant and precision. It reports a verdict, the gap ratio, and the causes most likely to explain a gap — each ranked by prior likelihood times how well its typical effect size matches what you saw, with the on-device command that settles it. When you give a JetPack and power mode it also runs the Jetson Configuration Checker and folds its non-PASS checks into the ranking. This page states the reference rule, the measured-value normalisation, the verdict rule, the ranking rule, the full cause catalogue with verify commands and sources, the configuration hand-off, the submit prefill, the evidence classes and what invalidates a result.
Contents
1. What this engine answers
"I measured 38 fps for YOLO11n INT8 on an Orin Nano Super; the docs say up to 67 fps — is my board broken, my config wrong, or is the published number optimistic?" Benchmark Reality Check does not run a benchmark itself: it takes the number you already measured, looks up what the Benchmark Explorer database (or its class B → C → D estimator fallback) says to expect for the exact same hardware × model family × variant × precision, and reports whether your number is within, below, or above that range — then ranks the reasons a gap of that size is typically caused by, so you check the likely one first instead of re-flashing at random.
2. Inputs and defaults
| Input | Required / default | Notes |
|---|---|---|
hardware | Required | Must be a catalog module or a benchmark-database reference platform (/api/v1/catalog benchmarks_v2.hardware). |
model_family | Required | Must be a known family (benchmarks_v2.families). |
variant | Required | Free-form (e.g. n, s, 8b) — matched against the reference rows' model.variant. |
precision | Default fp16 | fp32 / fp16 / bf16 / fp8 / int8 / int4. |
measured_fps / measured_latency_ms / measured_tokens_per_s | Exactly one required | Aliases fps, latency_ms, tokens_per_s also accepted. Must be > 0. |
runtime | Defaults to the reference row's runtime | If no reference row exists, defaults to tensorrt on Jetson hardware, otherwise left unset (reported runtime_assumed). |
scope | Default inference_only | inference_only or end_to_end. |
batch | Default 1 | 1–256. Used in the latency → fps conversion (§3). |
resolution | Optional | Compared against the reference row's input resolution for the input-mismatch cause. |
jetpack | Optional | Together with power_mode, triggers the Jetson Configuration Checker hand-off (§8) — Jetson hardware only. |
power_mode | Optional | nvpmodel preset name. |
install_method | Optional | Passed through to the Configuration Checker (sdk_manager, sd_card_image, iso_image, apt_upgrade, flash_sh, unknown). |
deployment | Default bare_metal | bare_metal or docker — passed to the Configuration Checker. |
thermal_state | Default unknown | active_cooled, passive, enclosed, unknown — weights the thermal-throttling cause. |
clocks_locked | Optional boolean | Weights the clocks-not-locked cause. |
warmup | Optional boolean | Weights the no-warmup cause. |
samples | Optional integer | < 50 weights the no-warmup / short-run cause. |
super_flash | Optional boolean | Whether the board was flashed with the Super configuration — weights the super-flash-missing cause and is passed to the Configuration Checker. |
3. Measured-value normalisation
The engine compares like with like: your measurement is converted into whichever metric the reference uses (fps, latency or tokens/s), not the other way round.
If the value used was derived rather than given directly, the result
carries an assumption stating so and flags measured.converted.
The reference row decides which metric is compared: LLM/VLM rows compare
on tokens_per_s; everything else compares on fps
unless the only published metric is latency_ms.
4. The reference rule
The reference is the Benchmark Explorer's expected range for the exact hardware × model family × variant × precision: the min / median / max of every matching row (both evidence classes), the count, and how many of those rows are class C (measured and published). The characteristic runtime, resolution, batch and power mode shown alongside the range come from the single best-evidenced row in that set (class C over D).
When no row exists for the requested precision, the
reference falls back to the same estimator hierarchy the Inference
Estimator and Benchmark Explorer use — it tries a class-B (EdgeAIStack
measurement), then class-C (measured benchmark), then class-D (derived)
source in that order, and reports which tier answered plus the whole
tier chain it walked. Reference platforms outside the
hardware catalog (e.g. NVIDIA A100, T4, Raspberry Pi 5) have no estimator
hierarchy; an unmatched precision on those reports no reference
(NO_REFERENCE) rather than a guess.
Other precisions. When the requested precision has zero matching rows, the result also lists every other precision that does have rows for the same hardware × family × variant, with its median and best evidence class — so a request for FP8 on a board that only has published INT8 numbers still shows what is actually known.
5. The verdict rule and constraint status
The band is built from the range edges, not the median, with a ±15% tolerance:
Direction-aware for latency. BELOW_RANGE / ABOVE_RANGE
describe measured performance relative to the band, not the
numeric position of the value. For fps and tokens/s, higher is better, so
a measured value under lower is BELOW_RANGE (worse) and over
upper is ABOVE_RANGE (better) — direction matches magnitude.
For latency, lower is better, so the comparison flips: a latency
under lower (faster than the band's low end) is
ABOVE_RANGE, and a latency over upper (slower than
the band's high end) is BELOW_RANGE. The gap_ratio itself is
always the raw measured ÷ median — for latency a ratio above
1 means slower (worse), even though the verdict word is "below".
Constraint status, shown alongside the verdict:
ABOVE_RANGE always resolves to PASS — outperforming the published range is not a constraint violation (though §7's "reference is an estimate" cause still explains it when the reference is class D).
6. The ranking rule
Causes are ranked only for BELOW_RANGE and ABOVE_RANGE verdicts (direction
= "below" or "above"); WITHIN_RANGE and NO_REFERENCE rank nothing. For
every cause in the library whose direction matches (or is
both) and whose applies() guard is true for the
request:
Causes are sorted by likelihood descending. weight()
is a per-cause function of the request and, where relevant, the
Configuration Checker's checks (§8) — for example, "power mode below
maximum" weights near zero when you already reported the maximum preset,
and weights higher the further your reported preset's wattage is below
the maximum. Each ranked cause carries its explanation, its verify
command(s) with expected output and source, its remediation, and its
sources. The engine also builds an ordered, de-duplicated verify
plan across the top causes (up to 8 steps) so you can work down
it and stop at the first command that settles the gap.
7. Cause catalogue
Every cause the engine can rank, from
edgeaistack-api/src/v2/data/reality_check_causes.js. Evidence
class A = a vendor document backs the
mechanism (NVIDIA developer guide, TensorRT developer guide);
D = the cause itself is about the
reference being an EdgeAIStack estimate; E
= an engineering heuristic — plausible and widely reported, but not tied
to a specific vendor document.
Below range (your number is slower / worse than the band)
| Cause | When it applies | Typical effect band | Class | Verify | Remediation |
|---|---|---|---|---|---|
| You measured the whole pipeline scope_end_to_end |
You reported scope: end_to_end. Weight 0.95 — reference rows are inference-only. |
0.3–0.7× | E | trtexec --loadEngine=<model>.engine --iterations=200 --warmUp=500 (or hailortcli benchmark / yolo benchmark for that runtime) → mean latency/throughput for the model alone. Source: Ultralytics benchmark guide. |
Compare an inference-only measurement with the reference; size the full pipeline with Camera Stream Capacity, which budgets decode, preprocessing and tracking separately. |
| Power mode not the maximum preset power_mode_below_max |
Jetson hardware. Weight scales with how far the reported preset's wattage is below the maximum (MAXN / MAXN_SUPER); near zero if you already reported the maximum. | 0.4–0.85× | A | sudo nvpmodel -q → NV Power Mode: <MODE_NAME>. Source: NVIDIA Jetson Linux Developer Guide — Platform Power and Performance. |
sudo nvpmodel -m <id> for the maximum preset, then re-measure. |
| Clocks not locked clocks_not_locked |
Jetson hardware and clocks_locked is not true. Weight 0.85 when explicitly false, 0.6 when unstated. |
0.6–0.95× | A | sudo jetson_clocks --show → current vs. max CPU/GPU/EMC clocks. Source: NVIDIA Jetson Linux Developer Guide. | sudo jetson_clocks (after nvpmodel), confirm with --show, then re-measure with ≥ 200 iterations after warm-up. |
| Thermal throttling thermal_throttling |
Jetson, Hailo or RK3588 hardware. Weight 0.85 for passive/enclosed, 0.5 for unknown, 0.25 for active_cooled. |
0.5–0.9× | A | tegrastats → live GR3D_FREQ and per-rail temperature/power. Source: NVIDIA Jetson Linux Developer Guide — tegrastats utility. |
Watch tegrastats during the run: GR3D_FREQ dropping below maximum or temperatures above ~80 °C means throttling; add airflow or reduce the power preset and re-measure. |
| Framework runtime instead of the optimised engine framework_not_tensorrt |
Runtime is PyTorch / ONNX Runtime / Transformers / CPU while the reference used an optimised runtime (TensorRT, Hailo SDK, Edge TPU, RKNN); or runtime is llama.cpp/Ollama while the reference used MLC. Weight 0.9 (0.7 for the LLM-runtime case). | 0.2–0.6× | E | LLM case: mlc_llm bench <model> --device cuda → decode tokens/s near the reference. Otherwise: python3 -c "import tensorrt; print(tensorrt.__version__)" → confirms TensorRT is importable before you export to it. | Export to TensorRT (yolo export format=engine, or trtexec) — or the platform SDK — and measure that engine; or measure with the reference's own runtime (MLC) instead of llama.cpp/Ollama. |
| Precision differs from the reference row precision_mismatch |
The reference is a fallback (no row at the requested precision), or the reference row's precision differs from what you reported. Weight 0.7 (fallback) / 0.6 (stated mismatch). | 0.4–0.8× | E | trtexec --loadEngine=<model>.engine --verbose 2>&1 | grep -i "precision\|int8\|fp16" → the engine's actual build precision. Source: TensorRT Developer Guide. | Rebuild the engine at the reference precision (INT8 with a calibration set, or FP16) and compare like with like. |
| Input size or batch differs input_mismatch both directions |
Your resolution or batch differs from the reference row's. Weight 0.8. |
0.4–2.5× | E | trtexec --loadEngine=<model>.engine 2>&1 | grep -i "input\|shape" → input shape N×3×H×W matching the reference. Source: Ultralytics benchmark guide. | Re-export at the reference input size and batch 1, or query the explorer at your input size. |
| TensorRT engine built for another TensorRT / JetPack trt_version_mismatch |
Runtime is TensorRT on Jetson. Weight 0.8 when the Configuration Checker's runtime check is non-PASS, else 0.35. |
0.5–0.95× | A | dpkg -l | grep tensorrt and cat /etc/nv_tegra_release → installed TensorRT/L4T versions. Source: TensorRT Developer Guide (engine portability). | Rebuild the engine on the target with the installed TensorRT and re-measure. |
| Super presets absent super_flash_missing |
Orin Nano / NX on JetPack 6.2+. Weight 0.85 when the Configuration Checker flags the power-mode check VERSION_RISK / UNSUPPORTED / REQUIRES_VALIDATION, 0.8 when install_method: iso_image, else 0.4. |
0.5–0.8× | A | cat /proc/device-tree/model (look for "Super") and sudo nvpmodel -q. Source: power-mode registry Super-enablement note. | Flash with the jetson-orin-nano-devkit-super configuration from an x86 host (SDK Manager); the ISO image cannot upgrade a board into Super Mode. |
| JetPack / runtime configuration not the published pairing jetpack_pairing |
The Configuration Checker flags module_support, install_method, runtime, artifact_cuda or artifact_ubuntu as non-PASS. Weight 0.9 if any check is UNSUPPORTED, else 0.6. |
0.5–0.95× | A | cat /etc/nv_tegra_release and dpkg -l nvidia-jetpack. Sources: the named JetPack release's registry sources. | Whatever the Configuration Checker's own remediation says for the failing check(s) — this cause surfaces its checks directly. |
| No warm-up or too few iterations no_warmup_or_short_run |
warmup: false, or samples < 50. Weight 0.8 / 0.6. |
0.5–0.9× | E | trtexec --loadEngine=<model>.engine --warmUp=500 --iterations=200 --avgRuns=50 → stable mean/median latency. Source: Ultralytics benchmark guide. | Discard ≥ 50 warm-up iterations and report the mean of ≥ 200 timed iterations. |
| Engine placed on DLA instead of GPU dla_vs_gpu |
Orin NX / AGX Orin with TensorRT. Weight 0.25 (low prior — most requests are GPU). | 0.3–0.7× | E | trtexec --loadEngine=<model>.engine --verbose 2>&1 | grep -i "DLA" → no DLA layers for a GPU engine. Source: TensorRT Developer Guide. | Rebuild without --useDLACore for a GPU comparison. |
| Host CPU / interface bottleneck host_side_bottleneck |
Hailo, Coral or RK3588 accelerator hardware. Weight 0.6 (fixed — no source cited, engineering heuristic). | 0.2–0.7× | E | SDK's own hardware-only benchmark (hailortcli benchmark --measure-latency / Coral classify_image.py / rknn_benchmark) → hw-only throughput near the reference. |
If hw-only matches the reference, the gap is host-side — use a faster host link (PCIe over USB) or move pre/post-processing off the CPU. |
Above range (your number is faster / better than the band)
| Cause | When it applies | Typical effect band | Class | Verify | Remediation |
|---|---|---|---|---|---|
| The reference is an EdgeAIStack estimate reference_is_estimate |
The best-evidenced matching row (or the fallback) is class D. Weight 0.85. | 1.1–2.0× | D | No verify command — this cause is settled by comparing evidence classes, not by running anything. | Submit your measurement (with the protocol fields) so it replaces the estimate as a class C row. |
| Newer JetPack / TensorRT than the reference row newer_software |
Jetson hardware. Weight 0.5 (fixed). | 1.05–1.4× | E | cat /etc/nv_tegra_release and dpkg -l | grep tensorrt → your JetPack/TensorRT versions. Source: Ultralytics benchmark guide. | Note the JetPack and TensorRT versions with your submission; the explorer keeps rows per software version. |
| Smaller input or batched inference smaller_input_or_batching |
batch > 1, or resolution differs from the reference row's. Weight 0.8. |
1.2–4.0× | E | trtexec --loadEngine=<model>.engine 2>&1 | grep -i "input\|shape" → confirms input shape/batch. Source: Ultralytics benchmark guide. | Compare at batch 1 and the reference input size, or query the explorer with your input size. |
| Lighter variant or lower precision than the reference lighter_variant_or_precision |
The reference is a fallback, or its precision differs from what you reported. Weight 0.5 (fixed, no source cited). | 1.2–3.0× | E | trtexec --loadEngine=<model>.engine --verbose 2>&1 | grep -i "precision" → confirms build precision. Source: TensorRT Developer Guide. | Confirm variant and precision, then compare against the matching row. |
Publisher documents behind the class-A causes
| Publisher | Document · doc id | Verified |
|---|---|---|
| NVIDIA | Jetson Linux Developer Guide — Platform Power and Performance · nvidia-docs:jetson/r36.4.4/DeveloperGuide/SD/PlatformPowerAndPerformance | 2026-09-07 |
| Ultralytics | NVIDIA Jetson guide — benchmark methodology · ultralytics:guides/nvidia-jetson#benchmarks | 2026-09-07 |
| NVIDIA | TensorRT Developer Guide — engine compatibility · nvidia-docs:deeplearning/tensorrt/developer-guide | 2026-09-07 |
| NVIDIA | Jetson Linux Developer Guide — tegrastats utility · nvidia-docs:jetson/r36.4.4/DeveloperGuide/AT/JetsonLinuxDevelopmentTools/Tegrastats | 2026-09-07 |
Causes flagged E without a cited document (host-side bottleneck, newer-software, lighter-variant-or-precision) are engineering heuristics stated as such — widely reported directionally, not backed by a specific vendor claim about the magnitude.
8. Configuration hand-off
When both jetpack and (optionally) power_mode
are given for Jetson hardware, the engine runs the
Jetson Configuration
Checker internally and folds its non-PASS checks into the cause
weights:
| Configuration Checker check | Feeds cause | Effect |
|---|---|---|
power_mode → VERSION_RISK / UNSUPPORTED / REQUIRES_VALIDATION | super_flash_missing | Weight raised to 0.85. |
runtime → non-PASS | trt_version_mismatch | Weight raised to 0.8 (from 0.35). |
module_support, install_method, runtime, artifact_cuda, artifact_ubuntu → any non-PASS | jetpack_pairing | Cause applies at all only when at least one of these is non-PASS; weight 0.9 if any is UNSUPPORTED, else 0.6. |
If the Configuration Checker cannot run (non-Jetson hardware, or an
internal error), the result carries a warning
(Configuration check skipped: …) and the causes that read its
checks fall back to their non-configuration weight.
9. Submit prefill
Every result carries a submit_prefill object —
hardware, model_family, variant,
precision, runtime (yours, or the reference's if
you didn't state one), scope, resolution (yours,
or the reference's), batch, fps,
latency_ms, tokens_per_s, jetpack
and power_mode — pre-filling the
measurement protocol
submission form so a WITHIN_RANGE or ABOVE_RANGE result (or any
NO_REFERENCE result) can become a class-C row with one click, without
retyping the workload.
10. Evidence classes and confidence
This grades the reference, not the ranking: a HIGH-confidence verdict still ranks causes with the same likelihood × fit rule as a LOW one — confidence tells you how much to trust the number you were compared against, not how much to trust which cause is listed first.
11. What invalidates a result
- A dataset update. The reference is read live from the Benchmark Explorer database; a newer research pass or measurement submission that adds or replaces a row for this hardware × family × variant × precision changes the range and can flip the verdict.
- A class-D reference later measured. Submitting a measurement for a configuration that currently only has a class-D estimate replaces it with a class-C row — an ABOVE_RANGE result explained by "the reference is an estimate" (§7) is exactly the signal that this is about to happen.
- Self-reported fields that don't match reality.
clocks_locked,warmup,thermal_stateandsuper_flashare taken as given; the ranking is only as good as what you reported. The verify commands exist precisely to check them independently. - A JetPack / power-mode configuration that changes. Re-flashing, changing the power mode or moving JetPack versions changes what the Configuration Checker hand-off (§8) reports, which changes the weights on several causes.
- A coverage gap filled by future research — a NO_REFERENCE result today may gain a real reference once a measurement lands for that exact configuration.
12. Limitations
- Causes are ranked heuristics, not measurements.
likelihoodcombines a prior (how often this cause explains a gap of this shape, in general) with a fit score (how well its typical effect band matches your specific gap) — it is not a probability estimated from your board's actual telemetry. The verify command, not the ranking, is what actually settles a cause. - No thermal model. The thermal-throttling cause reasons from your reported
thermal_state, not from a measured temperature curve; it cannot tell you how close to throttling you are, only that enclosed/passive cooling raises the prior. - End-to-end pipelines need a different engine. This engine's reference rows are inference-only; if you measured a full camera pipeline (decode, pre/post-processing, tracking, encode), use Camera Stream Capacity to budget the pipeline, not this engine to explain the gap.
- Several causes carry a fixed weight regardless of context (host-side bottleneck 0.6, newer-software 0.5, lighter-variant-or-precision 0.5, DLA-vs-GPU 0.25) because no further signal distinguishes cases — they rank on fit to the gap size alone.
- Inherits every limitation of the Benchmark Explorer reference (§13 there): most rows are class D, publisher measurement conditions are not always fully stated, and the cross-hardware comparison is not repeated here.
13. Method changelog
| Method | Date | Change |
|---|---|---|
| 1.0 | 2026-09-07 | First release. Reference from the Benchmark Explorer's expected-range rule with its B → C → D fallback; ±15% verdict band around the range edges, direction-aware for latency; 17-cause library (13 below-range, 4 above-range) ranked by prior × fit to the gap ratio; Jetson Configuration Checker hand-off for 3 causes; submit prefill into the measurement protocol form. |
Method changes bump the method version. The underlying reference data (the benchmark database, the JetPack registry, the power-mode registry) versions independently — see the Benchmark Explorer and Jetson Configuration Checker methodology pages for their dataset versions.
Check your own number against the reference.
Every result carries the reference rows, the ranked causes with their verify commands, and a permanent link. Run the check at /engines/benchmark-reality-check/, browse what's actually been measured at Benchmark Explorer or /benchmarks/, and read the measurement protocol to submit your own class-C row.