All checks were successful
joule-moq-remote host agent / joule-moq-remote · does this change touch it (pull_request) Successful in 6s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 7s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 6s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 6s
wai-app and Create / wai-app · does this change touch it (pull_request) Successful in 6s
wai-audit collector and player integration / does this change touch it (pull_request) Successful in 6s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (pull_request) Successful in 6s
WAI operation catalogue / does this change touch it (pull_request) Successful in 6s
WAI conformance / does this change touch it (pull_request) Successful in 6s
WAI energy receipts / does this change touch it (pull_request) Successful in 5s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 6s
wai-fleet service / does this change touch it (pull_request) Successful in 6s
WAI JPEG-AI whole decode (pinned inputs, required) / does this change touch it (pull_request) Successful in 7s
wai-ledger service / does this change touch it (pull_request) Successful in 6s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (pull_request) Successful in 1m25s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 6s
wai-quantum for JavaScript / does this change touch it (pull_request) Successful in 6s
wai-quantum studio and desktop / does this change touch it (pull_request) Successful in 6s
wai-sink-android native sink library / does this change touch it (pull_request) Successful in 6s
wai-sink-swift native sink package / does this change touch it (pull_request) Successful in 6s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (pull_request) Successful in 1m57s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 2m7s
WAI Studio / does this change touch it (pull_request) Successful in 6s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 6s
wai-web wasm32 / does this change touch it (pull_request) Successful in 6s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (pull_request) Successful in 29s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (pull_request) Successful in 2m1s
WAI conformance / fast integer kernels, every x86_64 kernel set (AVX-512 silicon) (pull_request) Successful in 2m59s
wai-audit collector and player integration / collector · linux (pull_request) Successful in 1m1s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 26s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 4m19s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 16s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 1m4s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (pull_request) Successful in 1m15s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (pull_request) Successful in 5m15s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 6m19s
wai-fleet service / service · macos (pull_request) Successful in 1m2s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (pull_request) Successful in 2m46s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 1m43s
wai-ledger service / service · macos (pull_request) Successful in 1m24s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 1m2s
WAI operation catalogue / the catalogue and every door · linux (pull_request) Successful in 4m18s
wai-quantum studio and desktop / desktop app · windows (pull_request) Successful in 9m19s
wai-pack / wai-pack · macos (pull_request) Successful in 3m8s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 30s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 7m49s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 3m23s
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (pull_request) Successful in 1m39s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 3m9s
wai-fleet service / service · linux (pull_request) Successful in 2m5s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 3m28s
wai-ledger service / service · linux (pull_request) Successful in 1m43s
wai-pack / wai-pack · linux (pull_request) Successful in 1m55s
wai-quantum for JavaScript / javascript · linux (pull_request) Successful in 3m0s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (pull_request) Successful in 1m10s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 16m12s
WAI conformance / each feature of the independent verifiers' steps compiles alone (pull_request) Successful in 11m32s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (pull_request) Successful in 4m51s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 13m12s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 15m2s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 4m3s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 16m34s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m40s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 17m22s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m44s
wai-quantum studio and desktop / desktop app · linux (pull_request) Successful in 5m46s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 34s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 17s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 9m28s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 5m7s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 14m49s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m34s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (pull_request) Successful in 2m16s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 11m4s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 13m6s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 5m58s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (pull_request) Successful in 10m55s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 9m51s
WAI Studio / Studio in WebKit · linux (pull_request) Successful in 10m15s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 9m21s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 30m14s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 1h4m7s
Every change to WAI added an entry at the head of wai/CHANGELOG.md, and every new module appended to the hand-kept lists of .github/workflows/wai-conformance.yml. So any two branches conflicted on those lines and had to merge one after another. This moves both into files a change adds. - Changelog entries: a change adds wai/changes/<yyyy-mm-dd>-<slug>.md holding the entry text. scripts/changelog-assemble.py renders the entries into CHANGELOG.md's Unreleased section for a release, in a stable order. scripts/check-changelog-fragment.py, run by repo-checks on every pull request, fails a pull request that changes wai/ and adds or edits no entry file directly in wai/changes/ (a release passes, and so does a commit with the trailer line "Changelog: none"). A pull request opened before the check reached main passes as it is; one opened after it that adds its entry to the head of Unreleased fails and is told where the entry goes. wai breaking reads breaking changes from entry files too. - The conformance workflow: each per-module verifier step is a file in .github/wai-conformance/verifiers/, each corpus a file in corpora/, and the integer-kernel tests carry a tag line. scripts/wai-conformance-lists.py derives every list the workflow kept by hand (WAI_FEATURES, the union --bin and --test lists, the features-alone lists, the kernel and corpus steps) from those files when the workflow runs. Its `selftest --exact` holds the derived lists to the hand lists of the commit before this one, and its dry-run prints every command each job runs: the dry-runs before and after this change differ only in the gate's path list, which gains the two paths this change adds. - What stays shared, and how to insert there, is written in wai/CONTRIBUTING.md and wai/changes/README.md: wai-rs Cargo.toml features and [[test]] entries, lib.rs, registry rows, wai/.gitattributes and the live corpus table take an insert beside the related entry, never at the end. Co-Authored-By: Claude Opus 5.5 <[email protected]>
132 lines
6.3 KiB
Rust
132 lines
6.3 KiB
Rust
// wai-conformance: int-kernels
|
||
//! What the integer video encoder holds (`int_video_enc::working_bytes`) against what it
|
||
//! holds in fact, measured with a global allocator that tracks the bytes live and their
|
||
//! peak, as `tests/int_payload_cost.rs` measures the decoder.
|
||
//!
|
||
//! The encoder codes in two passes and keeps no residual or symbol per sample, so beyond
|
||
//! the frames it is given it holds the reconstruction it returns, the motion vectors and
|
||
//! the stream (as emitted, finished and copied into the payload): a small multiple of
|
||
//! the clip at worst, about one clip for content that codes well. The clips: noise at
|
||
//! step 1 (a wide residual table, a long stream), a smooth pan, block 1 (a vector for
|
||
//! every pixel), one frame; tiny clips whose residual table is wide, where the table's
|
||
//! fit is most of what is held (1 × 3 noise, 2 frames; 2 × 5, 4 frames, block 5); and a
|
||
//! seeded sweep of small random clips over every block, precision, search and step.
|
||
//!
|
||
//! Its own test binary with a single test, so that no other test's allocations land in
|
||
//! the window it measures.
|
||
#![cfg(feature = "video_int")]
|
||
|
||
use std::alloc::{GlobalAlloc, Layout, System};
|
||
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
|
||
|
||
use wai::int_video_enc::{encode, working_bytes, EncParams};
|
||
|
||
/// The system allocator, tracking the bytes live and the most live at once.
|
||
struct Live;
|
||
static CUR: AtomicUsize = AtomicUsize::new(0);
|
||
static PEAK: AtomicUsize = AtomicUsize::new(0);
|
||
|
||
unsafe impl GlobalAlloc for Live {
|
||
unsafe fn alloc(&self, l: Layout) -> *mut u8 {
|
||
PEAK.fetch_max(CUR.fetch_add(l.size(), Relaxed) + l.size(), Relaxed);
|
||
unsafe { System.alloc(l) }
|
||
}
|
||
unsafe fn alloc_zeroed(&self, l: Layout) -> *mut u8 {
|
||
PEAK.fetch_max(CUR.fetch_add(l.size(), Relaxed) + l.size(), Relaxed);
|
||
unsafe { System.alloc_zeroed(l) }
|
||
}
|
||
unsafe fn realloc(&self, p: *mut u8, l: Layout, new: usize) -> *mut u8 {
|
||
if new >= l.size() {
|
||
PEAK.fetch_max(CUR.fetch_add(new - l.size(), Relaxed) + (new - l.size()), Relaxed);
|
||
} else {
|
||
CUR.fetch_sub(l.size() - new, Relaxed);
|
||
}
|
||
unsafe { System.realloc(p, l, new) }
|
||
}
|
||
unsafe fn dealloc(&self, p: *mut u8, l: Layout) {
|
||
CUR.fetch_sub(l.size(), Relaxed);
|
||
unsafe { System.dealloc(p, l) }
|
||
}
|
||
}
|
||
|
||
#[global_allocator]
|
||
static ALLOC: Live = Live;
|
||
|
||
fn clip(h: usize, w: usize, n: usize, f: impl Fn(usize, usize, usize, usize) -> u8) -> Vec<Vec<u8>> {
|
||
(0..n).map(|t| (0..h * w * 3).map(|i| f(t, i / 3 / w, i / 3 % w, i % 3)).collect()).collect()
|
||
}
|
||
|
||
/// A clip: its name, height, width, frames and the encoder's parameters.
|
||
type Case = (&'static str, u32, u32, Vec<Vec<u8>>, EncParams);
|
||
|
||
#[test]
|
||
fn the_encoder_holds_at_most_its_working_bytes() {
|
||
let mut x: u64 = 0x9e37_79b9_7f4a_7c15;
|
||
let mut noise = move || {
|
||
x ^= x << 13;
|
||
x ^= x >> 7;
|
||
x ^= x << 17;
|
||
(x >> 24) as u8
|
||
};
|
||
let noisy: Vec<Vec<u8>> = (0..10).map(|_| (0..40 * 48 * 3).map(|_| noise()).collect()).collect();
|
||
let cases: Vec<Case> = vec![
|
||
("noise, q 1", 40, 48, noisy, EncParams { block: 4, search: 2, mv_precision: 2, q: 1 }),
|
||
("smooth pan", 36, 64, clip(36, 64, 16, |t, y, x, c| ((x * 3 + y + 2 * t + c * 40) % 200) as u8), EncParams { block: 8, search: 3, mv_precision: 1, q: 6 }),
|
||
("block 1", 16, 16, clip(16, 16, 6, |t, y, x, c| ((x * 7 + y * 5 + t * 3 + c) % 256) as u8), EncParams { block: 1, search: 1, mv_precision: 1, q: 2 }),
|
||
("one frame", 50, 70, clip(50, 70, 1, |_, y, x, c| ((x ^ y) as u8).wrapping_mul(c as u8 + 1)), EncParams { block: 16, search: 4, mv_precision: 2, q: 3 }),
|
||
("1 x 3 noise, 2 frames, q 1", 1, 3, vec![vec![0, 255, 7, 250, 3, 128, 255, 0, 90], vec![255, 0, 250, 5, 255, 0, 0, 255, 1]], EncParams { block: 1, search: 1, mv_precision: 1, q: 1 }),
|
||
("2 x 5 noise, 4 frames, block 5, q 1", 2, 5, clip(2, 5, 4, |t, y, x, c| ((x * 97 + y * 31 + t * 151 + c * 67) * 2654435761 % 256) as u8), EncParams { block: 5, search: 1, mv_precision: 2, q: 1 }),
|
||
];
|
||
for (name, h, w, frames, p) in cases {
|
||
let base = CUR.load(Relaxed);
|
||
PEAK.store(base, Relaxed);
|
||
let e = encode(&frames, h, w, &p).expect("a clip the encoder codes");
|
||
let peak = (PEAK.load(Relaxed) - base) as u64;
|
||
let bound = working_bytes(frames.len() as u64, h, w, p.block);
|
||
let clip_bytes = frames.len() as u64 * h as u64 * w as u64 * 3;
|
||
assert!(peak <= bound, "{name}: held {peak} bytes, past the stated {bound}");
|
||
// The reconstruction it returns is held, so at least one clip.
|
||
assert!(peak >= clip_bytes, "{name}: held {peak} bytes, under the clip's {clip_bytes}");
|
||
drop(e);
|
||
}
|
||
// The review's sweep, seeded: small clips of noise, ramps and extremes, every block
|
||
// size to 8, both precisions, search to 2, steps from 1 to 65535.
|
||
let mut s: u64 = 0x1234_5678_9abc_def1;
|
||
let mut next = move || {
|
||
s ^= s << 13;
|
||
s ^= s >> 7;
|
||
s ^= s << 17;
|
||
s
|
||
};
|
||
let count = 3000;
|
||
for i in 0..count {
|
||
let h = 1 + (next() % 12) as u32;
|
||
let w = 1 + (next() % 12) as u32;
|
||
let n = 1 + (next() % 30) as usize;
|
||
let block = 1 + (next() % 8) as u32;
|
||
let mv_precision = 1 + (next() % 2) as u8;
|
||
let search = (next() % 3) as u32;
|
||
let q = [1u32, 2, 5, 64, 255, 65535][(next() % 6) as usize];
|
||
let kind = next() % 3;
|
||
let len = h as usize * w as usize * 3;
|
||
let frames: Vec<Vec<u8>> = (0..n)
|
||
.map(|t| {
|
||
(0..len)
|
||
.map(|j| match kind {
|
||
0 => (next() >> 24) as u8,
|
||
1 => ((j * 7 + t * 13) % 251) as u8,
|
||
_ => if (j + t) % 2 == 0 { 0 } else { 255 },
|
||
})
|
||
.collect()
|
||
})
|
||
.collect();
|
||
let p = EncParams { block, search, mv_precision, q };
|
||
let base = CUR.load(Relaxed);
|
||
PEAK.store(base, Relaxed);
|
||
let e = encode(&frames, h, w, &p).expect("a clip the encoder codes");
|
||
let peak = (PEAK.load(Relaxed) - base) as u64;
|
||
let bound = working_bytes(n as u64, h, w, block);
|
||
assert!(peak <= bound, "sweep case {i} ({h} x {w}, {n} frames, {p:?}): held {peak} bytes, past the stated {bound}");
|
||
drop(e);
|
||
}
|
||
}
|