open-standards/wai/research/determinism-cost.md
Transaction Science f218af5ac0
Some checks failed
wai-ops-gpu integer operators on GPUs / does this change touch it (push) Successful in 25s
WAI operation catalogue / does this change touch it (push) Successful in 34s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 40s
wai-det-jpegai WAISM float-level module of record / does this change touch it (push) Successful in 1m7s
wai-app and Create / wai-app · does this change touch it (push) Successful in 46s
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 1m23s
wai-ops integer operators / does this change touch it (push) Successful in 35s
wai-quantum for JavaScript / does this change touch it (push) Successful in 31s
wai-sink-android native sink library / does this change touch it (push) Successful in 18s
wai-pack / wai-pack · does this change touch it (push) Successful in 33s
wai-ledger service / does this change touch it (push) Successful in 1m37s
joule-moq-http live HTTP egress / joule-moq-http · does this change touch it (push) Successful in 1m48s
wai-audit collector and player integration / does this change touch it (push) Successful in 1m44s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 1m47s
wai-key-proxy / does this change touch it (push) Successful in 1m38s
wai-fleet service / does this change touch it (push) Successful in 1m38s
WAI Studio / does this change touch it (push) Successful in 22s
wai-sink-swift native sink package / does this change touch it (push) Successful in 51s
wai-quantum studio and desktop / does this change touch it (push) Successful in 1m9s
wai-ops-gpu integer operators on GPUs / Vulkan GPUs (framework-128gb) (push) Successful in 9m59s
wai-ops-gpu integer operators on GPUs / Vulkan GPUs (jetson-hub) (push) Successful in 11m56s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Has been cancelled
WAI Studio / Studio in Chromium and Firefox · macos (push) Has been cancelled
WAI Studio / Studio in WebKit · linux (push) Has been cancelled
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Has been cancelled
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Has been cancelled
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Has been cancelled
wai-quantum studio and desktop / studio · browser (push) Has been cancelled
wai-quantum studio and desktop / desktop app · macos (push) Has been cancelled
wai-quantum studio and desktop / desktop app · linux (push) Has been cancelled
wai-quantum studio and desktop / desktop app · windows (push) Has been cancelled
wai-quantum for JavaScript / javascript · linux (push) Has been cancelled
wai-pack / wai-pack · linux (push) Has been cancelled
wai-pack / wai-pack · linux-arm64 (push) Has been cancelled
wai-pack / wai-pack · macos (push) Has been cancelled
wai-pack / wai-pack · independent verifier (Python) (push) Has been cancelled
wai-pack / wai-pack · the floor through a media prober (push) Has been cancelled
wai-pack / wai-pack · dependency licences (push) Has been cancelled
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (push) Has been cancelled
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (push) Has been cancelled
wai-ledger service / service · linux (push) Has been cancelled
wai-ledger service / service · macos (push) Has been cancelled
wai-key-proxy / proxy · linux (push) Has been cancelled
wai-fleet service / service · linux (push) Has been cancelled
wai-fleet service / service · macos (push) Has been cancelled
WAI examples / WAI examples · does this change touch them (push) Has been cancelled
WAI examples / WAI examples · portable · linux (push) Has been cancelled
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (push) Has been cancelled
WAI examples / WAI examples · android-app · linux-arm64 (push) Has been cancelled
wai-det-jpegai WAISM float-level module of record / linux · both checkers, F1, F2 on wasmtime (Cranelift, Winch, Pulley) and Wasmi, the planted faults (push) Has been cancelled
wai-det-jpegai WAISM float-level module of record / linux-arm64 · both checkers, F1, F2 on wasmtime (Cranelift, Winch, Pulley) and Wasmi, the planted faults (push) Has been cancelled
WAI operation catalogue / the catalogue and every door · linux (push) Has been cancelled
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Has been cancelled
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Has been cancelled
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Has been cancelled
wai-audit collector and player integration / collector · linux (push) Has been cancelled
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Has been cancelled
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Has been cancelled
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Has been cancelled
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (push) Has been cancelled
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Has been cancelled
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Has been cancelled
joule-moq-http live HTTP egress / joule-moq-http, every target (push) Has been cancelled
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 37s
wai-ops integer operators / linux-aarch64 (push) Successful in 4m58s
wai-ops integer operators / wasm32-wasip2 (wasmtime) (push) Successful in 1m1s
wai-ops integer operators / independent checker (Python) (push) Successful in 26s
wai-ops integer operators / wasm32 under Node (push) Successful in 50s
wai-ops integer operators / linux-x86_64 (push) Successful in 3m6s
wai-ffmpeg / wai-ffmpeg · VLC 3.0.24 on the patched FFmpeg, playing the corpora (push) Failing after 4m37s
wai-gstreamer / wai-gstreamer · the plugin on a distribution's GStreamer (push) Failing after 5m59s
wai-ffmpeg / wai-ffmpeg · the series on FFmpeg 9.0.2, checked and fuzzed (push) Successful in 17m38s
wai-ops integer operators / macos-arm64 (push) Successful in 1m55s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 9m49s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 15m49s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 20m14s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 14m1s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 12m3s
wai.image.jpegai: the exact decoder decodes the configurations of its bundle's model its vectors hold; two the reference leaves to the machine are refused configuration_undetermined
Completeness row C8. The exact decoder (jpegai_decode) decoded one configuration, the
reference codestream's; every other trapped. With the jpegai/v1 bundle (tools_0, the
high-operation-point synthesis, one eICCI pair) it now decodes:
- pictures whose sides are 128, 192 or 256, any display cropping (the post-filters run on the
  displayed picture; eICCI pads a side to a multiple of 4 by repetition);
- beta_displacement_log from -1069 to 702, the chroma one independent or not;
- LSBS off per plane; residual variance scaling and GRFS both off, or GRFS alone (one band);
- each post-filter off; eICCI on any plane subset with the bundle's pair; no colour transform.
Held by 29 configuration vectors (wai-rs/tests/vectors/jpegai/configs/: synthetic pictures the
reference software's encoder coded at each configuration, its rate search off, and header
edits of them), each pinned to its RGB8 (the same digests on Linux x86_64 and macOS arm64),
decoded the direct way to the same bits at every stage, and max|d| = 1 from the reference
decoder's picture on 2.5% to 6.6% of samples (tests/jpegai_configs.rs; wai-jpegai-e2e.yml).

Refused with a new code, configuration_undetermined (D74): residual variance scaling without
GRFS (the reference dequantises it by an integer shift or a float division as its tables sit,
and raises on a CPU) and a signalled colour matrix (a library inverse, applied by its first
row alone; the reference raises before either). Everything else outside scope is refused as
before, each with a vector or a header test showing where.

Readings fixed (D74): the scale's incomplete 8x8 blocks pad with 1411; LEF samples its scale
surface at the binary32 quotient's floor; no colour transform gives the decoded components.
The float ONNX path keeps the reference codestream's configuration alone
(check_reference_configuration). The scale path's text (integer-operators 13.6.1) gains the
picture's sizes, beta and the RVS modes; 13.6.2 states the graphs' declared sizes as maxima.

Second reader: tools/wai_jpegai_header.py (standard library) reads and writes the headers and
gives each codestream's scope; tools/wai_jpegai_configs.py writes the manifest, checks that
reader against it and holds decodes to the reference pictures; tools/wai_jpegai_make_vectors.py
makes the vectors (the edits regenerate byte for byte).

Planted faults (cfg(wai_planted), never in an ordinary build), each caught by the vectors:
likely-pad-index, beta-after-likely, grfs-only-floor, rvs-mode-swap, lef-nearest-round,
icci-pad-index, crop-index, icci-subset-swap, lsbs-off-ignored, ct0-order.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-12 04:54:58 -05:00

453 lines
67 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# What exactness costs: `wai.neural.int_hyper` against its float model
> **Status.** A measured record and its procedure, informative. Every figure below is
> computed from the readings in [`determinism-cost/record.json`](determinism-cost/record.json),
> and `tools/wai_determinism_cost_verify.py` recomputes each one from those readings and
> checks every figure this page and [determinism-tiers](../extensions/determinism-tiers.md)
> §7 quote from it (each is followed by a `det` marker naming its place in the record).
> What WAI claims, and does not, on the strength of this record is in determinism-tiers §7.
> Measured 2026-10-22; the runs of §4.6, on the narrow kernel sets, 2026-10-24 and 2026-10-25.
## 1. What is measured, and what is not
`wai.neural.int_hyper` is an integer export of one pretrained learned codec: the
mean-scale hyperprior `mbt2018_mean` (MSE), quantised to per-channel 12-bit weights and
activations at 2¹², with an integer inverse GDN and an integer hyper-decoder that decides
every entropy table (determinism-tiers §5). The float model is the same checkpoint, coded
and decoded by the library its checkpoints are published with. This record measures what
the integer decode costs against that float model, at all eight published qualities, on
pictures of the pinned reference set:
1. **Rate and distortion**: the BD-rate of the integer codec against the float codec, by
PSNR and by MS-SSIM (§2.4).
2. **Reproducibility across platforms**: each codec's streams decoded on every platform
reached, and each decode compared byte for byte with the first platform's (§2.5).
3. **Time and energy** of a decode, both codecs, on the CPU and on a GPU (§2.6).
Not measured here, and why:
- **`wai.image.jpegai`'s exact decoder.** It implements the configurations of one model of
the base standard (tools_0), whose β displacement is a rate axis within it; coding the
reference set along it needs the standard's reference encoder, which has run here only on
the synthetic configuration vectors, not on the reference set. Its comparisons with the
reference decoder, on the reference codestream and on those vectors, are determinism-tiers
§5 and §6.
- **`wai.neural.int_synth` and `wai.neural.int_mlicpp`.** Neither has a float model with a
rate axis to compare with: the committed `int_synth` vectors are a synthesis from a
given latent (one of them a quantised float model trained on one photograph, the others
seeded integer weights), and the `int_mlicpp` vector has seeded weights.
- **`wai.neural.mbt2018_mean`**, WAI's float capability over the same model family, which
decodes through an ONNX runtime. The float side here is the model's own library.
- **A neural processor.** No decoder on main runs its graphs on one
(determinism-tiers §5).
- **The encoder.** Both codecs analyse the picture in floating point. The integer tier
covers the decode: the bytes of a payload depend on the machine that encoded it, and
every conforming sink then decodes those bytes to the same picture.
## 2. Procedure
### 2.1 Pictures
The pinned reference manifest `wai-image-references.json` (SHA-256 `db33c663…6b554b66`,
the manifest `tools/wai_visual_provenance_check.py` pins) lists 384 files. The rule:
every PNG entry the manifest marks `self_test` that holds one picture of 768×512 or
512×768 samples. That gives 24 pictures, each checked against the manifest's SHA-256
before it is read and named in the record by the first 16 hex digits of that digest.
Both sides are multiples of 64, so every picture is coded whole.
### 2.2 The two codecs
- **Checkpoints.** The eight published `mbt2018_mean` (MSE) checkpoints, qualities 1–8,
each pinned by the SHA-256 of its bytes (`CKPT_SHA256` in
`tools/wai_determinism_cost.py`, and in the record) and loaded as tensors only.
Qualities 1–4 have N = 128, M = 192; qualities 5–8, N = 192, M = 320.
- **Float codec.** The library's own `compress` and `decompress` (release 1.2.8, on the
pinned stack of `tools/requirements-sota-int.txt`): the float analysis, the factorised
hyper-latent, the float hyper-decoder deciding each scale bucket, the float synthesis.
Its reconstruction in [0, 1] becomes 8-bit samples by ×255 and rounding half to even.
- **Integer codec.** The same model exported per quality exactly as
`tools/wai_sota_int_synth_export.py` exports quality 6, coded as a `WIH1` payload
(integer-payloads §4), and decoded by `wai_det_cost`, which runs `int_payload::decode_int`,
the integer decode path every reference sink runs. Two cross-checks tie the export to
the one CI already checks, both run on the build host: the quality-6 set this procedure
writes (`g_s.whm`, `h_s.whm`, `entropy.json`) is byte for byte the set the export tool
writes; and on the export tool's pinned photograph (from `tools/wai_sota_source_image.py`),
this procedure's integer encoder gives the export tool's hyper-decoder output and writes
both rANS streams byte for byte as the export tool does.
- **Encoding.** The library on one CPU thread with deterministic algorithms, on the build
host (§3).
### 2.3 Rate and distortion
- **Rate**: the bytes of the two entropy-coded streams, hyper-latent and latent, for both
codecs, ×8 over the picture's samples per channel (bits per pixel). A `WIH1` payload adds
a 32-byte header and two 4-byte lengths, which are not counted; the record keeps each
payload's size.
- **PSNR**: 10·log₁₀(255²·n / SSE) over all n samples of the three channels, against the
picture's 8-bit samples.
- **MS-SSIM**, the perceptual metric: per channel on 8-bit samples (dynamic range 255),
five scales, an 11-tap Gaussian window of σ = 1.5 applied over the valid region,
K₁ = 0.01, K₂ = 0.03, 2×2 mean pooling between scales, the contrast-structure term at
the first four scales and luminance-contrast-structure at the fifth, exponents 0.0448,
0.2856, 0.3001, 0.2363 and 0.1333, each term clamped at zero; the mean over the three
channels. BD-rate reads it as −10·log₁₀(1 − MS-SSIM).
### 2.4 BD-rate
Per picture, the integer codec's eight (rate, quality) points against the float codec's
eight, by the Bjøntegaard delta of ITU-T VCEG-M33: log₁₀ of the rate interpolated as a
function of quality by a monotone piecewise-cubic Hermite interpolant (the
Fritsch–Carlson slopes with the three-point shape-preserving ends), each curve integrated
over the quality range the two share, and the mean difference in log rate turned into a
percentage. A positive figure is the extra rate the integer codec needs for the float
codec's quality. A curve whose quality does not rise strictly with rate has no BD-rate, and
the record lists such pictures. The record states each picture's figure, and their
median, mean, minimum and maximum.
### 2.5 Reproducibility across platforms
Every integer payload is decoded on each platform of §3, and each decode's RGB8 compared
by SHA-256 with the build host's first decode of it. Every float stream is decoded again
in a fresh process on each platform and device of §3, under the entropy tables the
encoder used (their SHA-256 is recorded per platform, so a difference in the tables would
show), and its RGB8, its decoded entropy-table indexes and its decoded symbols compared,
each by SHA-256, with the encoding process's own decode. A decode whose indexes or symbols
differ has diverged in the entropy decode; one whose symbols agree and whose samples
differ has diverged after it. For every float decode that differs, the record keeps its
PSNR change.
### 2.6 Time and energy
`tools/wai_det_energy.py` runs a decoder as a child process that loads its models and
streams, decodes each once, and then decodes the same eight pictures (the first eight of
§2.1, at quality 2 and at quality 6) in each of seven rounds on command, blocking between
rounds. A round's time is the child's own clock around its decodes; every decode's output is
hashed and compared with its first decode, so no time is reported for a different output.
The counters, each with its scope:
- **The decoder's own CPU energy** (macOS): the kernel's per-task energy count
(`ri_energy_nj`, `proc_pid_rusage`), read while the child blocks and only once its CPU
time has stopped moving, so every thread's energy has folded into the count. Scope: the
decoding process, CPU only; it excludes the GPU. Class `OnChipCounter`, filtering
unknown. Energy that system services spend on the process's behalf is billed to it in a
separate count, which the record keeps beside it.
- **The GPU rail** (macOS): IOReport's `GPU Energy` channel, the whole GPU, read every
100 ms. A round's GPU figure counts only where the decoder held at least 99% of the GPU
time that every accelerator client accumulated over the round (the I/O Registry's
`accumulatedGPUTime`), which the record keeps per round.
- **Package energy** (Linux): powercap `package-0`, the whole package, read every 100 ms.
A whole-device counter is bracketed by 5 s idle windows before and after every round. A
round's marginal energy is the counter's advance over the round minus the mean idle power
of its two brackets times the round's span, and its ratio is the marginal power over the
larger idle standard deviation (energy-measurement §3, §4). A round's figure is used only
where the counter was live in the round and in both its brackets (energy-measurement §3.1:
advancing in two intervals in a row, in five or more and in at least four of every five,
over at least 300 ms) and its ratio is at least 3; a figure is publishable only where all
seven rounds are used and read clean (ratio ≥ 10). The record
gives every round's readings, and per run the median, minimum and maximum over rounds of
the time and of each energy figure per decode, with the host's load average.
## 3. Platforms
| platform | machine | what ran |
|---|---|---|
| build host | arm64 desktop SoC, 24 performance and 8 efficiency cores, 80-core integrated GPU; macOS 27.0.1; shared, under heavy load from other work | both encoders; the integer decode on the CPU (all cores, one core), on the GPU (Metal) and as wasm32-wasip2 under wasmtime 49.0.3; the float decode on the CPU (one thread, the library's default of 24) and on the GPU (Metal); the timed runs with the per-task count and the GPU rail |
| x86_64 host A | x86_64 SoC, 16 cores and 32 threads, AVX-512, integrated GPU of PCI vendor 0x1002 (device 0x1586); Linux 7.0, glibc 2.43; shared, otherwise lightly loaded | the integer decode on the CPU, on the GPU (Vulkan, Mesa 26.0.8) and as the build host's wasm32-wasip2 binary under wasmtime 49.0.3; the float decode on the CPU (one thread, the library's default of 16); the timed runs with the package counter |
| x86_64 host B | x86_64 laptop CPU, 14 cores and 20 threads, AVX2, discrete GPU of PCI vendor 0x10de (device 0x28e1); Linux 7.0, glibc 2.39 | the integer decode on the CPU and on the GPU (Vulkan, driver 595.84); the float decode on the CPU (the library's default of 14 threads) and on the GPU (through the GPU vendor's compute API, in the float stack's 2.14.0 build for it) |
Builds: rustc 1.98.0, release profile, `--no-default-features --features neural_int`
(with `ops_gpu` for the GPU decodes, wgpu 30.0.1); the wasm32-wasip2 binary was built once,
on the build host, and the same file ran on both hosts. Float stack: Python 3.11 (3.12 on
host B), the pinned versions of `tools/requirements-sota-int.txt` (its CPU-only build on
host A, its GPU build on host B), with deterministic algorithms requested. The tags under which the record
keeps each platform are in `determinism-cost/runs/README.md`.
§4.6's builds are the same, from the change that added the narrow kernel sets, made on each
host (the wasm32-wasip2 file again once, on the build host), beside each host's build of the
record's own commit; on host A the float stack was set up again from the same pinned
versions. Host B's GPU was not reached for §4.6 (its driver was not loaded when the runs
were taken), so its GPU decode is the record's only.
## 4. Results
Every figure here is the record's, and the verifier of §6 recomputes it; each is followed by a marker naming
its place in `record.json`, and `wai_determinism_cost_verify.py` holds the text to the
record.
In brief:
- **Rate.** At equal PSNR the integer codec needs a median of
+1.61 %<!--det:summary.bd_rate_percent.psnr.median--> more rate than the float codec over
the 24 pictures, and at equal MS-SSIM a median of
+0.95 %<!--det:summary.bd_rate_percent.ms_ssim.median-->. The smallest figure of any
picture is +0.56 %<!--det:summary.bd_rate_percent.psnr.min--> by PSNR and
+0.52 %<!--det:summary.bd_rate_percent.ms_ssim.min--> by MS-SSIM: the export costs rate on
every picture (§4.1, and each picture's figure in the record).
- **Bytes.** The integer decode gave the same bytes on every platform, under every kernel
set: 0<!--det:summary.integer_cross_platform_total.differ--> of
4608<!--det:summary.integer_cross_platform_total.decodes--> decodes differed (§4.3, §4.6). The
float decode gave the encoder's bytes only on the encoder's own CPU. Everywhere else it
gave other bytes for every stream, and its entropy decode diverged on many of them, from
76<!--det:summary.float_cross_platform.linux-x86_64-b-cpu.symbols_differ--> of 192 on host
B's CPU to 192<!--det:summary.float_cross_platform.linux-x86_64-b-cuda.symbols_differ--> on
its GPU (§4.4).
- **Time and energy.** On host A, where every round read clean, the record's integer
decode took longer and drew more package energy than the float decode on the same CPU, at
both qualities, and so did the integer decode with its graphs on the integrated GPU
(§4.5). On the narrow kernel sets (§4.6) the same integer decode, giving the same bytes,
took 144.8<!--det:summary.timing.linux-int-cpu-q6-after.ms_per_decode.median--> ms and
12.43<!--det:summary.timing.linux-int-cpu-q6-after.rapl.marginal_j_per_decode.median--> J at quality 6
against 210.7<!--det:summary.timing.linux-float-cpu-q6-again.ms_per_decode.median--> ms and
14.03<!--det:summary.timing.linux-float-cpu-q6-again.rapl.marginal_j_per_decode.median--> J for the float
decode measured beside it, and less time and energy than the float decode at quality 2
as well. On the build host it still drew more of its own CPU energy than the float decode
(§4.6, and §5 on what that count covers there).
### 4.1 BD-rate, integer codec against float codec
| quality metric | pictures | median | mean | min | max |
|---|---:|---:|---:|---:|---:|
| PSNR | 24<!--det:summary.bd_rate_percent.psnr.n--> | +1.61<!--det:summary.bd_rate_percent.psnr.median--> % | +1.71<!--det:summary.bd_rate_percent.psnr.mean--> % | +0.56<!--det:summary.bd_rate_percent.psnr.min--> % | +2.97<!--det:summary.bd_rate_percent.psnr.max--> % |
| MS-SSIM | 24<!--det:summary.bd_rate_percent.ms_ssim.n--> | +0.95<!--det:summary.bd_rate_percent.ms_ssim.median--> % | +1.03<!--det:summary.bd_rate_percent.ms_ssim.mean--> % | +0.52<!--det:summary.bd_rate_percent.ms_ssim.min--> % | +2.45<!--det:summary.bd_rate_percent.ms_ssim.max--> % |
### 4.2 Per quality (medians over the pictures)
| quality | float bpp | float PSNR (dB) | integer rate ÷ float rate | ΔPSNR (dB), integer − float | ΔMS-SSIM (dB), integer − float |
|---:|---:|---:|---:|---:|---:|
| 1 | 0.106<!--det:summary.per_quality.q1.float_bpp.median--> | 28.16<!--det:summary.per_quality.q1.float_psnr_db.median--> | 1.0006<!--det:summary.per_quality.q1.rate_ratio.median--> | -0.005<!--det:summary.per_quality.q1.delta_psnr_db.median--> | -0.005<!--det:summary.per_quality.q1.delta_ms_ssim_db.median--> |
| 2 | 0.166<!--det:summary.per_quality.q2.float_bpp.median--> | 29.74<!--det:summary.per_quality.q2.float_psnr_db.median--> | 1.0000<!--det:summary.per_quality.q2.rate_ratio.median--> | -0.007<!--det:summary.per_quality.q2.delta_psnr_db.median--> | -0.007<!--det:summary.per_quality.q2.delta_ms_ssim_db.median--> |
| 3 | 0.248<!--det:summary.per_quality.q3.float_bpp.median--> | 31.36<!--det:summary.per_quality.q3.float_psnr_db.median--> | 1.0000<!--det:summary.per_quality.q3.rate_ratio.median--> | -0.016<!--det:summary.per_quality.q3.delta_psnr_db.median--> | -0.010<!--det:summary.per_quality.q3.delta_ms_ssim_db.median--> |
| 4 | 0.370<!--det:summary.per_quality.q4.float_bpp.median--> | 32.99<!--det:summary.per_quality.q4.float_psnr_db.median--> | 1.0001<!--det:summary.per_quality.q4.rate_ratio.median--> | -0.032<!--det:summary.per_quality.q4.delta_psnr_db.median--> | -0.018<!--det:summary.per_quality.q4.delta_ms_ssim_db.median--> |
| 5 | 0.550<!--det:summary.per_quality.q5.float_bpp.median--> | 34.78<!--det:summary.per_quality.q5.float_psnr_db.median--> | 1.0000<!--det:summary.per_quality.q5.rate_ratio.median--> | -0.022<!--det:summary.per_quality.q5.delta_psnr_db.median--> | -0.010<!--det:summary.per_quality.q5.delta_ms_ssim_db.median--> |
| 6 | 0.792<!--det:summary.per_quality.q6.float_bpp.median--> | 36.79<!--det:summary.per_quality.q6.float_psnr_db.median--> | 1.0000<!--det:summary.per_quality.q6.rate_ratio.median--> | -0.174<!--det:summary.per_quality.q6.delta_psnr_db.median--> | -0.073<!--det:summary.per_quality.q6.delta_ms_ssim_db.median--> |
| 7 | 1.106<!--det:summary.per_quality.q7.float_bpp.median--> | 38.79<!--det:summary.per_quality.q7.float_psnr_db.median--> | 1.0000<!--det:summary.per_quality.q7.rate_ratio.median--> | -0.176<!--det:summary.per_quality.q7.delta_psnr_db.median--> | -0.108<!--det:summary.per_quality.q7.delta_ms_ssim_db.median--> |
| 8 | 1.511<!--det:summary.per_quality.q8.float_bpp.median--> | 40.78<!--det:summary.per_quality.q8.float_psnr_db.median--> | 1.0000<!--det:summary.per_quality.q8.rate_ratio.median--> | -0.942<!--det:summary.per_quality.q8.delta_psnr_db.median--> | -0.481<!--det:summary.per_quality.q8.delta_ms_ssim_db.median--> |
### 4.3 The integer decode across platforms
Tags (§3): `macos-arm64-cpu` the build host's CPU, all cores, and `-1t` one core; `macos-arm64-gpu-metal` its GPU; `wasm32-wasip2` the WebAssembly build under wasmtime there, and `wasm32-wasip2-x86_64` the same file on host A; `linux-x86_64-cpu` and `linux-x86_64-gpu-vulkan` host A's CPU and integrated GPU; `linux-x86_64-b-cpu` and `linux-x86_64-b-gpu-vulkan` host B's CPU and discrete GPU. Each line's decodes are the 192 payloads, 24 pictures at 8 qualities.
| platform | decodes | identical to the build host's CPU decode | differ | refused |
|---|---:|---:|---:|---:|
| `linux-x86_64-b-cpu` | 192<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu.refused--> |
| `linux-x86_64-b-gpu-vulkan` | 192<!--det:summary.integer_cross_platform.linux-x86_64-b-gpu-vulkan.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-b-gpu-vulkan.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-b-gpu-vulkan.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-b-gpu-vulkan.refused--> |
| `linux-x86_64-cpu` | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu.refused--> |
| `linux-x86_64-gpu-vulkan` | 192<!--det:summary.integer_cross_platform.linux-x86_64-gpu-vulkan.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-gpu-vulkan.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-gpu-vulkan.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-gpu-vulkan.refused--> |
| `macos-arm64-cpu` | 192<!--det:summary.integer_cross_platform.macos-arm64-cpu.decodes--> | 192<!--det:summary.integer_cross_platform.macos-arm64-cpu.identical--> | 0<!--det:summary.integer_cross_platform.macos-arm64-cpu.differ--> | 0<!--det:summary.integer_cross_platform.macos-arm64-cpu.refused--> |
| `macos-arm64-cpu-1t` | 192<!--det:summary.integer_cross_platform.macos-arm64-cpu-1t.decodes--> | 192<!--det:summary.integer_cross_platform.macos-arm64-cpu-1t.identical--> | 0<!--det:summary.integer_cross_platform.macos-arm64-cpu-1t.differ--> | 0<!--det:summary.integer_cross_platform.macos-arm64-cpu-1t.refused--> |
| `macos-arm64-gpu-metal` | 192<!--det:summary.integer_cross_platform.macos-arm64-gpu-metal.decodes--> | 192<!--det:summary.integer_cross_platform.macos-arm64-gpu-metal.identical--> | 0<!--det:summary.integer_cross_platform.macos-arm64-gpu-metal.differ--> | 0<!--det:summary.integer_cross_platform.macos-arm64-gpu-metal.refused--> |
| `wasm32-wasip2` | 192<!--det:summary.integer_cross_platform.wasm32-wasip2.decodes--> | 192<!--det:summary.integer_cross_platform.wasm32-wasip2.identical--> | 0<!--det:summary.integer_cross_platform.wasm32-wasip2.differ--> | 0<!--det:summary.integer_cross_platform.wasm32-wasip2.refused--> |
| `wasm32-wasip2-x86_64` | 192<!--det:summary.integer_cross_platform.wasm32-wasip2-x86_64.decodes--> | 192<!--det:summary.integer_cross_platform.wasm32-wasip2-x86_64.identical--> | 0<!--det:summary.integer_cross_platform.wasm32-wasip2-x86_64.differ--> | 0<!--det:summary.integer_cross_platform.wasm32-wasip2-x86_64.refused--> |
### 4.4 The float decode across platforms
Against the encoding process's own decode. Tags: `macos-arm64-cpu-1t` and `macos-arm64-cpu` the build host's CPU with one thread and with the library's default of 24, each in a fresh process; `macos-arm64-gpu-mps` its GPU; `linux-x86_64-cpu` and `linux-x86_64-cpu-1t` host A's CPU with the library's default of 16 threads and with one; `linux-x86_64-b-cpu` host B's CPU (14 threads); `linux-x86_64-b-cuda` host B's GPU. Where the symbols differ, the entropy decode diverged.
| platform | decodes | identical to the encoder's decode | differ | of which the indexes differ | of which the symbols differ | ΔPSNR where they differ (dB): median, min, max | ΔPSNR where the symbols differ (dB): median |
|---|---:|---:|---:|---:|---:|---|---:|
| `linux-x86_64-b-cpu` | 192<!--det:summary.float_cross_platform.linux-x86_64-b-cpu.decodes--> | 0<!--det:summary.float_cross_platform.linux-x86_64-b-cpu.identical--> | 192<!--det:summary.float_cross_platform.linux-x86_64-b-cpu.rgb_differ--> | 76<!--det:summary.float_cross_platform.linux-x86_64-b-cpu.indexes_differ--> | 76<!--det:summary.float_cross_platform.linux-x86_64-b-cpu.symbols_differ--> | -0.000<!--det:summary.float_cross_platform.linux-x86_64-b-cpu.delta_psnr_db_where_differ.median-->, -30.126<!--det:summary.float_cross_platform.linux-x86_64-b-cpu.delta_psnr_db_where_differ.min-->, +0.000<!--det:summary.float_cross_platform.linux-x86_64-b-cpu.delta_psnr_db_where_differ.max--> | -17.582<!--det:summary.float_cross_platform.linux-x86_64-b-cpu.delta_psnr_db_where_symbols_differ.median--> |
| `linux-x86_64-b-cuda` | 192<!--det:summary.float_cross_platform.linux-x86_64-b-cuda.decodes--> | 0<!--det:summary.float_cross_platform.linux-x86_64-b-cuda.identical--> | 192<!--det:summary.float_cross_platform.linux-x86_64-b-cuda.rgb_differ--> | 192<!--det:summary.float_cross_platform.linux-x86_64-b-cuda.indexes_differ--> | 192<!--det:summary.float_cross_platform.linux-x86_64-b-cuda.symbols_differ--> | -19.697<!--det:summary.float_cross_platform.linux-x86_64-b-cuda.delta_psnr_db_where_differ.median-->, -30.518<!--det:summary.float_cross_platform.linux-x86_64-b-cuda.delta_psnr_db_where_differ.min-->, -9.500<!--det:summary.float_cross_platform.linux-x86_64-b-cuda.delta_psnr_db_where_differ.max--> | -19.697<!--det:summary.float_cross_platform.linux-x86_64-b-cuda.delta_psnr_db_where_symbols_differ.median--> |
| `linux-x86_64-cpu` | 192<!--det:summary.float_cross_platform.linux-x86_64-cpu.decodes--> | 0<!--det:summary.float_cross_platform.linux-x86_64-cpu.identical--> | 192<!--det:summary.float_cross_platform.linux-x86_64-cpu.rgb_differ--> | 183<!--det:summary.float_cross_platform.linux-x86_64-cpu.indexes_differ--> | 183<!--det:summary.float_cross_platform.linux-x86_64-cpu.symbols_differ--> | -17.037<!--det:summary.float_cross_platform.linux-x86_64-cpu.delta_psnr_db_where_differ.median-->, -30.686<!--det:summary.float_cross_platform.linux-x86_64-cpu.delta_psnr_db_where_differ.min-->, +0.000<!--det:summary.float_cross_platform.linux-x86_64-cpu.delta_psnr_db_where_differ.max--> | -17.434<!--det:summary.float_cross_platform.linux-x86_64-cpu.delta_psnr_db_where_symbols_differ.median--> |
| `linux-x86_64-cpu-1t` | 192<!--det:summary.float_cross_platform.linux-x86_64-cpu-1t.decodes--> | 0<!--det:summary.float_cross_platform.linux-x86_64-cpu-1t.identical--> | 192<!--det:summary.float_cross_platform.linux-x86_64-cpu-1t.rgb_differ--> | 182<!--det:summary.float_cross_platform.linux-x86_64-cpu-1t.indexes_differ--> | 182<!--det:summary.float_cross_platform.linux-x86_64-cpu-1t.symbols_differ--> | -17.037<!--det:summary.float_cross_platform.linux-x86_64-cpu-1t.delta_psnr_db_where_differ.median-->, -30.457<!--det:summary.float_cross_platform.linux-x86_64-cpu-1t.delta_psnr_db_where_differ.min-->, +0.000<!--det:summary.float_cross_platform.linux-x86_64-cpu-1t.delta_psnr_db_where_differ.max--> | -17.345<!--det:summary.float_cross_platform.linux-x86_64-cpu-1t.delta_psnr_db_where_symbols_differ.median--> |
| `macos-arm64-cpu` | 192<!--det:summary.float_cross_platform.macos-arm64-cpu.decodes--> | 192<!--det:summary.float_cross_platform.macos-arm64-cpu.identical--> | 0<!--det:summary.float_cross_platform.macos-arm64-cpu.rgb_differ--> | 0<!--det:summary.float_cross_platform.macos-arm64-cpu.indexes_differ--> | 0<!--det:summary.float_cross_platform.macos-arm64-cpu.symbols_differ--> | — | — |
| `macos-arm64-cpu-1t` | 192<!--det:summary.float_cross_platform.macos-arm64-cpu-1t.decodes--> | 192<!--det:summary.float_cross_platform.macos-arm64-cpu-1t.identical--> | 0<!--det:summary.float_cross_platform.macos-arm64-cpu-1t.rgb_differ--> | 0<!--det:summary.float_cross_platform.macos-arm64-cpu-1t.indexes_differ--> | 0<!--det:summary.float_cross_platform.macos-arm64-cpu-1t.symbols_differ--> | — | — |
| `macos-arm64-gpu-mps` | 192<!--det:summary.float_cross_platform.macos-arm64-gpu-mps.decodes--> | 0<!--det:summary.float_cross_platform.macos-arm64-gpu-mps.identical--> | 192<!--det:summary.float_cross_platform.macos-arm64-gpu-mps.rgb_differ--> | 184<!--det:summary.float_cross_platform.macos-arm64-gpu-mps.indexes_differ--> | 184<!--det:summary.float_cross_platform.macos-arm64-gpu-mps.symbols_differ--> | -17.200<!--det:summary.float_cross_platform.macos-arm64-gpu-mps.delta_psnr_db_where_differ.median-->, -34.147<!--det:summary.float_cross_platform.macos-arm64-gpu-mps.delta_psnr_db_where_differ.min-->, +0.000<!--det:summary.float_cross_platform.macos-arm64-gpu-mps.delta_psnr_db_where_differ.max--> | -17.358<!--det:summary.float_cross_platform.macos-arm64-gpu-mps.delta_psnr_db_where_symbols_differ.median--> |
### 4.5 Time and energy per decode (median over rounds; min–max)
Eight pictures per round, seven rounds; the runs' labels give the host (`linux` is host A, `macos` the build host), the codec, the fabric and the quality. The own CPU energy is the per-task count (macOS); the whole-device figure is the package counter (`rapl`, host A) or the GPU rail (`ioreport-gpu`, the build host), as the round's marginal over its idle brackets, from the rounds used (§2.6). The build host's rounds ran under the load average shown.
| run | time (ms) | own CPU energy (J) | whole-device marginal energy (J) | whole-device rounds | load average |
|---|---|---|---|---|---|
| `linux-float-cpu-q2` | 123.9<!--det:summary.timing.linux-float-cpu-q2.ms_per_decode.median--> (108.2<!--det:summary.timing.linux-float-cpu-q2.ms_per_decode.min-->–134.3<!--det:summary.timing.linux-float-cpu-q2.ms_per_decode.max-->) | — | rapl: 9.1<!--det:summary.timing.linux-float-cpu-q2.rapl.marginal_j_per_decode.median--> (8.0<!--det:summary.timing.linux-float-cpu-q2.rapl.marginal_j_per_decode.min-->–9.5<!--det:summary.timing.linux-float-cpu-q2.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-float-cpu-q2.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-float-cpu-q2.rapl.live_rounds--> live; 7 clean | 2<!--det:summary.timing.linux-float-cpu-q2.load_avg_1min.min-->–3<!--det:summary.timing.linux-float-cpu-q2.load_avg_1min.max--> |
| `linux-float-cpu-q6` | 191.5<!--det:summary.timing.linux-float-cpu-q6.ms_per_decode.median--> (181.0<!--det:summary.timing.linux-float-cpu-q6.ms_per_decode.min-->–200.3<!--det:summary.timing.linux-float-cpu-q6.ms_per_decode.max-->) | — | rapl: 13.7<!--det:summary.timing.linux-float-cpu-q6.rapl.marginal_j_per_decode.median--> (13.3<!--det:summary.timing.linux-float-cpu-q6.rapl.marginal_j_per_decode.min-->–14.0<!--det:summary.timing.linux-float-cpu-q6.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-float-cpu-q6.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-float-cpu-q6.rapl.live_rounds--> live; 7 clean | 5<!--det:summary.timing.linux-float-cpu-q6.load_avg_1min.min-->–7<!--det:summary.timing.linux-float-cpu-q6.load_avg_1min.max--> |
| `linux-int-cpu-q2` | 347.3<!--det:summary.timing.linux-int-cpu-q2.ms_per_decode.median--> (346.4<!--det:summary.timing.linux-int-cpu-q2.ms_per_decode.min-->–348.6<!--det:summary.timing.linux-int-cpu-q2.ms_per_decode.max-->) | — | rapl: 42.4<!--det:summary.timing.linux-int-cpu-q2.rapl.marginal_j_per_decode.median--> (42.1<!--det:summary.timing.linux-int-cpu-q2.rapl.marginal_j_per_decode.min-->–42.5<!--det:summary.timing.linux-int-cpu-q2.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-int-cpu-q2.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-int-cpu-q2.rapl.live_rounds--> live; 7 clean | 1<!--det:summary.timing.linux-int-cpu-q2.load_avg_1min.min-->–4<!--det:summary.timing.linux-int-cpu-q2.load_avg_1min.max--> |
| `linux-int-cpu-q6` | 729.6<!--det:summary.timing.linux-int-cpu-q6.ms_per_decode.median--> (728.7<!--det:summary.timing.linux-int-cpu-q6.ms_per_decode.min-->–731.6<!--det:summary.timing.linux-int-cpu-q6.ms_per_decode.max-->) | — | rapl: 92.5<!--det:summary.timing.linux-int-cpu-q6.rapl.marginal_j_per_decode.median--> (92.2<!--det:summary.timing.linux-int-cpu-q6.rapl.marginal_j_per_decode.min-->–92.7<!--det:summary.timing.linux-int-cpu-q6.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-int-cpu-q6.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-int-cpu-q6.rapl.live_rounds--> live; 7 clean | 3<!--det:summary.timing.linux-int-cpu-q6.load_avg_1min.min-->–11<!--det:summary.timing.linux-int-cpu-q6.load_avg_1min.max--> |
| `linux-int-gpu-q2` | 378.5<!--det:summary.timing.linux-int-gpu-q2.ms_per_decode.median--> (377.2<!--det:summary.timing.linux-int-gpu-q2.ms_per_decode.min-->–379.7<!--det:summary.timing.linux-int-gpu-q2.ms_per_decode.max-->) | — | rapl: 41.9<!--det:summary.timing.linux-int-gpu-q2.rapl.marginal_j_per_decode.median--> (41.0<!--det:summary.timing.linux-int-gpu-q2.rapl.marginal_j_per_decode.min-->–43.4<!--det:summary.timing.linux-int-gpu-q2.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-int-gpu-q2.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-int-gpu-q2.rapl.live_rounds--> live; 7 clean | 1<!--det:summary.timing.linux-int-gpu-q2.load_avg_1min.min-->–3<!--det:summary.timing.linux-int-gpu-q2.load_avg_1min.max--> |
| `linux-int-gpu-q6` | 845.4<!--det:summary.timing.linux-int-gpu-q6.ms_per_decode.median--> (844.1<!--det:summary.timing.linux-int-gpu-q6.ms_per_decode.min-->–846.2<!--det:summary.timing.linux-int-gpu-q6.ms_per_decode.max-->) | — | rapl: 93.5<!--det:summary.timing.linux-int-gpu-q6.rapl.marginal_j_per_decode.median--> (91.7<!--det:summary.timing.linux-int-gpu-q6.rapl.marginal_j_per_decode.min-->–93.8<!--det:summary.timing.linux-int-gpu-q6.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-int-gpu-q6.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-int-gpu-q6.rapl.live_rounds--> live; 7 clean | 1<!--det:summary.timing.linux-int-gpu-q6.load_avg_1min.min-->–5<!--det:summary.timing.linux-int-gpu-q6.load_avg_1min.max--> |
| `macos-float-cpu-q2` | 714.2<!--det:summary.timing.macos-float-cpu-q2.ms_per_decode.median--> (209.0<!--det:summary.timing.macos-float-cpu-q2.ms_per_decode.min-->–5663.9<!--det:summary.timing.macos-float-cpu-q2.ms_per_decode.max-->) | 0.7<!--det:summary.timing.macos-float-cpu-q2.task_j_per_decode.median--> (0.7<!--det:summary.timing.macos-float-cpu-q2.task_j_per_decode.min-->–0.7<!--det:summary.timing.macos-float-cpu-q2.task_j_per_decode.max-->) | — | — | 45<!--det:summary.timing.macos-float-cpu-q2.load_avg_1min.min-->–199<!--det:summary.timing.macos-float-cpu-q2.load_avg_1min.max--> |
| `macos-float-cpu-q6` | 403.4<!--det:summary.timing.macos-float-cpu-q6.ms_per_decode.median--> (214.6<!--det:summary.timing.macos-float-cpu-q6.ms_per_decode.min-->–736.4<!--det:summary.timing.macos-float-cpu-q6.ms_per_decode.max-->) | 1.2<!--det:summary.timing.macos-float-cpu-q6.task_j_per_decode.median--> (1.1<!--det:summary.timing.macos-float-cpu-q6.task_j_per_decode.min-->–1.5<!--det:summary.timing.macos-float-cpu-q6.task_j_per_decode.max-->) | — | — | 85<!--det:summary.timing.macos-float-cpu-q6.load_avg_1min.min-->–126<!--det:summary.timing.macos-float-cpu-q6.load_avg_1min.max--> |
| `macos-float-gpu-q2` | 51.7<!--det:summary.timing.macos-float-gpu-q2.ms_per_decode.median--> (50.0<!--det:summary.timing.macos-float-gpu-q2.ms_per_decode.min-->–55.3<!--det:summary.timing.macos-float-gpu-q2.ms_per_decode.max-->) | 0.1<!--det:summary.timing.macos-float-gpu-q2.task_j_per_decode.median--> (0.1<!--det:summary.timing.macos-float-gpu-q2.task_j_per_decode.min-->–0.1<!--det:summary.timing.macos-float-gpu-q2.task_j_per_decode.max-->) | ioreport-gpu: none usable | 0<!--det:summary.timing.macos-float-gpu-q2.ioreport-gpu.usable_rounds--> of 7 used; 0<!--det:summary.timing.macos-float-gpu-q2.ioreport-gpu.live_rounds--> live; 2 clean, 5 no ratio; GPU share 1.000<!--det:summary.timing.macos-float-gpu-q2.ioreport-gpu.gpu_share.min-->–1.000<!--det:summary.timing.macos-float-gpu-q2.ioreport-gpu.gpu_share.max--> | 126<!--det:summary.timing.macos-float-gpu-q2.load_avg_1min.min-->–149<!--det:summary.timing.macos-float-gpu-q2.load_avg_1min.max--> |
| `macos-float-gpu-q6` | 66.4<!--det:summary.timing.macos-float-gpu-q6.ms_per_decode.median--> (60.0<!--det:summary.timing.macos-float-gpu-q6.ms_per_decode.min-->–77.8<!--det:summary.timing.macos-float-gpu-q6.ms_per_decode.max-->) | 0.2<!--det:summary.timing.macos-float-gpu-q6.task_j_per_decode.median--> (0.1<!--det:summary.timing.macos-float-gpu-q6.task_j_per_decode.min-->–0.2<!--det:summary.timing.macos-float-gpu-q6.task_j_per_decode.max-->) | ioreport-gpu: none usable | 0<!--det:summary.timing.macos-float-gpu-q6.ioreport-gpu.usable_rounds--> of 7 used; 0<!--det:summary.timing.macos-float-gpu-q6.ioreport-gpu.live_rounds--> live; 4 no ratio, 3 clean; GPU share 0.113<!--det:summary.timing.macos-float-gpu-q6.ioreport-gpu.gpu_share.min-->–1.000<!--det:summary.timing.macos-float-gpu-q6.ioreport-gpu.gpu_share.max--> | 74<!--det:summary.timing.macos-float-gpu-q6.load_avg_1min.min-->–81<!--det:summary.timing.macos-float-gpu-q6.load_avg_1min.max--> |
| `macos-int-cpu-q2` | 152.4<!--det:summary.timing.macos-int-cpu-q2.ms_per_decode.median--> (115.1<!--det:summary.timing.macos-int-cpu-q2.ms_per_decode.min-->–376.8<!--det:summary.timing.macos-int-cpu-q2.ms_per_decode.max-->) | 4.6<!--det:summary.timing.macos-int-cpu-q2.task_j_per_decode.median--> (4.4<!--det:summary.timing.macos-int-cpu-q2.task_j_per_decode.min-->–4.8<!--det:summary.timing.macos-int-cpu-q2.task_j_per_decode.max-->) | — | — | 44<!--det:summary.timing.macos-int-cpu-q2.load_avg_1min.min-->–57<!--det:summary.timing.macos-int-cpu-q2.load_avg_1min.max--> |
| `macos-int-cpu-q6` | 648.9<!--det:summary.timing.macos-int-cpu-q6.ms_per_decode.median--> (519.5<!--det:summary.timing.macos-int-cpu-q6.ms_per_decode.min-->–865.7<!--det:summary.timing.macos-int-cpu-q6.ms_per_decode.max-->) | 10.5<!--det:summary.timing.macos-int-cpu-q6.task_j_per_decode.median--> (10.2<!--det:summary.timing.macos-int-cpu-q6.task_j_per_decode.min-->–10.9<!--det:summary.timing.macos-int-cpu-q6.task_j_per_decode.max-->) | — | — | 113<!--det:summary.timing.macos-int-cpu-q6.load_avg_1min.min-->–130<!--det:summary.timing.macos-int-cpu-q6.load_avg_1min.max--> |
| `macos-int-gpu-q2` | 251.3<!--det:summary.timing.macos-int-gpu-q2.ms_per_decode.median--> (248.7<!--det:summary.timing.macos-int-gpu-q2.ms_per_decode.min-->–253.5<!--det:summary.timing.macos-int-gpu-q2.ms_per_decode.max-->) | 0.1<!--det:summary.timing.macos-int-gpu-q2.task_j_per_decode.median--> (0.1<!--det:summary.timing.macos-int-gpu-q2.task_j_per_decode.min-->–0.1<!--det:summary.timing.macos-int-gpu-q2.task_j_per_decode.max-->) | ioreport-gpu: none usable | 0<!--det:summary.timing.macos-int-gpu-q2.ioreport-gpu.usable_rounds--> of 7 used; 5<!--det:summary.timing.macos-int-gpu-q2.ioreport-gpu.live_rounds--> live; 7 clean; GPU share 0.788<!--det:summary.timing.macos-int-gpu-q2.ioreport-gpu.gpu_share.min-->–0.916<!--det:summary.timing.macos-int-gpu-q2.ioreport-gpu.gpu_share.max--> | 117<!--det:summary.timing.macos-int-gpu-q2.load_avg_1min.min-->–128<!--det:summary.timing.macos-int-gpu-q2.load_avg_1min.max--> |
| `macos-int-gpu-q6` | 529.9<!--det:summary.timing.macos-int-gpu-q6.ms_per_decode.median--> (527.9<!--det:summary.timing.macos-int-gpu-q6.ms_per_decode.min-->–546.0<!--det:summary.timing.macos-int-gpu-q6.ms_per_decode.max-->) | 0.1<!--det:summary.timing.macos-int-gpu-q6.task_j_per_decode.median--> (0.1<!--det:summary.timing.macos-int-gpu-q6.task_j_per_decode.min-->–0.1<!--det:summary.timing.macos-int-gpu-q6.task_j_per_decode.max-->) | ioreport-gpu: none usable | 0<!--det:summary.timing.macos-int-gpu-q6.ioreport-gpu.usable_rounds--> of 7 used; 0<!--det:summary.timing.macos-int-gpu-q6.ioreport-gpu.live_rounds--> live; 2 clean, 5 no ratio; GPU share 0.923<!--det:summary.timing.macos-int-gpu-q6.ioreport-gpu.gpu_share.min-->–1.000<!--det:summary.timing.macos-int-gpu-q6.ioreport-gpu.gpu_share.max--> | 37<!--det:summary.timing.macos-int-gpu-q6.load_avg_1min.min-->–68<!--det:summary.timing.macos-int-gpu-q6.load_avg_1min.max--> |
On the build host no GPU-rail figure is used. While the GPU idled between rounds its rail
did not advance at all, so the idle brackets around most rounds were not live (§2.6); and
in some rounds another client held more than 1% of the GPU's time (the table's GPU share). Those rounds' readings are
in the record, and nothing is drawn from them. The per-task counts there are the
decoding process's own CPU energy, which the load on the host changes less than it changes
the time, but does change; §5 states what they cover.
### 4.6 The integer decode on the narrow kernel sets
The record's integer decoder (§4.3, §4.5) ran the wide kernels of `wai-rs`'s `int_kernels`:
32×32→64-bit multiply-accumulates, NEON on arm64 and portable Rust elsewhere. The runs of
this section are of the build that added the narrow kernel sets (`int_kernels::Isa`):
convolutions on 16-bit operands with 32-bit partial sums in blocks bounded so that no value
leaves its type (NEON on arm64; AVX2, AVX2 with VNNI, AVX-512 and AVX-512 with VNNI on
x86_64), the inverse GDN's norms and outputs in SIMD lanes, and the element-wise operators
and the requantisation in 64-bit arithmetic where their values fit. Every operator still
gives the interpreter's integers (the `int_kernels` documentation states how, and the tests
it names hold each set to the interpreter); the set is chosen by the processor's features,
or by `WAI_INT_ISA`. The wasm32-wasip2 build has no narrow set and runs the wide kernels, as
`wide` names below, with the build's other changes.
**Bytes.** Every payload decoded again on each platform with each kernel set the platform
runs, against the record's build host CPU decode (the GPU decodes run both graphs on the
device and are unchanged by the kernel sets; the runs check it):
| platform | kernel set | decodes | identical to the build host's CPU decode | differ | refused |
|---|---|---:|---:|---:|---:|
| `linux-x86_64-b-cpu` | `avx2` | 192<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-avx2.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-avx2.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-avx2.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-avx2.refused--> |
| `linux-x86_64-b-cpu` | `avx2-vnni` | 192<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-avx2-vnni.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-avx2-vnni.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-avx2-vnni.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-avx2-vnni.refused--> |
| `linux-x86_64-b-cpu` | `wide` | 192<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-wide.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-wide.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-wide.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-b-cpu-isa-wide.refused--> |
| `linux-x86_64-cpu` | `avx2` | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx2.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx2.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx2.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx2.refused--> |
| `linux-x86_64-cpu` | `avx2-vnni` | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx2-vnni.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx2-vnni.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx2-vnni.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx2-vnni.refused--> |
| `linux-x86_64-cpu` | `avx512` | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx512.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx512.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx512.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx512.refused--> |
| `linux-x86_64-cpu` | `avx512-vnni` | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx512-vnni.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx512-vnni.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx512-vnni.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-avx512-vnni.refused--> |
| `linux-x86_64-cpu` | `wide` | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-wide.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-wide.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-wide.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-cpu-isa-wide.refused--> |
| `linux-x86_64-gpu-vulkan` | `avx512-vnni` | 192<!--det:summary.integer_cross_platform.linux-x86_64-gpu-vulkan-isa-avx512-vnni.decodes--> | 192<!--det:summary.integer_cross_platform.linux-x86_64-gpu-vulkan-isa-avx512-vnni.identical--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-gpu-vulkan-isa-avx512-vnni.differ--> | 0<!--det:summary.integer_cross_platform.linux-x86_64-gpu-vulkan-isa-avx512-vnni.refused--> |
| `macos-arm64-cpu-1t` | `neon` | 192<!--det:summary.integer_cross_platform.macos-arm64-cpu-1t-isa-neon.decodes--> | 192<!--det:summary.integer_cross_platform.macos-arm64-cpu-1t-isa-neon.identical--> | 0<!--det:summary.integer_cross_platform.macos-arm64-cpu-1t-isa-neon.differ--> | 0<!--det:summary.integer_cross_platform.macos-arm64-cpu-1t-isa-neon.refused--> |
| `macos-arm64-cpu` | `neon` | 192<!--det:summary.integer_cross_platform.macos-arm64-cpu-isa-neon.decodes--> | 192<!--det:summary.integer_cross_platform.macos-arm64-cpu-isa-neon.identical--> | 0<!--det:summary.integer_cross_platform.macos-arm64-cpu-isa-neon.differ--> | 0<!--det:summary.integer_cross_platform.macos-arm64-cpu-isa-neon.refused--> |
| `macos-arm64-cpu` | `wide` | 192<!--det:summary.integer_cross_platform.macos-arm64-cpu-isa-wide.decodes--> | 192<!--det:summary.integer_cross_platform.macos-arm64-cpu-isa-wide.identical--> | 0<!--det:summary.integer_cross_platform.macos-arm64-cpu-isa-wide.differ--> | 0<!--det:summary.integer_cross_platform.macos-arm64-cpu-isa-wide.refused--> |
| `macos-arm64-gpu-metal` | `neon` | 192<!--det:summary.integer_cross_platform.macos-arm64-gpu-metal-isa-neon.decodes--> | 192<!--det:summary.integer_cross_platform.macos-arm64-gpu-metal-isa-neon.identical--> | 0<!--det:summary.integer_cross_platform.macos-arm64-gpu-metal-isa-neon.differ--> | 0<!--det:summary.integer_cross_platform.macos-arm64-gpu-metal-isa-neon.refused--> |
| `wasm32-wasip2` | `wide` | 192<!--det:summary.integer_cross_platform.wasm32-wasip2-isa-wide.decodes--> | 192<!--det:summary.integer_cross_platform.wasm32-wasip2-isa-wide.identical--> | 0<!--det:summary.integer_cross_platform.wasm32-wasip2-isa-wide.differ--> | 0<!--det:summary.integer_cross_platform.wasm32-wasip2-isa-wide.refused--> |
| `wasm32-wasip2-x86_64` | `wide` | 192<!--det:summary.integer_cross_platform.wasm32-wasip2-x86_64-isa-wide.decodes--> | 192<!--det:summary.integer_cross_platform.wasm32-wasip2-x86_64-isa-wide.identical--> | 0<!--det:summary.integer_cross_platform.wasm32-wasip2-x86_64-isa-wide.differ--> | 0<!--det:summary.integer_cross_platform.wasm32-wasip2-x86_64-isa-wide.refused--> |
**Time and energy.** The procedure of §2.6, on the same eight pictures. On each host the
runs were taken in one session: `-before` the record's own build of the integer decoder run
again, `-after` this section's build (its kernel set chosen by the processor: AVX-512 with
VNNI on host A, AVX2 with VNNI on host B, NEON on the build host; `-after-avx2` the AVX2 set
on host A), `-again` the float decoder run again. `linux-b` is host B, measured only for the
integer decode (its float stack was not set up again), under the load of the CI jobs it
also serves.
| run | time (ms) | own CPU energy (J) | whole-device marginal energy (J) | whole-device rounds | load average |
|---|---|---|---|---|---|
| `linux-b-int-cpu-q2-after` | 170.2<!--det:summary.timing.linux-b-int-cpu-q2-after.ms_per_decode.median--> (168.9<!--det:summary.timing.linux-b-int-cpu-q2-after.ms_per_decode.min-->–203.6<!--det:summary.timing.linux-b-int-cpu-q2-after.ms_per_decode.max-->) | — | rapl: 11.56<!--det:summary.timing.linux-b-int-cpu-q2-after.rapl.marginal_j_per_decode.median--> (9.31<!--det:summary.timing.linux-b-int-cpu-q2-after.rapl.marginal_j_per_decode.min-->–11.91<!--det:summary.timing.linux-b-int-cpu-q2-after.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-b-int-cpu-q2-after.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-b-int-cpu-q2-after.rapl.live_rounds--> live; 2 relative-only, 5 clean | 5<!--det:summary.timing.linux-b-int-cpu-q2-after.load_avg_1min.min-->–6<!--det:summary.timing.linux-b-int-cpu-q2-after.load_avg_1min.max--> |
| `linux-b-int-cpu-q2-before` | 714.0<!--det:summary.timing.linux-b-int-cpu-q2-before.ms_per_decode.median--> (704.2<!--det:summary.timing.linux-b-int-cpu-q2-before.ms_per_decode.min-->–716.3<!--det:summary.timing.linux-b-int-cpu-q2-before.ms_per_decode.max-->) | — | rapl: 43.84<!--det:summary.timing.linux-b-int-cpu-q2-before.rapl.marginal_j_per_decode.median--> (42.71<!--det:summary.timing.linux-b-int-cpu-q2-before.rapl.marginal_j_per_decode.min-->–44.30<!--det:summary.timing.linux-b-int-cpu-q2-before.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-b-int-cpu-q2-before.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-b-int-cpu-q2-before.rapl.live_rounds--> live; 7 clean | 2<!--det:summary.timing.linux-b-int-cpu-q2-before.load_avg_1min.min-->–9<!--det:summary.timing.linux-b-int-cpu-q2-before.load_avg_1min.max--> |
| `linux-b-int-cpu-q6-after` | 294.3<!--det:summary.timing.linux-b-int-cpu-q6-after.ms_per_decode.median--> (292.3<!--det:summary.timing.linux-b-int-cpu-q6-after.ms_per_decode.min-->–301.1<!--det:summary.timing.linux-b-int-cpu-q6-after.ms_per_decode.max-->) | — | rapl: 19.97<!--det:summary.timing.linux-b-int-cpu-q6-after.rapl.marginal_j_per_decode.median--> (18.83<!--det:summary.timing.linux-b-int-cpu-q6-after.rapl.marginal_j_per_decode.min-->–20.20<!--det:summary.timing.linux-b-int-cpu-q6-after.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-b-int-cpu-q6-after.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-b-int-cpu-q6-after.rapl.live_rounds--> live; 7 clean | 6<!--det:summary.timing.linux-b-int-cpu-q6-after.load_avg_1min.min-->–11<!--det:summary.timing.linux-b-int-cpu-q6-after.load_avg_1min.max--> |
| `linux-b-int-cpu-q6-before` | 1582.1<!--det:summary.timing.linux-b-int-cpu-q6-before.ms_per_decode.median--> (1555.6<!--det:summary.timing.linux-b-int-cpu-q6-before.ms_per_decode.min-->–1598.9<!--det:summary.timing.linux-b-int-cpu-q6-before.ms_per_decode.max-->) | — | rapl: 84.92<!--det:summary.timing.linux-b-int-cpu-q6-before.rapl.marginal_j_per_decode.median--> (83.95<!--det:summary.timing.linux-b-int-cpu-q6-before.rapl.marginal_j_per_decode.min-->–87.95<!--det:summary.timing.linux-b-int-cpu-q6-before.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-b-int-cpu-q6-before.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-b-int-cpu-q6-before.rapl.live_rounds--> live; 7 clean | 6<!--det:summary.timing.linux-b-int-cpu-q6-before.load_avg_1min.min-->–12<!--det:summary.timing.linux-b-int-cpu-q6-before.load_avg_1min.max--> |
| `linux-float-cpu-q2-again` | 132.2<!--det:summary.timing.linux-float-cpu-q2-again.ms_per_decode.median--> (123.2<!--det:summary.timing.linux-float-cpu-q2-again.ms_per_decode.min-->–139.7<!--det:summary.timing.linux-float-cpu-q2-again.ms_per_decode.max-->) | — | rapl: 9.26<!--det:summary.timing.linux-float-cpu-q2-again.rapl.marginal_j_per_decode.median--> (9.00<!--det:summary.timing.linux-float-cpu-q2-again.rapl.marginal_j_per_decode.min-->–9.33<!--det:summary.timing.linux-float-cpu-q2-again.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-float-cpu-q2-again.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-float-cpu-q2-again.rapl.live_rounds--> live; 7 clean | 2<!--det:summary.timing.linux-float-cpu-q2-again.load_avg_1min.min-->–4<!--det:summary.timing.linux-float-cpu-q2-again.load_avg_1min.max--> |
| `linux-float-cpu-q6-again` | 210.7<!--det:summary.timing.linux-float-cpu-q6-again.ms_per_decode.median--> (200.8<!--det:summary.timing.linux-float-cpu-q6-again.ms_per_decode.min-->–226.1<!--det:summary.timing.linux-float-cpu-q6-again.ms_per_decode.max-->) | — | rapl: 14.03<!--det:summary.timing.linux-float-cpu-q6-again.rapl.marginal_j_per_decode.median--> (13.65<!--det:summary.timing.linux-float-cpu-q6-again.rapl.marginal_j_per_decode.min-->–14.41<!--det:summary.timing.linux-float-cpu-q6-again.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-float-cpu-q6-again.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-float-cpu-q6-again.rapl.live_rounds--> live; 7 clean | 6<!--det:summary.timing.linux-float-cpu-q6-again.load_avg_1min.min-->–8<!--det:summary.timing.linux-float-cpu-q6-again.load_avg_1min.max--> |
| `linux-int-cpu-q2-after` | 92.9<!--det:summary.timing.linux-int-cpu-q2-after.ms_per_decode.median--> (90.8<!--det:summary.timing.linux-int-cpu-q2-after.ms_per_decode.min-->–93.1<!--det:summary.timing.linux-int-cpu-q2-after.ms_per_decode.max-->) | — | rapl: 7.31<!--det:summary.timing.linux-int-cpu-q2-after.rapl.marginal_j_per_decode.median--> (7.29<!--det:summary.timing.linux-int-cpu-q2-after.rapl.marginal_j_per_decode.min-->–7.50<!--det:summary.timing.linux-int-cpu-q2-after.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-int-cpu-q2-after.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-int-cpu-q2-after.rapl.live_rounds--> live; 7 clean | 3<!--det:summary.timing.linux-int-cpu-q2-after.load_avg_1min.min-->–5<!--det:summary.timing.linux-int-cpu-q2-after.load_avg_1min.max--> |
| `linux-int-cpu-q2-after-avx2` | 101.6<!--det:summary.timing.linux-int-cpu-q2-after-avx2.ms_per_decode.median--> (101.3<!--det:summary.timing.linux-int-cpu-q2-after-avx2.ms_per_decode.min-->–103.0<!--det:summary.timing.linux-int-cpu-q2-after-avx2.ms_per_decode.max-->) | — | rapl: 9.27<!--det:summary.timing.linux-int-cpu-q2-after-avx2.rapl.marginal_j_per_decode.median--> (9.22<!--det:summary.timing.linux-int-cpu-q2-after-avx2.rapl.marginal_j_per_decode.min-->–9.35<!--det:summary.timing.linux-int-cpu-q2-after-avx2.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-int-cpu-q2-after-avx2.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-int-cpu-q2-after-avx2.rapl.live_rounds--> live; 7 clean | 3<!--det:summary.timing.linux-int-cpu-q2-after-avx2.load_avg_1min.min-->–5<!--det:summary.timing.linux-int-cpu-q2-after-avx2.load_avg_1min.max--> |
| `linux-int-cpu-q2-before` | 345.8<!--det:summary.timing.linux-int-cpu-q2-before.ms_per_decode.median--> (345.2<!--det:summary.timing.linux-int-cpu-q2-before.ms_per_decode.min-->–346.4<!--det:summary.timing.linux-int-cpu-q2-before.ms_per_decode.max-->) | — | rapl: 42.25<!--det:summary.timing.linux-int-cpu-q2-before.rapl.marginal_j_per_decode.median--> (42.17<!--det:summary.timing.linux-int-cpu-q2-before.rapl.marginal_j_per_decode.min-->–42.33<!--det:summary.timing.linux-int-cpu-q2-before.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-int-cpu-q2-before.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-int-cpu-q2-before.rapl.live_rounds--> live; 7 clean | 2<!--det:summary.timing.linux-int-cpu-q2-before.load_avg_1min.min-->–5<!--det:summary.timing.linux-int-cpu-q2-before.load_avg_1min.max--> |
| `linux-int-cpu-q6-after` | 144.8<!--det:summary.timing.linux-int-cpu-q6-after.ms_per_decode.median--> (142.7<!--det:summary.timing.linux-int-cpu-q6-after.ms_per_decode.min-->–147.7<!--det:summary.timing.linux-int-cpu-q6-after.ms_per_decode.max-->) | — | rapl: 12.43<!--det:summary.timing.linux-int-cpu-q6-after.rapl.marginal_j_per_decode.median--> (12.28<!--det:summary.timing.linux-int-cpu-q6-after.rapl.marginal_j_per_decode.min-->–12.58<!--det:summary.timing.linux-int-cpu-q6-after.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-int-cpu-q6-after.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-int-cpu-q6-after.rapl.live_rounds--> live; 7 clean | 8<!--det:summary.timing.linux-int-cpu-q6-after.load_avg_1min.min-->–11<!--det:summary.timing.linux-int-cpu-q6-after.load_avg_1min.max--> |
| `linux-int-cpu-q6-after-avx2` | 166.3<!--det:summary.timing.linux-int-cpu-q6-after-avx2.ms_per_decode.median--> (164.7<!--det:summary.timing.linux-int-cpu-q6-after-avx2.ms_per_decode.min-->–166.8<!--det:summary.timing.linux-int-cpu-q6-after-avx2.ms_per_decode.max-->) | — | rapl: 16.46<!--det:summary.timing.linux-int-cpu-q6-after-avx2.rapl.marginal_j_per_decode.median--> (16.36<!--det:summary.timing.linux-int-cpu-q6-after-avx2.rapl.marginal_j_per_decode.min-->–16.53<!--det:summary.timing.linux-int-cpu-q6-after-avx2.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-int-cpu-q6-after-avx2.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-int-cpu-q6-after-avx2.rapl.live_rounds--> live; 7 clean | 2<!--det:summary.timing.linux-int-cpu-q6-after-avx2.load_avg_1min.min-->–4<!--det:summary.timing.linux-int-cpu-q6-after-avx2.load_avg_1min.max--> |
| `linux-int-cpu-q6-before` | 728.0<!--det:summary.timing.linux-int-cpu-q6-before.ms_per_decode.median--> (725.8<!--det:summary.timing.linux-int-cpu-q6-before.ms_per_decode.min-->–729.8<!--det:summary.timing.linux-int-cpu-q6-before.ms_per_decode.max-->) | — | rapl: 92.14<!--det:summary.timing.linux-int-cpu-q6-before.rapl.marginal_j_per_decode.median--> (91.96<!--det:summary.timing.linux-int-cpu-q6-before.rapl.marginal_j_per_decode.min-->–92.67<!--det:summary.timing.linux-int-cpu-q6-before.rapl.marginal_j_per_decode.max-->) | 7<!--det:summary.timing.linux-int-cpu-q6-before.rapl.usable_rounds--> of 7 used; 7<!--det:summary.timing.linux-int-cpu-q6-before.rapl.live_rounds--> live; 7 clean | 4<!--det:summary.timing.linux-int-cpu-q6-before.load_avg_1min.min-->–12<!--det:summary.timing.linux-int-cpu-q6-before.load_avg_1min.max--> |
| `macos-float-cpu-q2-again` | 212.5<!--det:summary.timing.macos-float-cpu-q2-again.ms_per_decode.median--> (140.4<!--det:summary.timing.macos-float-cpu-q2-again.ms_per_decode.min-->–330.5<!--det:summary.timing.macos-float-cpu-q2-again.ms_per_decode.max-->) | 0.92<!--det:summary.timing.macos-float-cpu-q2-again.task_j_per_decode.median--> (0.81<!--det:summary.timing.macos-float-cpu-q2-again.task_j_per_decode.min-->–1.07<!--det:summary.timing.macos-float-cpu-q2-again.task_j_per_decode.max-->) | — | — | 40<!--det:summary.timing.macos-float-cpu-q2-again.load_avg_1min.min-->–47<!--det:summary.timing.macos-float-cpu-q2-again.load_avg_1min.max--> |
| `macos-float-cpu-q6-again` | 271.3<!--det:summary.timing.macos-float-cpu-q6-again.ms_per_decode.median--> (215.7<!--det:summary.timing.macos-float-cpu-q6-again.ms_per_decode.min-->–598.7<!--det:summary.timing.macos-float-cpu-q6-again.ms_per_decode.max-->) | 1.28<!--det:summary.timing.macos-float-cpu-q6-again.task_j_per_decode.median--> (1.22<!--det:summary.timing.macos-float-cpu-q6-again.task_j_per_decode.min-->–1.51<!--det:summary.timing.macos-float-cpu-q6-again.task_j_per_decode.max-->) | — | — | 46<!--det:summary.timing.macos-float-cpu-q6-again.load_avg_1min.min-->–61<!--det:summary.timing.macos-float-cpu-q6-again.load_avg_1min.max--> |
| `macos-int-cpu-q2-after` | 274.1<!--det:summary.timing.macos-int-cpu-q2-after.ms_per_decode.median--> (98.3<!--det:summary.timing.macos-int-cpu-q2-after.ms_per_decode.min-->–385.0<!--det:summary.timing.macos-int-cpu-q2-after.ms_per_decode.max-->) | 2.96<!--det:summary.timing.macos-int-cpu-q2-after.task_j_per_decode.median--> (2.83<!--det:summary.timing.macos-int-cpu-q2-after.task_j_per_decode.min-->–3.12<!--det:summary.timing.macos-int-cpu-q2-after.task_j_per_decode.max-->) | — | — | 32<!--det:summary.timing.macos-int-cpu-q2-after.load_avg_1min.min-->–46<!--det:summary.timing.macos-int-cpu-q2-after.load_avg_1min.max--> |
| `macos-int-cpu-q2-before` | 130.9<!--det:summary.timing.macos-int-cpu-q2-before.ms_per_decode.median--> (106.2<!--det:summary.timing.macos-int-cpu-q2-before.ms_per_decode.min-->–338.3<!--det:summary.timing.macos-int-cpu-q2-before.ms_per_decode.max-->) | 4.76<!--det:summary.timing.macos-int-cpu-q2-before.task_j_per_decode.median--> (4.47<!--det:summary.timing.macos-int-cpu-q2-before.task_j_per_decode.min-->–4.90<!--det:summary.timing.macos-int-cpu-q2-before.task_j_per_decode.max-->) | — | — | 34<!--det:summary.timing.macos-int-cpu-q2-before.load_avg_1min.min-->–42<!--det:summary.timing.macos-int-cpu-q2-before.load_avg_1min.max--> |
| `macos-int-cpu-q6-after` | 477.5<!--det:summary.timing.macos-int-cpu-q6-after.ms_per_decode.median--> (392.1<!--det:summary.timing.macos-int-cpu-q6-after.ms_per_decode.min-->–909.3<!--det:summary.timing.macos-int-cpu-q6-after.ms_per_decode.max-->) | 6.43<!--det:summary.timing.macos-int-cpu-q6-after.task_j_per_decode.median--> (6.12<!--det:summary.timing.macos-int-cpu-q6-after.task_j_per_decode.min-->–6.63<!--det:summary.timing.macos-int-cpu-q6-after.task_j_per_decode.max-->) | — | — | 32<!--det:summary.timing.macos-int-cpu-q6-after.load_avg_1min.min-->–62<!--det:summary.timing.macos-int-cpu-q6-after.load_avg_1min.max--> |
| `macos-int-cpu-q6-before` | 268.1<!--det:summary.timing.macos-int-cpu-q6-before.ms_per_decode.median--> (228.4<!--det:summary.timing.macos-int-cpu-q6-before.ms_per_decode.min-->–409.0<!--det:summary.timing.macos-int-cpu-q6-before.ms_per_decode.max-->) | 11.01<!--det:summary.timing.macos-int-cpu-q6-before.task_j_per_decode.median--> (10.93<!--det:summary.timing.macos-int-cpu-q6-before.task_j_per_decode.min-->–11.16<!--det:summary.timing.macos-int-cpu-q6-before.task_j_per_decode.max-->) | — | — | 33<!--det:summary.timing.macos-int-cpu-q6-before.load_avg_1min.min-->–47<!--det:summary.timing.macos-int-cpu-q6-before.load_avg_1min.max--> |
On host A every round of every run read clean. At quality 6 the narrow kernels took the
integer decode from 728.0<!--det:summary.timing.linux-int-cpu-q6-before.ms_per_decode.median--> ms and
92.14<!--det:summary.timing.linux-int-cpu-q6-before.rapl.marginal_j_per_decode.median--> J to
144.8<!--det:summary.timing.linux-int-cpu-q6-after.ms_per_decode.median--> ms and
12.43<!--det:summary.timing.linux-int-cpu-q6-after.rapl.marginal_j_per_decode.median--> J, against
210.7<!--det:summary.timing.linux-float-cpu-q6-again.ms_per_decode.median--> ms and
14.03<!--det:summary.timing.linux-float-cpu-q6-again.rapl.marginal_j_per_decode.median--> J for the float decode;
at quality 2 from 345.8<!--det:summary.timing.linux-int-cpu-q2-before.ms_per_decode.median--> ms and
42.25<!--det:summary.timing.linux-int-cpu-q2-before.rapl.marginal_j_per_decode.median--> J to
92.9<!--det:summary.timing.linux-int-cpu-q2-after.ms_per_decode.median--> ms and
7.31<!--det:summary.timing.linux-int-cpu-q2-after.rapl.marginal_j_per_decode.median--> J, against
132.2<!--det:summary.timing.linux-float-cpu-q2-again.ms_per_decode.median--> ms and
9.26<!--det:summary.timing.linux-float-cpu-q2-again.rapl.marginal_j_per_decode.median--> J. With the AVX2 set
on the same host the integer decode drew
9.27<!--det:summary.timing.linux-int-cpu-q2-after-avx2.rapl.marginal_j_per_decode.median--> J at quality 2 and
16.46<!--det:summary.timing.linux-int-cpu-q6-after-avx2.rapl.marginal_j_per_decode.median--> J at quality 6.
The record's own runs of 2026-10-22 (§4.5) and the `-before` runs agree within a few
tenths of a joule.
On host B, under the load of the CI jobs it serves, the integer decode went from
1582.1<!--det:summary.timing.linux-b-int-cpu-q6-before.ms_per_decode.median--> ms and
84.92<!--det:summary.timing.linux-b-int-cpu-q6-before.rapl.marginal_j_per_decode.median--> J to
294.3<!--det:summary.timing.linux-b-int-cpu-q6-after.ms_per_decode.median--> ms and
19.97<!--det:summary.timing.linux-b-int-cpu-q6-after.rapl.marginal_j_per_decode.median--> J at quality 6, and
from 714.0<!--det:summary.timing.linux-b-int-cpu-q2-before.ms_per_decode.median--> ms and
43.84<!--det:summary.timing.linux-b-int-cpu-q2-before.rapl.marginal_j_per_decode.median--> J to
170.2<!--det:summary.timing.linux-b-int-cpu-q2-after.ms_per_decode.median--> ms and
11.56<!--det:summary.timing.linux-b-int-cpu-q2-after.rapl.marginal_j_per_decode.median--> J at quality 2, where
two of the seven rounds were relative-only against their idle brackets and the rest clean. No float decode was measured
beside them there.
On the build host the narrow kernels lowered the decoder's own CPU energy from
11.01<!--det:summary.timing.macos-int-cpu-q6-before.task_j_per_decode.median--> J to
6.43<!--det:summary.timing.macos-int-cpu-q6-after.task_j_per_decode.median--> J at quality 6 and from
4.76<!--det:summary.timing.macos-int-cpu-q2-before.task_j_per_decode.median--> J to
2.96<!--det:summary.timing.macos-int-cpu-q2-after.task_j_per_decode.median--> J at quality 2. The float decode's
own CPU energy there was 1.28<!--det:summary.timing.macos-float-cpu-q6-again.task_j_per_decode.median--> J and
0.92<!--det:summary.timing.macos-float-cpu-q2-again.task_j_per_decode.median--> J: by that count the integer
decode still costs more on this host, and the count may leave out the float decode's matrix
unit (§5). The host was under heavy load from other work throughout (the load averages in
the table). Its times swing with that load from round to round and from run to run by more
than the kernels change them, so that a run's median time there says little: the `-after`
runs' medians lie above the `-before` runs' though their ranges overlap, while each run's
per-task counts stay within a few tenths of a joule of each other. The per-task count is the
build host's comparable figure.
## 5. What this does and does not show
- **One model, one export.** The integer codec is a post-training quantisation of one
model family with one recipe: per-channel 12-bit weights, activations at 2¹², no
retraining. Another model, a wider export or quantisation-aware training costs
something else, and this record does not say what.
- **One set of pictures.** 24 pictures of one source set at 768×512, whole. Rate and
quality are picture-dependent, so the record keeps every picture's figure.
- **What the BD-rate includes.** The integer codec's rate is its own: its hyper-decoder
decides the tables in integers, so its streams differ from the float codec's even before
its synthesis runs. The BD-rate is the cost of the whole integer codec at equal quality,
rate and distortion together.
- **Reproducibility.** An integer decode that gave the same bytes on every platform
reached is evidence of the construction on those platforms. It is not the ground of the
tier's claim (determinism-tiers §7). A float decode that reproduced on a platform here
says nothing of another platform, another build of the library or another device.
- **Time and energy.** Both hosts are shared, and the build host was under heavy load
from other work throughout; the record keeps the load average of every round. The
per-task count is the decoder's own CPU energy and nothing else; the GPU rail and the
package counter cover their whole device, and a figure from them is the round's marginal
over its idle brackets. The record's integer decoder is CPU code with the wide kernels of
`int_kernels` (NEON on arm64, portable Rust elsewhere), §4.6's with the narrow kernel sets
(NEON on arm64, AVX2 and AVX-512 on x86_64), and its GPU decode runs the graphs the
device takes through `wai-ops-gpu`; the float decode runs the library's own kernels. The
figures compare those implementations on those hosts, not integer and float arithmetic in
general.
- **What the per-task count covers on the build host.** It is the kernel's account of the
process's CPU energy. The float library's CPU kernels on that host may hand matrix work to
a matrix unit the CPU clusters share, and this record does not establish whether the
per-task count includes that unit's energy; so on the build host, the float codec's CPU
figure may be lower than the energy its decode caused. Host A's package counter has no
such gap for the CPU: it covers the whole package, the decode's share of it being the
marginal over the idle brackets. Whether it also covers the package's integrated GPU, the
interface does not state, so host A's figure for the integer decode with its graphs on that
GPU is the package's marginal and nothing more.
- **The encoder** is float in both codecs and is not measured.
## 6. Reproduce
```sh
W=/some/work/dir; T=wai/tools
python3 $T/wai_determinism_cost.py select $W <reference-root> # 24 pictures, checked
python3 $T/wai_determinism_cost.py export $W # 8 pinned checkpoints -> integer sets
python3 $T/wai_determinism_cost.py encode $W # both codecs; float decode in-process
python3 $T/wai_determinism_cost.py jobs $W native > jobs.tsv
wai_det_cost decode jobs.tsv > $W/int.native.tsv # the integer decodes (wai-rs bin)
python3 $T/wai_determinism_cost.py metrics $W
# per platform: wai_det_cost [--gpu] decode <jobs> > $W/xplat/<tag>.tsv (+ <tag>.json, the platform)
# wai_determinism_cost.py fdecode $W <tag> --device cpu|mps [--threads 1]
# per run: wai_det_energy.py --label L --counter task|ioreport-gpu|rapl -- <child> > $W/energy/L.json
python3 $T/wai_determinism_cost.py record $W wai/research/determinism-cost/record.json
python3 -I $T/wai_determinism_cost_verify.py wai/research/determinism-cost/record.json \
wai/research/determinism-cost.md wai/extensions/determinism-tiers.md
```
The scripts that ran each step on each host are in [`determinism-cost/runs/`](determinism-cost/runs/README.md).