perf(kernel): disable AVX-512 VBMI2 tier by default; defer dict-frame table clear - #443
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe PR refactors HashChain dictionary priming by deferring hash-table clearing from ChangesHashChain dict prime: deferred hash-table clearing
AVX-512 default feature
FSE encoder optimization
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@zstd/src/encoding/match_table/storage.rs`:
- Around line 1351-1365: The HashChain dictionary deactivation is incomplete
because when `invalidate_primed_dictionary()` is called, it only invalidates the
cached dms tree but fails to set `dictionary_active = false`. This causes
`reset()` to defer table clears based on the stale `dictionary_active = true`
flag, but since the dictionary is gone, the expected `prime_with_dictionary()`
or `restore_primed_dictionary()` calls never execute, leaving deferred clears
unprocessed and stale table entries with old absolute positions. To fix this,
modify the `invalidate_primed_dictionary()` method to explicitly set
`dictionary_active = false` for HashChain, ensuring that `reset()` will not
defer the table clear when no dictionary is available for re-priming on the next
frame.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: f964e277-2e80-4847-b8b4-2deef34d68b8
📒 Files selected for processing (3)
zstd/Cargo.tomlzstd/src/encoding/match_generator.rszstd/src/encoding/match_table/storage.rs
Removing or replacing a dictionary invalidated the primed snapshot but left the HashChain storage marked dictionary-active. A following no-dictionary frame then took the dict-active reset branch (rewind to origin, defer the table clear to a prime/restore that never runs), leaving stale dict-region entries at the rewound base. Output stayed correct (every match is window-bounds-checked and byte-verified), but the deferred-clear invariant the reset documents was violated. Clear the dictionary-active flag on invalidate so the next reset takes the no-dictionary path; a replacement dictionary re-arms it on re-prime. Adds a regression guard for the remove-dictionary then no-dict round-trip.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@zstd/src/fse/fse_encoder.rs`:
- Around line 808-825: The unsafe code using `set_len` on `state_table_flat`
currently depends on invariants that are only verified in debug builds via
debug_assert statements (located around the phase-2 verification logic before
this block). Convert these debug_assert calls to regular assert or assert_eq
calls to ensure the safety contract for full table initialization is enforced in
all build profiles, preventing potential undefined behavior if probability
normalization regresses in release builds.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b6b98277-7b6e-49a0-be79-0768594c2499
📒 Files selected for processing (5)
README.mdzstd/src/encoding/frame_compressor.rszstd/src/encoding/match_generator.rszstd/src/encoding/match_table/storage.rszstd/src/fse/fse_encoder.rs
The uninitialized-then-filled state_table_flat relied on a debug_assert for its full-init proof, so release builds carried no guard. Promote the spread-cycle invariant to a release assert and add a cursor-sum assert, so a probability-normalization regression panics here instead of leaving uninitialized slots that later read as UB. Two O(1) checks per FSE build.
Summary
Two perf changes, the first is the substantive one:
Disable the AVX-512 VBMI2 decode tier by default. The dashboard's
low-entropy-1mdecompress outsiders atlevel_3_dfast/level_4_dfast(reported ~6x slower than the C reference,
-83%) are an AVX-512 artifact, nota real regression. Verified ours-vs-c_ffi on three hosts, interleaved,
back-to-back so contamination hits both arms equally:
Rust beats the C reference on every tier we can test — including the worst-case
pure-scalar path. The dashboard runner is AVX-512-capable, so the runtime
dispatch selected the VBMI2 tier there; AVX-512 license-based frequency
downclocking stalls the whole (bursty, memory-bound) decode and the heavier
kernel never amortizes, so the VBMI2 tier runs far slower than AVX2 on that
silicon. With
kernel_vbmi2removed from the default feature set, AVX-512 hostsfall back to the AVX2 tier (faster there); the kernel is kept and opt-in via
--features kernel_vbmi2for a sustained-AVX-512 workload that benefits.Defer the dict-frame table clear to prime. The dict-active matcher reset
zero-filled the hash/chain tables, but the reuse hot path immediately restores a
clean primed snapshot over them via
clone_from, so that fill was thrown away.Deferred to
prime_with_dictionary(mirrors the Fast matcher's existingtable_overwritten_by_restoreskip that the HC path lacked). Byte-identicaloutput; small win on tiny dict frames.
Verification
The VBMI2 change cannot be measured on the available hosts (none have AVX-512) —
the dashboard CI runner is the AVX-512 test machine. The dashboard decode delta
on
low-entropy-1mlevel_3_dfast/level_4_dfastshould move from the-83%band back toward parity once the runner stops selecting VBMI2.
Testing
cargo nextest run -p structured-zstd— 789 passcargo clippy --all-targets— cleanSummary by CodeRabbit
kernel_vbmi2) tier from the default feature set; it can still be enabled explicitly via--features kernel_vbmi2.