Commit Graph
322 Commits
Author SHA1 Message Date
ddidderr 2557319583 feat(compress): move window dictionary policy into Rust
Move shared-window max-distance enforcement and dictionary-validity decisions into Rust. C keeps the private window pointer arithmetic, match-state pointer invalidation, and logging while applying the projected limit state returned by Rust.

Test Plan:
- ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo test --manifest-path rust/Cargo.toml
- ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; make -B -C programs -j1 zstd
- ulimit -v 41943040; make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s
2026-07-19 20:05:29 +02:00
ddidderr ff57c578db feat(compress): move window lifecycle predicates into Rust
Move shared window initialization and the empty-window and external-dictionary predicates behind the Rust compression seam. Rust now owns the projected five-field lifecycle state, while C retains the containing window and its overflow-correction counter.

Test Plan:
- ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo test --manifest-path rust/Cargo.toml
- ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; make -B -C programs -j1 zstd
- ulimit -v 41943040; make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s
2026-07-19 19:58:18 +02:00
ddidderr b4ad7ee796 feat(compress): move window update policy into Rust
Move the shared prefix and external-dictionary window transition into Rust
through a five-field projection. Preserve wrapping pointer-address arithmetic,
contiguous detection, short-dictionary clamping, and overlap clipping while C
retains the private match-state container and copies the projected fields back.

Test Plan:
- ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo test --manifest-path rust/Cargo.toml
- ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; make -B -C programs -j1 zstd
- ulimit -v 41943040; make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s
2026-07-19 19:49:24 +02:00
ddidderr 4aafcde301 fix(compress): reserve the block split terminal boundary
The optimal block splitter stores up to 196 split points and then needs one
additional partition entry for the terminal sequence boundary consumed by the
C block-emission loop. The previous array declaration provided only the split
slots, so a maximally partitioned block could write the terminal boundary past
the projected Rust/C state. Reserve the extra entry and document the layout;
retain focused tests for equal-cost and estimation-error cases so the splitter
continues to avoid unnecessary or invalid partitions.

Test Plan:
- Focused block-split Rust tests -- 7 passed
- `make -B -C lib -j2 lib` -- passed
- `cargo +nightly fmt --manifest-path rust/Cargo.toml -- --check` -- passed
- Scoped `git diff --check` -- passed
2026-07-18 17:59:49 +02:00
ddidderr c057bcbbdf feat(compress): move window clearing leaf into Rust
Keep the private ZSTD_window_t layout and pointer-difference calculation in C,
then route the size_t-to-U32 conversion and paired limit writes through a small
Rust ABI leaf. This removes the inline C window-clear implementation while
preserving its overflow behavior at both single-threaded and multithreaded
call sites.

Test Plan:
- cargo test --manifest-path rust/Cargo.toml --lib zstd_compress::tests (77 passed)
- make -C programs -j2 zstd
- rustfmt +nightly --edition 2021 rust/src/zstd_compress.rs --check
- make -C tests -j2 test-cli-tests (41 passed)
- make -C tests -j2 test-legacy test-invalidDictionaries test-decodecorpus test-rust-lib-smoke (passed)
- git diff --check
2026-07-18 17:23:33 +02:00
ddidderr 293cf96892 feat(compress): move overflow policy arithmetic to Rust
The window overflow gate mixed two scalar decisions with C-owned pointer and
window state. The early correction test uses the block-start index and must
wait for dictionary invalidation, while the normal fallback uses the block-end
index and the platform-selected ZSTD_CURRENT_MAX threshold. Keeping those
subtractions and the ZSTD_window_t wrapper in C preserves the existing call
contract without making Rust depend on pointer width or private state.

Move the U32 cycle/MAX arithmetic, correction-count scaling, dictionary gate,
and frequent-policy decision into Rust. C passes the two pointer-derived
indices only through scalar results, and supplies the current-max threshold
and active build policy explicitly so 32/64-bit and fuzzing configurations
remain authoritative.

Test Plan:
- `cargo test --manifest-path rust/Cargo.toml --no-default-features
  --features compression` -- 348 passed.
- Compression clippy for the library, benches, and tests, followed by
  nightly fmt and the repeated three clippy checks -- passed.
- `make -C lib -j2 lib-mt` and `make -C lib -j2 lib-nomt` -- passed.
- `make -C tests -j2 fuzzer` and `./tests/fuzzer -s4142 -t63 -i64 -v` --
  passed all 64 cases.
- `make -C tests -j2 test-zstream` -- passed 84 deterministic, 5,477 first
  randomized, and 6,902 new-API randomized cases; the existing unterminated
  string initializer warning remains.
2026-07-18 15:30:19 +02:00
ddidderr d00bcf7d06 feat(compress): move window overflow arithmetic to Rust
The window-overflow helper mixed pointer arithmetic and ZSTD_window_t state
updates with the scalar U32 cycle calculation that determines the correction.
That made the arithmetic boundary depend on the host pointer implementation.

Add a narrow Rust ABI leaf that accepts only the current index, cycle log, and
maximum distance. Rust preserves the start-index adjustment, cycle alignment,
cycle-size versus max-distance selection, and explicit U32 wrapping. C derives
newCurrent from the returned correction so it can retain every invariant check,
pointer update, workspace/table transition, counter update, and dictionary
invalidation in the existing stateful wrapper.

Test Plan:
- Rust compression clippy, bench clippy, test clippy, nightly fmt, and the
  repeated three clippy checks -- passed.
- `cargo test --manifest-path rust/Cargo.toml --no-default-features
  --features compression` -- 340 passed.
- `make -C lib -j2 lib-mt` and `make -C lib -j2 lib-nomt` -- passed.
- `./tests/fuzzer -s4142 -t63 -i64 -v` -- focused overflow coverage passed.
- `make -C tests -j2 test-zstream` -- 84 deterministic, 5,018 standard
  randomized, and 8,851 new-API randomized cases passed.
- `make -C tests -j2 test-fuzzer` reaches the pre-existing CCtx-reuse test 56
  failure; a pristine 837e4f099 worktree reproduces it, while the focused
  test-56 run passes.
2026-07-18 14:56:18 +02:00
ddidderr adb6928f04 feat(compress): move literal compression policy to Rust
ZSTD_literalsCompressionIsDisabled() previously switched on the private
ZSTD_CCtx_params layout in a header inline helper. Replace that switch with a
scalar ABI call that extracts only literalCompressionMode, strategy, and
targetLength in C. The Rust helper preserves the enable and disable results,
the fast-strategy auto rule, and C's debug assertion plus release fallthrough
for invalid modes. Keep callers and compression state ownership in C, and
cover the policy truth table and debug invalid-mode invariant in Rust.

Test Plan:
- Compression-feature clippy for the library, benches, and tests before and
  after nightly formatting -- passed.
- `cargo +nightly fmt --manifest-path rust/Cargo.toml` -- passed.
- `cargo test --manifest-path rust/Cargo.toml --no-default-features
  --features compression zstd_compress_params` -- passed (43 tests).
- `make -B -C lib -j2 lib` -- passed.
- `make -C tests test-rust-lib-smoke` -- passed.
- `tests/fuzzer -s4560 -t47 -i48 -v` and `-s4560 -t56 -i57 -v` -- passed.
- `make -C tests -j2 test-zstream` -- passed (84 named, 5,416, and 8,387
  randomized cases).
- `git diff --check` and `git diff --cached --check` -- passed.
2026-07-18 13:27:34 +02:00
ddidderr 48eb895af3 feat(compress): move raw and RLE block emitters to Rust
Replace the shared C raw and one-byte RLE fallback block serializers with Rust ABI leaves. Preserve the zstd block headers, payload copies, capacity errors, and all existing C compressor dispatch and context ownership; share the raw serializer with the Rust one-shot path.

Test Plan:

- cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression (208 tests)

- cargo clippy --manifest-path rust/Cargo.toml

- cargo clippy --manifest-path rust/Cargo.toml --benches

- cargo clippy --manifest-path rust/Cargo.toml --tests

- make -B -C lib -j2 lib
2026-07-18 06:03:39 +02:00
ddidderr 23d45378bd feat(compress): route complete stream frames through Rust
Route ordinary complete-input ZSTD_compressStream2 calls through the Rust frame compressor while retaining the C state machine for partial, advanced, and dictionary-backed streams. Track explicit maxBlockSize requests so the migrated path preserves the original byte-identical default behavior, and extend the C archive smoke test across context reuse and fallback cases.

Test Plan:

- cargo clippy --manifest-path rust/Cargo.toml

- cargo clippy --manifest-path rust/Cargo.toml --benches

- cargo clippy --manifest-path rust/Cargo.toml --tests

- cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression (133 passed)

- make -B -C tests -j2 test-rust-lib-smoke and ./tests/rustLibSmoke

- make -B -C tests -j2 test-zstream (passed, including both APIs and maxBlockSize case 78)
2026-07-18 01:52:28 +02:00
ddidderr 5c448120cf feat(compress): route simple context frames through Rust
Dispatch ordinary dictionary-free ZSTD_compress2 calls through the Rust frame
compressor while retaining the original C implementation for advanced
contexts. Prepare the C workspace first so allocation downsizing and
static-context limits remain observable.

Mark successful Rust frames so a following one-shot
ZSTD_compressStream2(..., ZSTD_e_end) call uses the same output path. Other
streaming directives and advanced parameters remain on the C implementation.

Test Plan:
- RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER= cargo test --manifest-path
  rust/Cargo.toml --no-default-features --features compression
  zstd_compress::tests
- RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER= cargo clippy --manifest-path
  rust/Cargo.toml --no-default-features --features compression -- -D warnings
- cargo +nightly fmt --manifest-path rust/Cargo.toml -- --check
- make -B -C tests fuzzer
- ./tests/fuzzer -t114 -i1000 --no-big-tests -s1

The basic fuzzer run now reaches the existing Rust one-shot compression-ratio
limit at test 113; the new stateful reuse tests pass before that point.
2026-07-12 19:16:14 +02:00
Yann ColletandYann Collet 8eb2587432 added benchmark for get1BlockSummary() 2025-01-15 17:11:27 -08:00
Victor ZhangandGitHub a610550e2c Merge pull request #4218 from facebook/externC
Move #includes out of `extern "C"` blocks
2025-01-07 10:06:08 -08:00
Yann Collet 12c47d3262 improved speed of the Sequences converter 2024-12-20 10:37:00 -08:00
Yann Collet 95ad9e47ff added benchmark for ZSTD_convertBlockSequences_wBlockDelim() 2024-12-20 10:37:00 -08:00
Yann ColletandYann Collet 1c8f5b0f11 minor optimization for ZSTD_compressSequencesAndLiterals()
does not need to track and update internal `litPtr`.
note: does not measurably impact performance.
2024-12-20 10:36:59 -08:00
Yann Collet 8ab04097ed add the compressSequences() benchmark scenario 2024-12-20 10:36:59 -08:00
Yann Collet 4ef9d7d585 codemod: ZSTD_cParamMode_e -> ZSTD_CParamMode_e 2024-12-20 10:36:58 -08:00
Yann Collet 56cfb7816a codemod: ZSTD_paramSwitch_e -> ZSTD_ParamSwitch_e 2024-12-20 10:36:58 -08:00
Yann Collet 08edecb78c codemod: ZSTD_blockCompressor -> ZSTD_BlockCompressor_f 2024-12-20 10:36:57 -08:00
Yann Collet 25bef24c5c codemod: rawSeqStore_t -> RawSeqStore_t 2024-12-20 10:36:57 -08:00
Yann Collet 41c667c0fd codemod: repcodes_t -> Repcodes_t 2024-12-20 10:36:57 -08:00
Yann Collet 5df80acedb codemod: ZSTD_matchState_t -> ZSTD_MatchState_t 2024-12-20 10:36:57 -08:00
Yann Collet 30671d77af codemod: ZSTD_sequencePosition -> ZSTD_SequencePosition 2024-12-20 10:36:57 -08:00
Yann Collet 03d95f9d13 fix proper type for .forceNonContiguous 2024-12-20 10:36:57 -08:00
Yann Collet 76dd3a98c4 scope: ZSTD_copySequencesToSeqStore*() are private to ZSTD_compress.c
no need to publish them outside of this unit.
2024-12-20 10:36:57 -08:00
Yann Collet c97522f7fb codemod: ZSTD_sequenceFormat_e -> ZSTD_SequenceFormat_e
since it's a type name.

Note: in contrast with previous names, this one is on the Public API side.
So there is a #define, so that existing programs using ZSTD_sequenceFormat_e still work.
2024-12-20 10:36:56 -08:00
Yann Collet 477a01067f codemod: symbolEncodingType_e -> SymbolEncodingType_e 2024-12-20 10:36:56 -08:00
Yann Collet 8d4506bc94 codemod: ZSTD_sequenceLength -> ZSTD_SequenceLength 2024-12-20 10:36:55 -08:00
Yann Collet a2245721ca codemod: seqStore_t -> SeqStore_t
same idea, SeqStore_t is a type name, it should start with a Capital letter.
2024-12-20 10:36:55 -08:00
Yann Collet 9671813375 codemod: seqDef -> SeqDef
SeqDef is a type name, so it should start with a Capital letter.
It's an internal symbol, no impact on public API.
2024-12-20 10:36:55 -08:00
Yann Collet b4a40a845f move Sequences definition to zstd_compress_internal.h
they should not be in common/zstd_internal.h,
since these definitions are not shared beyond lib/compress/.
2024-12-20 10:36:55 -08:00
Yann Collet a00f45a037 created ZSTD_storeSeqOnly()
makes it possible to register a sequence without copying its literals.
2024-12-20 10:36:04 -08:00
Victor Zhang d0d5ce4c00 Remove extern C blocks from lib/* internal APIs (except xxhash.h) 2024-12-19 16:00:11 -08:00
Yann Collet 01474bf73b add internal compression parameter preBlockSplitter_level
not yet exposed to the interface.

Also: renames `useBlockSplitter` to `postBlockSplitter`
to better qualify the difference between the 2 settings.
2024-10-28 16:31:15 -07:00
Yann Collet cae8d13294 splitter workspace is now provided by ZSTD_CCtx* 2024-10-23 11:50:56 -07:00
Yann Collet 31d48e9ffa fixing minor formatting issue in 32-bit mode with logs enabled 2024-10-23 11:50:56 -07:00
Yann ColletandGitHub 8c38bda935 Merge pull request #4165 from facebook/cspeed_cmov
Improve compression speed on small blocks
2024-10-11 16:20:19 -07:00
Yann Collet 186b132495 made search strategy switchable
between cmov and branch
and use a simple heuristic based on wlog to select between them.

note: performance is not good on clang (yet)
2024-10-08 13:52:56 -07:00
Yann Collet 2cc600bab2 refactor search into an inline function
for easier swapping with a parameter
2024-10-08 11:10:48 -07:00
Yann Collet 1e7fa242f4 minor refactor zstd_fast
make hot variables more local
2024-10-07 11:22:40 -07:00
Ilya Tokar e8fce38954 Optimize compression by avoiding unpredictable branches
Avoid unpredictable branch. Use conditional move to generate the address
that is guaranteed to be safe and compare unconditionally.
Instead of

if (idx < limit && x[idx] == val ) // mispredicted idx < limit branch

Do

addr = cmov(safe,x+idx)
if (*addr == val && idx < limit) // almost always false so well predicted

Using microbenchmarks from https://github.com/google/fleetbench,
I get about ~10% speed-up:

name                                                                                          old cpu/op   new cpu/op    delta
BM_ZSTD_COMPRESS_Fleet/compression_level:-7/window_log:15                                     1.46ns ± 3%   1.31ns ± 7%   -9.88%  (p=0.000 n=35+38)
BM_ZSTD_COMPRESS_Fleet/compression_level:-7/window_log:16                                     1.41ns ± 3%   1.28ns ± 3%   -9.56%  (p=0.000 n=36+39)
BM_ZSTD_COMPRESS_Fleet/compression_level:-5/window_log:15                                     1.61ns ± 1%   1.43ns ± 3%  -10.70%  (p=0.000 n=30+39)
BM_ZSTD_COMPRESS_Fleet/compression_level:-5/window_log:16                                     1.54ns ± 2%   1.39ns ± 3%   -9.21%  (p=0.000 n=37+39)
BM_ZSTD_COMPRESS_Fleet/compression_level:-3/window_log:15                                     1.82ns ± 2%   1.61ns ± 3%  -11.31%  (p=0.000 n=37+40)
BM_ZSTD_COMPRESS_Fleet/compression_level:-3/window_log:16                                     1.73ns ± 3%   1.56ns ± 3%   -9.50%  (p=0.000 n=38+39)
BM_ZSTD_COMPRESS_Fleet/compression_level:-1/window_log:15                                     2.12ns ± 2%   1.79ns ± 3%  -15.55%  (p=0.000 n=34+39)
BM_ZSTD_COMPRESS_Fleet/compression_level:-1/window_log:16                                     1.99ns ± 3%   1.72ns ± 3%  -13.70%  (p=0.000 n=38+38)
BM_ZSTD_COMPRESS_Fleet/compression_level:0/window_log:15                                      3.22ns ± 3%   2.94ns ± 3%   -8.67%  (p=0.000 n=38+40)
BM_ZSTD_COMPRESS_Fleet/compression_level:0/window_log:16                                      3.19ns ± 4%   2.86ns ± 4%  -10.55%  (p=0.000 n=40+38)
BM_ZSTD_COMPRESS_Fleet/compression_level:1/window_log:15                                      2.60ns ± 3%   2.22ns ± 3%  -14.53%  (p=0.000 n=40+39)
BM_ZSTD_COMPRESS_Fleet/compression_level:1/window_log:16                                      2.46ns ± 3%   2.13ns ± 2%  -13.67%  (p=0.000 n=39+36)
BM_ZSTD_COMPRESS_Fleet/compression_level:2/window_log:15                                      2.69ns ± 3%   2.46ns ± 3%   -8.63%  (p=0.000 n=37+39)
BM_ZSTD_COMPRESS_Fleet/compression_level:2/window_log:16                                      2.63ns ± 3%   2.36ns ± 3%  -10.47%  (p=0.000 n=40+40)
BM_ZSTD_COMPRESS_Fleet/compression_level:3/window_log:15                                      3.20ns ± 2%   2.95ns ± 3%   -7.94%  (p=0.000 n=35+40)
BM_ZSTD_COMPRESS_Fleet/compression_level:3/window_log:16                                      3.20ns ± 4%   2.87ns ± 4%  -10.33%  (p=0.000 n=40+40)

I've also measured the impact on internal workloads and saw similar
~10% improvement in performance, measured by cpu usage/byte of data.
2024-09-20 16:07:01 -04:00
Yann Collet 09cb37cbb1 Limit range of operations on Indexes in 32-bit mode
and use unsigned type.
This reduce risks that an operation produces a negative number when crossing the 2 GB limit.
2024-08-21 11:03:43 -07:00
Yann Collet cb784edf5d added android-ndk-build 2024-07-30 11:34:49 -07:00
Federico MarescaandGitHub 5e9a6c2fe4 Refactor dictionary matchfinder index safety check (#4039) 2024-05-29 12:35:24 -04:00
Yann Collet 22574d848d fix issue 5921623844651008
ossfuzz managed to create a scenario which triggers an `assert`.
This fixes it, by giving +1 more space for the backward search pass.
2024-02-06 13:01:14 -08:00
Yann Collet b88c593d8f added or updated code comments
as suggested by @terrelln,
to make the code of the optimal parser a bit more understandable.
2024-02-05 18:32:25 -08:00
Yann Collet 5474edbe60 fixed wrong assert
by introducing ZSTD_OPT_SIZE
2024-02-03 19:31:53 -08:00
Yann Collet 4683667785 refactor optimal parser
store stretches as intermediate solution instead of sequences.
makes it possible to link a solution to a predecessor.
2024-01-31 02:51:46 -08:00
Elliot Gorokhovsky d151a4880b Move offload API params into ZSTD_CCtx_params 2023-11-27 08:11:01 -08:00