Repository navigation
feat(rust): predict the vmaf_v1.0.16 models in Rust, bit-identical to the C predictor - #2085
Merged
Merged
Conversation
lusoris
force-pushed
the
rc4/rust-extractor-framework
branch
from
October 7, 2026 14:26
e99e0f4 to
5962a1a
Compare
16 of 26 tasks
lusoris
force-pushed
the
rc4/rust-extractor-framework
branch
from
October 7, 2026 15:19
5962a1a to
e8886a9
Compare
42 tasks
lusoris
force-pushed
the
rc4/rust-extractor-framework
branch
from
October 7, 2026 16:43
e8886a9 to
ccf7ccf
Compare
lusoris
force-pushed
the
rc4/predict-twin
branch
from
October 7, 2026 17:51
c13e232 to
71fd212
Compare
lusoris
marked this pull request as ready for review
October 7, 2026 17:51
lusoris
force-pushed
the
rc4/predict-twin
branch
from
October 7, 2026 21:02
71fd212 to
2f8ffd6
Compare
| /* What the table was handed for frame 1. */ | ||
| static char *check_routed_arguments(const Fixture *fx) | ||
| { | ||
| mu_assert("the table gets the raw score", fake.first_raw == raw_score(0, 1)); |
| fixture_close(&fx); | ||
| vmaf_predict_install_rust_ops(NULL); | ||
| mu_assert("an unsupported model scores", err == 0 && again == 0); | ||
| mu_assert("an unsupported model runs the C predictor", state == 2 && score == expected); |
lusoris
force-pushed
the
rc4/predict-twin
branch
from
October 8, 2026 01:03
2f8ffd6 to
a77da3e
Compare
…2548 landed twice (#2560) * fix(test): drop the second MALLOC_PERTURB_ entry and state row that #2548 landed twice #2548 landed the merge train's squash of its first revision, which still carried its own MALLOC_PERTURB_=0 entry for test_gpu_picture_pool_uaf and a state row for the same bug; #2547 had already landed both. core/test/meson.build now lists the entry once (#2547's), docs/state.md keeps T-GPU-POOL-UAF-TEST-FILLS-HOST-MEMORY-2026-10-08 only, and the #2548 changelog and rebase-note fragments no longer claim that fix. Signed-off-by: Lusoris <lusoris@proton.me>
… (ADR-2199) (#2423) * ci(hooks): run actionlint under a deadline so a deadlock fails loudly (ADR-2199) actionlint v1.7.12 writes the script of a `run:` block to shellcheck's stdin pipe before it starts shellcheck, so it deadlocks when the script is larger than the pipe. A user over fs.pipe-user-pages-soft gets pipes of 8 KiB, which made the pre-push hook hang on about every other push. scripts/ci/run_actionlint.py gives the run 90 seconds, terminates the process group, names the cause and exits 124; it never reports a pass for a run that did not finish. The hook and `make lint-actions` both go through it. The defect is upstream (rhysd/actionlint#702). Decision Q-078. Restore SIGQUIT for actionlint and signal only it, so the hang dump survives a background start where non-interactive shells ignore SIGQUIT by default. Signed-off-by: Lusoris <lusoris@proton.me>
#2096) * feat(rust): port the integer motion extractor to Rust (motion_rust)
…m extractor (#2099) * feat(rust): add adm_rust, a bit-identical Rust twin of the integer adm extractor Signed-off-by: Lusoris <lusoris@proton.me>
… the C predictor (#2085) * feat(rust): predict the vmaf_v1.0.16 models in Rust, bit-identical to the C predictor Add the vmafx-predict crate (normalise, chroma correction, nu-SVR, denormalise, finite checks, polynomial and piecewise score transform, clip) with its C ABI and a flat model view built by core/src/rust/shim/rust_predict.c. predict.c splits the post-gather steps into predict_compute_c() and predict_compute_rust(); VMAF_FEATURE_IMPL=rust selects the Rust predictor, which runs only for models it implements and says so otherwise. predict.c and model_lifetime.c reach Rust only through the struct VmafRustPredictOps table declared in predict.h and installed with vmaf_predict_install_rust_ops(). The shim defines the table and vmaf_rust_predict_install(); it is a libvmaf source (rust_shim_sources), and vmaf_ctx_subsystems_init() calls the installer next to vmaf_rust_twins_install(). Binaries that link the predict_c archive without libvmaf never need the Rust archive. With VMAF_FEATURE_IMPL=rust and no table installed, or for a model the Rust predictor refuses, the C predictor runs and a WARNING names the model; vmaf_model_destroy() frees the handle through the table. test_predict_rust_ops (every build, a stand-in table) covers the routing, the fallback warnings, error propagation and the free on destroy; test_rust_predict compares both predictors bit for bit on the v1.0.16 models and edited variants and checks that vmaf_init() installs the table. * fix(rust): keep the cbindgen headers byte for byte so the Rust ABI header check passes rust-abi-header.sh --check compares core/src/rust/include/*.h with a fresh cbindgen 0.29.4 run, but the clang-format commit hook had reformatted vmafx_rs.h, so the Rust workflow's check failed on every head. The clang-format hooks and make format skip the directory, both headers are regenerated verbatim (whitespace only), and a tooling test fails when a formatter selects them or the check fails. * ci(tidy): measure the translation units of the Rust predictor's C side in the cpu lane The clang-tidy coverage rule on master requires every tracked translation unit to be read by a lane. The new and touched units of this pull request were measured in the dev container (scripts/dev/tidy-lane.sh --write --only ... cpu, clang-tidy 22.1.8): 0 findings, 0 uncited NOLINT; they join the cpu lane's measured sources. * docs(agents): write the Rust twin's agent page in the internal register (praetor caveman lint) * docs(rust): move the rebase note to a fragment and leave the rendered files to the landing render (ADR-2197) Signed-off-by: Lusoris <lusoris@proton.me>
lusoris
force-pushed
the
rc4/predict-twin
branch
from
October 8, 2026 02:16
a77da3e to
059f018
Compare
lusoris
added a commit
that referenced
this pull request
Oct 8, 2026
…maf_test_link test_predict_rust_ops, test_rust_predict and test_rust_cambi_kernels came to master with #2085 and #2090 and link libvmaf.get_static_lib(). After the library split libvmaf.a is the compat library: a white-box test links vmaf_test_link (libvmaf.a with libvmafx.a, or both shared libraries), as every other white-box test of this PR does. Signed-off-by: Lusoris <lusoris@proton.me>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
RC4 lane P of #1723: the prediction step of the
vmaf_v1.0.16*models in Rust. With-Denable_rust_features=trueandVMAF_FEATURE_IMPL=rust,vmaf_predict_score_at_index()runs normalisation, the chroma correction, the nu-SVR (RBF, plus linear and polynomial kernels), denormalisation, the finite checks, the polynomial and piecewise-linear score transform and the clip in the newvmafx-predictcrate. The C predictor stays the default. Model loading, name resolution, the score gather from the collector and the append of the prediction stay in C. Lands bottom-up per Q-083 after #2086 (the framework, ADR-1713).Landed base: #2086 (framework, ADR-1713) and #2199 are on master; this branch was rebased onto master
2da09c2a9with the framework's commits dropped, retargeted tomaster, and queued with the other twins (Q-083). The cpu tidy baseline took master's side at each rebase and was re-measured in the dev container (4 TUs, 0 findings). Re-gate on that head: default build 0 warnings,--suite=fast392 OK, golden 280 passed, msvcism pass; Rust build 0 warnings,--suite=fast --suite=rust397 OK, 0 fail; model cells--modelson netflix, checker1, checker10: 24 of 24 EQUAL.Result: bit-identical to the C predictor on every model cell measured on the rebased head, 0 diffs (details below).
Rebase and adaptation. The lane's commits are squashed into one commit and replayed onto the rebased framework head (
5962a1a51). The lane's stand-in wiring (shim compiled into thepredict_carchive,#ifdef HAVE_RUST_FEATURESinpredict.candmodel.c, its own env reader) is replaced by the design the RC4 contract fixes for the predictor (request P-1):predict.ckeeps astruct VmafRustPredictOpstable (create,predict,destroy, declared inpredict.h), set withvmaf_predict_install_rust_ops(); NULL means the C predictor.predict.c,model.candmodel_lifetime.ccontain no Rust symbol, no Rust include and noHAVE_RUST_FEATURESbranch, so every binary that links thepredict_carchive without libvmaf still links without the Rust archive.core/src/rust/shim/rust_predict.cbuilds the flat model view, defines the table onvmafx_rs_model_new/_predict/_freeandvmaf_rust_predict_install(); it is listed inrust_shim_sources(a libvmaf source), andvmaf_ctx_subsystems_init()calls the installer next tovmaf_rust_twins_install().vmaf_feature_impl_rust_requested(). WithVMAF_FEATURE_IMPL=rustand no table (a build without Rust), or a model the Rust predictor refuses, the C predictor runs and a WARNING names the model (no silent fallback); a value other thanc/rustfails the prediction with-EINVAL.vmaf_model_destroy()(now inmodel_lifetime.con master) frees the Rust handle through the table and the raw-score scratch.core/test/test_predict_rust_ops.c(every build, a counting stand-in table) covers the routing, both WARNING fallbacks, error propagation, one handle per model and the free on destroy;test_rust_predictgains a check thatvmaf_init()installs the table.core/src/rust/shim/rust_predict.candcore/test/test_rust_predict.cbuild only with-Denable_rust_features=trueand join the tidy-coverage exceptions next to the framework's Rust-only units (same reason, expiry 2026-12-31).test_predict_rust_ops.cis built in every configuration and is measured by the cpu lane.Rust ABI header check (found here, fixed here). With the pinned cbindgen 0.29.4,
scripts/dev/rust-abi-header.sh --check(the Rust workflow's step, ADR-1713) failed on the framework head: the clang-format commit hook had reformattedcore/src/rust/include/vmafx_rs.hwhen it was committed. The clang-format hooks andmake formatnow skipcore/src/rust/include/, both generated headers (vmafx_rs.h, this lane'svmafx_rs_predict.h) are cbindgen's bytes (whitespace-only diff), andscripts/ci/tests/test_rust_abi_header_verbatim.pyfails when a formatter selects them or the check fails (all three cases fail on the previous head). State rowT-RUST-ABI-HEADER-CHECK-FORMATTED-2026-10-07.Re-gate after the framework's second rebase (onto #2173, framework head
e8886a95a): default build 0 warnings,--suite=fast381 OK, golden 280 passed, msvcism pass, affected tooling 2164 passed; Rust build 0 warnings,--suite=fast --suite=rust386 OK, 0 fail; model cellsrust_twin_diff.py --modelson five fixtures 38 EQUAL, 2 REFUSED by both sides (the two3d0h_2160models on sparks10), 0 other; the tidy baseline was re-measured in the container (4 TUs, 0 findings) after master's history entry for #2173.Type
feat— new featurefix— bug fixperf— performance improvementrefactor— no behavior changedocs— documentation onlytest— test-onlybuild/ci— tooling / infraport— cherry-pick from upstream Netflix/vmafsycl/cuda/simd— backend-specificChecklist
make format && make lintis green locally. (Commit hooks pass; Rust:cargo fmt --all --check,cargo clippy --workspace --all-targets -- -D warningsclean.)fb2dd3c07), CPU only,-j4, both builds with$(bash scripts/ci/werror-args.sh true)and 0 compiler warnings:-Denable_rust_features=true -Db_lto=false):python3 scripts/ci/run_meson_test.py -- -C build-rs --suite=fast --suite=rust→ 382 OK, 0 fail (incl.test_rust_predict,test_predict_rust_ops,test_rust_abi_layout,test_rust_twin_registry,test_rust_twin_harness_netflix).--suite=fast→ 377 OK, 0 fail (incl.test_predict_rust_ops,test_predict); every binary that links thepredict_carchive links without the Rust archive.make test-netflix-golden→ 280 passed, 3 skipped. Affected Python suites: 2149 passed, 0 failed.cargo fmt --all --check,cargo clippy --offline --workspace --all-targets -- -D warnings(0 warnings),cargo test -p vmafx-predict→ 10 passed (--manifest-path core/src/rust/Cargo.toml).scripts/dev/preflight.sh --stage msvcism→ pass.core/src/predict.c,core/src/libvmaf.c,core/src/model_lifetime.c,core/test/test_predict_rust_ops.c0 findings (scripts/dev/tidy-lane.sh --write --only ... cpu, clang-tidy 22.1.8 in the dev image;test_predict_rust_ops.cadded to the cpu lane's measured sources).vmaf_rust_predict_install()call removed fromlibvmaf.c,test_rust_predictfails ("vmaf_init() installed the Rust predictor"); with the store invmaf_predict_install_rust_ops()removed,test_predict_rust_opsfails ("the table's result is the score"). Both restored./cross-backend-diffand the worst ULP is ≤ 2. — no SIMD/GPU code touched (CPU prediction only)..c/.cpp/.cu/.h/.hpp, it has the appropriate license header (seeCONTRIBUTING.md). (EUPL-1.2 for fork-authored files; the Rust files that port Netflix code statement by statement carry BSD-2-Clause-Patent and name the C file they mirror.)!orBREAKING CHANGE:and the migration path is documented below. — not breaking;struct VmafModelis internal.docs/adr/_index_fragments/<NNNN-slug>.mdand the slug is appended todocs/adr/_index_fragments/_order.txt— no new ADR; the decisions are ADR-1713's (the predictor table is the contract's section 4). The one choice this PR makes (a model the Rust predictor refuses runs on the C predictor with a WARNING; sigmoid kernel refused becausevmafx_fex::libmhas notanhand no v1 model uses it) is recorded incore/src/AGENTS.d/rust-model-prediction.md.Bug-status hygiene (ADR-0165)
docs/state.mdupdated in this PR with a row in the appropriate section, ORno state delta: REASON. — no state delta: no bug opened, closed or ruled out; no C defect found while porting.Netflix golden-data gate (ADR-0024)
assertAlmostEqual(...)score in the Netflix golden Python tests.Cross-backend numerical results
Rust predictor vs C predictor through
scripts/ci/rust_twin_diff.py --models --fixtures netflix,checker1,checker10,sparks10,bbb4k --threads 0on the rebased head: the samebuild-rs/tools/vmafrun withVMAF_FEATURE_IMPL=cand=rust,--precision max --json, every per-frame metric includingvmafcompared as IEEE doubles. Every model logsmodel vmaf: Rust predictionon the Rust side and no such line on the C side (checked per model onnetflix). 40 cells: 38 EQUAL, 2 REFUSED, 0 other.Identical frames / total; max abs diff 0 in every EQUAL cell. REFUSED: both sides exit 234 on the same input (
SpEED: image too small, operating width or height is 0: the 2160 prescale of 480x270), which the harness counts as parity.test_rust_predictadds 48 random frames x 4 flag sets per model on the 8 models, edited copies (piecewise knots without_lte_in/out_gte_in,p1only, no transform and no clip, normalisation off, chroma off), the chroma sentinel and NaN input (both fail with-EINVAL, output untouched). On the lane branch, mutating the Rust (denormalise by a reciprocal product, a one-ulp change of thep1term) failed both the test and the harness.Performance
Speed is not a gate in RC4 (measured on the lane branch before the rebase; the arithmetic is unchanged). Single thread,
--threads 1, median of 3, default modelvmaf_v1.0.16_3d0h, host load average 20 to 30:The prediction is about 0.002 ms of a 2 ms (576x324) or 80 ms (4K) frame, so the end-to-end numbers measure the host load, not the predictor. The Rust predictor is about 25 percent slower than the C one per call (215 support vectors, one
expeach, bounds-checked slices); left for RC7.Deep-dive deliverables (ADR-0108)
AGENTS.mdinvariant note —core/src/AGENTS.d/rust-model-prediction.md(bit identity withpredict.c; only libvmaf links the Rust archive,predict.c/model.c/model_lifetime.creach Rust only throughVmafRustPredictOps).changelog.d/added/rust-model-prediction.md.docs/rebase-notes.d/rust-model-prediction.md(fragment, ADR-2197), "Rust model prediction (RC4 lane P, RC4 — Rust metric, zero-copy import, the VMAFx API and the cloud-native platform #1723)".Reproducer
Known follow-ups
scripts/dev/rust-abi-header.sh --checkregeneratesvmafx_rs_predict.honly where cbindgen is installed;test_rust_abi_layoutandtest_rust_predictguard the ABI meanwhile.