From eb6608869fa58d324227b3e5484cc3347a8dd8ed Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 18 Feb 2025 16:19:18 -0800 Subject: [PATCH 001/245] faster clang-msan-testzstd this is by far our longest CI test. Attempt to make it run a bit faster. --- .github/workflows/dev-long-tests.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 899a57b75..0aa85ff7e 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -222,16 +222,13 @@ jobs: sudo apt-get install clang CC=clang FUZZER_FLAGS="--long-tests" make clean msan-fuzztest - # lasts ~24mn clang-msan-testzstd: runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 - name: clang + MSan + Test Zstd run: | - sudo apt-get update - sudo apt-get install clang - CC=clang make msan-test-zstd HAVE_ZLIB=0 HAVE_LZ4=0 HAVE_LZMA=0 V=1 + CC=clang make -j msan-test-zstd HAVE_ZLIB=0 HAVE_LZ4=0 HAVE_LZMA=0 V=1 armfuzz: runs-on: ubuntu-latest From 37077c859be9a07884283602ffbccf32bba32e95 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 18 Feb 2025 21:22:02 -0800 Subject: [PATCH 002/245] updated benchmark numbers using latest version of @inikep's lzbench --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index d91ef5df1..22a127dc9 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,9 @@ a list of known ports and bindings is provided on [Zstandard homepage](https://f For reference, several fast compression algorithms were tested and compared on a desktop featuring a Core i7-9700K CPU @ 4.9GHz -and running Ubuntu 20.04 (`Linux ubu20 5.15.0-101-generic`), +and running Ubuntu 24.04 (`Linux 6.8.0-53-generic`), using [lzbench], an open-source in-memory benchmark by @inikep -compiled with [gcc] 9.4.0, +compiled with [gcc] 14.2.0, on the [Silesia compression corpus]. [lzbench]: https://github.com/inikep/lzbench @@ -41,16 +41,16 @@ on the [Silesia compression corpus]. | Compressor name | Ratio | Compression| Decompress.| | --------------- | ------| -----------| ---------- | -| **zstd 1.5.6 -1** | 2.887 | 510 MB/s | 1580 MB/s | -| [zlib] 1.2.11 -1 | 2.743 | 95 MB/s | 400 MB/s | -| brotli 1.0.9 -0 | 2.702 | 395 MB/s | 430 MB/s | -| **zstd 1.5.6 --fast=1** | 2.437 | 545 MB/s | 1890 MB/s | -| **zstd 1.5.6 --fast=3** | 2.239 | 650 MB/s | 2000 MB/s | -| quicklz 1.5.0 -1 | 2.238 | 525 MB/s | 750 MB/s | -| lzo1x 2.10 -1 | 2.106 | 650 MB/s | 825 MB/s | -| [lz4] 1.9.4 | 2.101 | 700 MB/s | 4000 MB/s | -| lzf 3.6 -1 | 2.077 | 420 MB/s | 830 MB/s | -| snappy 1.1.9 | 2.073 | 530 MB/s | 1660 MB/s | +| **zstd 1.5.7 -1** | 2.896 | 510 MB/s | 1550 MB/s | +| [zlib] 1.3.1 -1 | 2.743 | 105 MB/s | 390 MB/s | +| brotli 1.1.0 -0 | 2.702 | 400 MB/s | 425 MB/s | +| **zstd 1.5.7 --fast=1** | 2.439 | 545 MB/s | 1850 MB/s | +| **zstd 1.5.7 --fast=3** | 2.241 | 635 MB/s | 1980 MB/s | +| quicklz 1.5.0 -1 | 2.238 | 520 MB/s | 750 MB/s | +| lzo1x 2.10 -1 | 2.106 | 650 MB/s | 780 MB/s | +| [lz4] 1.10.0 | 2.101 | 675 MB/s | 3850 MB/s | +| snappy 1.2.1 | 2.089 | 520 MB/s | 1500 MB/s | +| lzf 3.6 -1 | 2.077 | 410 MB/s | 820 MB/s | [zlib]: https://www.zlib.net/ [lz4]: https://lz4.github.io/lz4/ From 6af3842118ea5325480b403213b2a9fbed3d3d74 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 19 Feb 2025 16:25:00 -0800 Subject: [PATCH 003/245] updated man pages and manual fixes #4301 --- doc/zstd_manual.html | 55 ++++---- programs/zstd.1 | 292 +++++++++++++++++++++++++++++++++++-------- programs/zstdgrep.1 | 2 +- programs/zstdless.1 | 2 +- 4 files changed, 273 insertions(+), 78 deletions(-) diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html index 485d5eafb..89f0761f4 100644 --- a/doc/zstd_manual.html +++ b/doc/zstd_manual.html @@ -110,6 +110,7 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize); - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) note 1 : a 0 return value means the frame is valid but "empty". + When invoking this method on a skippable frame, it will return 0. note 2 : decompressed size is an optional field, it may not be present (typically in streaming mode). When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. In which case, it's necessary to use streaming mode to decompress data. @@ -128,9 +129,8 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);


ZSTD_DEPRECATED("Replaced by ZSTD_getFrameContentSize")
-ZSTDLIB_API
 unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
-

NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize(). +

This function is now obsolete, in favor of ZSTD_getFrameContentSize(). Both functions work the same way, but ZSTD_getDecompressedSize() blends "empty", "unknown" and "error" results to the same return value (0), while ZSTD_getFrameContentSize() gives them separate return values. @@ -142,7 +142,12 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); `srcSize` must be >= first frame size @return : the compressed size of the first frame starting at `src`, suitable to pass as `srcSize` to `ZSTD_decompress` or similar, - or an error code if input is invalid + or an error code if input is invalid + Note 1: this method is called _find*() because it's not enough to read the header, + it may have to scan through the frame's content, to reach its end. + Note 2: this method also works with Skippable Frames. In which case, + it returns the size of the complete skippable frame, + which is always equal to its content size + 8 bytes for headers.


Compression helper functions


@@ -166,8 +171,7 @@ size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in w


-

Error helper functions

#include "zstd_errors.h" /* list of errors */
-/* ZSTD_isError() :
+

Error helper functions

/* ZSTD_isError() :
  * Most ZSTD_* functions returning a size_t value can be tested for error,
  * using ZSTD_isError().
  * @return 1 if error, 0 otherwise
@@ -1239,7 +1243,7 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
 


ZSTDLIB_STATIC_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize);
-

srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX. +

srcSize must be large enough, aka >= ZSTD_FRAMEHEADERSIZE_PREFIX. @return : size of the Frame Header, or an error code (if srcSize is too small)


@@ -1252,20 +1256,20 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); unsigned blockSizeMax; ZSTD_FrameType_e frameType;
/* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */ unsigned headerSize; - unsigned dictID; + unsigned dictID; /* for ZSTD_skippableFrame, contains the skippable magic variant [0-15] */ unsigned checksumFlag; unsigned _reserved1; unsigned _reserved2; -} ZSTD_frameHeader; +} ZSTD_FrameHeader;

-
ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader(ZSTD_FrameHeader* zfhPtr, const void* src, size_t srcSize);   /**< doesn't consume input */
+
ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader(ZSTD_FrameHeader* zfhPtr, const void* src, size_t srcSize);
 /*! ZSTD_getFrameHeader_advanced() :
  *  same as ZSTD_getFrameHeader(),
  *  with added capability to select a format (like ZSTD_f_zstd1_magicless) */
 ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader_advanced(ZSTD_FrameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format);
-

decode Frame Header, or requires larger `srcSize`. - @return : 0, `zfhPtr` is correctly filled, - >0, `srcSize` is too small, value is wanted `srcSize` amount, +

decode Frame Header into `zfhPtr`, or requires larger `srcSize`. + @return : 0 => header is complete, `zfhPtr` is correctly filled, + >0 => `srcSize` is too small, @return value is the wanted `srcSize` amount, `zfhPtr` is not filled, or an error code, which can be tested using ZSTD_isError()


@@ -1421,7 +1425,7 @@ ZSTD_compressSequences(ZSTD_CCtx* cctx, ZSTD_compressSequencesAndLiterals(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const ZSTD_Sequence* inSeqs, size_t nbSequences, - const void* literals, size_t litSize, size_t litCapacity, + const void* literals, size_t litSize, size_t litBufCapacity, size_t decompressedSize);

This is a variant of ZSTD_compressSequences() which, instead of receiving (src,srcSize) as input parameter, receives (literals,litSize), @@ -1435,20 +1439,22 @@ ZSTD_compressSequencesAndLiterals(ZSTD_CCtx* cctx, - Not compatible with frame checksum, which must be disabled - If any block is incompressible, will fail and return an error - @litSize must be == sum of all @.litLength fields in @inSeqs. Any discrepancy will generate an error. - - the buffer @literals must have a size @litCapacity which is larger than @litSize by at least 8 bytes. + - @litBufCapacity is the size of the underlying buffer into which literals are written, starting at address @literals. + @litBufCapacity must be at least 8 bytes larger than @litSize. - @decompressedSize must be correct, and correspond to the sum of all Sequences. Any discrepancy will generate an error. @return : final compressed size, or a ZSTD error code.


ZSTDLIB_STATIC_API size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity,
-                                const void* src, size_t srcSize, unsigned magicVariant);
+                                 const void* src, size_t srcSize,
+                                       unsigned magicVariant);
 

Generates a zstd skippable frame containing data given by src, and writes it to dst buffer. Skippable frames begin with a 4-byte magic number. There are 16 possible choices of magic number, ranging from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15. - As such, the parameter magicVariant controls the exact skippable frame magic number variant used, so - the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant. + As such, the parameter magicVariant controls the exact skippable frame magic number variant used, + so the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant. Returns an error if destination buffer is not large enough, if the source size is not representable with a 4-byte unsigned int, or if the parameter magicVariant is greater than 15 (and therefore invalid). @@ -1457,13 +1463,14 @@ ZSTD_compressSequencesAndLiterals(ZSTD_CCtx* cctx,


-
size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant,
-                                const void* src, size_t srcSize);
-

Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer. +

ZSTDLIB_STATIC_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity,
+                                      unsigned* magicVariant,
+                                      const void* src, size_t srcSize);
+

Retrieves the content of a zstd skippable frame starting at @src, and writes it to @dst buffer. - The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, - i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested - in the magicVariant. + The parameter @magicVariant will receive the magicVariant that was supplied when the frame was written, + i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. + This can be NULL if the caller is not interested in the magicVariant. Returns an error if destination buffer is not large enough, or if the frame is not skippable. @@ -1471,7 +1478,7 @@ ZSTD_compressSequencesAndLiterals(ZSTD_CCtx* cctx,


-
unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size);
+
ZSTDLIB_STATIC_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size);
 

Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame.


diff --git a/programs/zstd.1 b/programs/zstd.1 index 5f1519f33..5503a5b86 100644 --- a/programs/zstd.1 +++ b/programs/zstd.1 @@ -1,392 +1,580 @@ -.TH "ZSTD" "1" "October 2024" "zstd 1.5.6" "User Commands" +. +.TH "ZSTD" "1" "February 2025" "zstd 1.5.7" "User Commands" +. .SH "NAME" \fBzstd\fR \- zstd, zstdmt, unzstd, zstdcat \- Compress or decompress \.zst files +. .SH "SYNOPSIS" -.TS -allbox; -\fBzstd\fR [\fIOPTIONS\fR] [\- \fIINPUT\-FILE\fR] [\-o \fIOUTPUT\-FILE\fR] -.TE +\fBzstd\fR [\fIOPTIONS\fR] [\-|\fIINPUT\-FILE\fR] [\-o \fIOUTPUT\-FILE\fR] +. .P \fBzstdmt\fR is equivalent to \fBzstd \-T0\fR +. .P \fBunzstd\fR is equivalent to \fBzstd \-d\fR +. .P \fBzstdcat\fR is equivalent to \fBzstd \-dcf\fR +. .SH "DESCRIPTION" \fBzstd\fR is a fast lossless compression algorithm and data compression tool, with command line syntax similar to \fBgzip\fR(1) and \fBxz\fR(1)\. It is based on the \fBLZ77\fR family, with further FSE & huff0 entropy stages\. \fBzstd\fR offers highly configurable compression speed, from fast modes at > 200 MB/s per core, to strong modes with excellent compression ratios\. It also features a very fast decoder, with speeds > 500 MB/s per core, which remains roughly stable at all compression settings\. +. .P \fBzstd\fR command line syntax is generally similar to gzip, but features the following few differences: +. .IP "\(bu" 4 -Source files are preserved by default\. It's possible to remove them automatically by using the \fB\-\-rm\fR command\. +Source files are preserved by default\. It\'s possible to remove them automatically by using the \fB\-\-rm\fR command\. +. .IP "\(bu" 4 When compressing a single file, \fBzstd\fR displays progress notifications and result summary by default\. Use \fB\-q\fR to turn them off\. +. .IP "\(bu" 4 \fBzstd\fR displays a short help page when command line is an error\. Use \fB\-q\fR to turn it off\. +. .IP "\(bu" 4 -\fBzstd\fR does not accept input from console, though it does accept \fBstdin\fR when it's not the console\. +\fBzstd\fR does not accept input from console, though it does accept \fBstdin\fR when it\'s not the console\. +. .IP "\(bu" 4 -\fBzstd\fR does not store the input's filename or attributes, only its contents\. +\fBzstd\fR does not store the input\'s filename or attributes, only its contents\. +. .IP "" 0 +. .P \fBzstd\fR processes each \fIfile\fR according to the selected operation mode\. If no \fIfiles\fR are given or \fIfile\fR is \fB\-\fR, \fBzstd\fR reads from standard input and writes the processed data to standard output\. \fBzstd\fR will refuse to write compressed data to standard output if it is a terminal: it will display an error message and skip the file\. Similarly, \fBzstd\fR will refuse to read compressed data from standard input if it is a terminal\. +. .P Unless \fB\-\-stdout\fR or \fB\-o\fR is specified, \fIfiles\fR are written to a new file whose name is derived from the source \fIfile\fR name: +. .IP "\(bu" 4 When compressing, the suffix \fB\.zst\fR is appended to the source filename to get the target filename\. +. .IP "\(bu" 4 When decompressing, the \fB\.zst\fR suffix is removed from the source filename to get the target filename +. .IP "" 0 +. .SS "Concatenation with \.zst Files" It is possible to concatenate multiple \fB\.zst\fR files\. \fBzstd\fR will decompress such agglomerated file as if it was a single \fB\.zst\fR file\. +. .SH "OPTIONS" +. .SS "Integer Suffixes and Special Values" In most places where an integer argument is expected, an optional suffix is supported to easily indicate large integers\. There must be no space between the integer and the suffix\. +. .TP \fBKiB\fR -Multiply the integer by 1,024 (2\e^10)\. \fBKi\fR, \fBK\fR, and \fBKB\fR are accepted as synonyms for \fBKiB\fR\. +Multiply the integer by 1,024 (2^10)\. \fBKi\fR, \fBK\fR, and \fBKB\fR are accepted as synonyms for \fBKiB\fR\. +. .TP \fBMiB\fR -Multiply the integer by 1,048,576 (2\e^20)\. \fBMi\fR, \fBM\fR, and \fBMB\fR are accepted as synonyms for \fBMiB\fR\. +Multiply the integer by 1,048,576 (2^20)\. \fBMi\fR, \fBM\fR, and \fBMB\fR are accepted as synonyms for \fBMiB\fR\. +. .SS "Operation Mode" If multiple operation mode options are given, the last one takes effect\. +. .TP \fB\-z\fR, \fB\-\-compress\fR Compress\. This is the default operation mode when no operation mode option is specified and no other operation mode is implied from the command name (for example, \fBunzstd\fR implies \fB\-\-decompress\fR)\. +. .TP \fB\-d\fR, \fB\-\-decompress\fR, \fB\-\-uncompress\fR Decompress\. +. .TP \fB\-t\fR, \fB\-\-test\fR Test the integrity of compressed \fIfiles\fR\. This option is equivalent to \fB\-\-decompress \-\-stdout > /dev/null\fR, decompressed data is discarded and checksummed for errors\. No files are created or removed\. +. .TP \fB\-b#\fR Benchmark file(s) using compression level \fI#\fR\. See \fIBENCHMARK\fR below for a description of this operation\. +. .TP \fB\-\-train FILES\fR Use \fIFILES\fR as a training set to create a dictionary\. The training set should contain a lot of small files (> 100)\. See \fIDICTIONARY BUILDER\fR below for a description of this operation\. +. .TP \fB\-l\fR, \fB\-\-list\fR -Display information related to a zstd compressed file, such as size, ratio, and checksum\. Some of these fields may not be available\. This command's output can be augmented with the \fB\-v\fR modifier\. +Display information related to a zstd compressed file, such as size, ratio, and checksum\. Some of these fields may not be available\. This command\'s output can be augmented with the \fB\-v\fR modifier\. +. .SS "Operation Modifiers" +. .IP "\(bu" 4 -\fB\-#\fR: selects \fB#\fR compression level [1\-19] (default: 3)\. Higher compression levels \fIgenerally\fR produce higher compression ratio at the expense of speed and memory\. A rough rule of thumb is that compression speed is expected to be divided by 2 every 2 levels\. Technically, each level is mapped to a set of advanced parameters (that can also be modified individually, see below)\. Because the compressor's behavior highly depends on the content to compress, there's no guarantee of a smooth progression from one level to another\. +\fB\-#\fR: selects \fB#\fR compression level [1\-19] (default: 3)\. Higher compression levels \fIgenerally\fR produce higher compression ratio at the expense of speed and memory\. A rough rule of thumb is that compression speed is expected to be divided by 2 every 2 levels\. Technically, each level is mapped to a set of advanced parameters (that can also be modified individually, see below)\. Because the compressor\'s behavior highly depends on the content to compress, there\'s no guarantee of a smooth progression from one level to another\. +. .IP "\(bu" 4 \fB\-\-ultra\fR: unlocks high compression levels 20+ (maximum 22), using a lot more memory\. Note that decompression will also require more memory when using these levels\. +. .IP "\(bu" 4 \fB\-\-fast[=#]\fR: switch to ultra\-fast compression levels\. If \fB=#\fR is not present, it defaults to \fB1\fR\. The higher the value, the faster the compression speed, at the cost of some compression ratio\. This setting overwrites compression level if one was set previously\. Similarly, if a compression level is set after \fB\-\-fast\fR, it overrides it\. +. .IP "\(bu" 4 \fB\-T#\fR, \fB\-\-threads=#\fR: Compress using \fB#\fR working threads (default: 1)\. If \fB#\fR is 0, attempt to detect and use the number of physical CPU cores\. In all cases, the nb of threads is capped to \fBZSTDMT_NBWORKERS_MAX\fR, which is either 64 in 32\-bit mode, or 256 for 64\-bit environments\. This modifier does nothing if \fBzstd\fR is compiled without multithread support\. +. .IP "\(bu" 4 \fB\-\-single\-thread\fR: Use a single thread for both I/O and compression\. As compression is serialized with I/O, this can be slightly slower\. Single\-thread mode features significantly lower memory usage, which can be useful for systems with limited amount of memory, such as 32\-bit systems\. +. .IP Note 1: this mode is the only available one when multithread support is disabled\. +. .IP Note 2: this mode is different from \fB\-T1\fR, which spawns 1 compression thread in parallel with I/O\. Final compressed result is also slightly different from \fB\-T1\fR\. +. .IP "\(bu" 4 \fB\-\-auto\-threads={physical,logical} (default: physical)\fR: When using a default amount of threads via \fB\-T0\fR, choose the default based on the number of detected physical or logical cores\. +. .IP "\(bu" 4 \fB\-\-adapt[=min=#,max=#]\fR: \fBzstd\fR will dynamically adapt compression level to perceived I/O conditions\. Compression level adaptation can be observed live by using command \fB\-v\fR\. Adaptation can be constrained between supplied \fBmin\fR and \fBmax\fR levels\. The feature works when combined with multi\-threading and \fB\-\-long\fR mode\. It does not work with \fB\-\-single\-thread\fR\. It sets window size to 8 MiB by default (can be changed manually, see \fBwlog\fR)\. Due to the chaotic nature of dynamic adaptation, compressed result is not reproducible\. +. .IP \fINote\fR: at the time of this writing, \fB\-\-adapt\fR can remain stuck at low speed when combined with multiple worker threads (>=2)\. +. .IP "\(bu" 4 \fB\-\-long[=#]\fR: enables long distance matching with \fB#\fR \fBwindowLog\fR, if \fB#\fR is not present it defaults to \fB27\fR\. This increases the window size (\fBwindowLog\fR) and memory usage for both the compressor and decompressor\. This setting is designed to improve the compression ratio for files with long matches at a large distance\. +. .IP Note: If \fBwindowLog\fR is set to larger than 27, \fB\-\-long=windowLog\fR or \fB\-\-memory=windowSize\fR needs to be passed to the decompressor\. +. +.IP "\(bu" 4 +\fB\-\-max\fR: set advanced parameters to maximum compression\. warning: this setting is very slow and uses a lot of resources\. It\'s inappropriate for 32\-bit mode and therefore disabled in this mode\. +. .IP "\(bu" 4 \fB\-D DICT\fR: use \fBDICT\fR as Dictionary to compress or decompress FILE(s) +. .IP "\(bu" 4 -\fB\-\-patch\-from FILE\fR: Specify the file to be used as a reference point for zstd's diff engine\. This is effectively dictionary compression with some convenient parameter selection, namely that \fIwindowSize\fR > \fIsrcSize\fR\. +\fB\-\-patch\-from FILE\fR: Specify the file to be used as a reference point for zstd\'s diff engine\. This is effectively dictionary compression with some convenient parameter selection, namely that \fIwindowSize\fR > \fIsrcSize\fR\. +. .IP Note: cannot use both this and \fB\-D\fR together\. +. .IP Note: \fB\-\-long\fR mode will be automatically activated if \fIchainLog\fR < \fIfileLog\fR (\fIfileLog\fR being the \fIwindowLog\fR required to cover the whole file)\. You can also manually force it\. +. .IP -Note: up to level 15, you can use \fB\-\-patch\-from\fR in \fB\-\-single\-thread\fR mode to improve compression ratio marginally at the cost of speed\. Using '\-\-single\-thread' above level 15 will lead to lower compression ratios\. +Note: up to level 15, you can use \fB\-\-patch\-from\fR in \fB\-\-single\-thread\fR mode to improve compression ratio marginally at the cost of speed\. Using \'\-\-single\-thread\' above level 15 will lead to lower compression ratios\. +. .IP Note: for level 19, you can get increased compression ratio at the cost of speed by specifying \fB\-\-zstd=targetLength=\fR to be something large (i\.e\. 4096), and by setting a large \fB\-\-zstd=chainLog=\fR\. +. .IP "\(bu" 4 -\fB\-\-rsyncable\fR: \fBzstd\fR will periodically synchronize the compression state to make the compressed file more rsync\-friendly\. There is a negligible impact to compression ratio, and a potential impact to compression speed, perceptible at higher speeds, for example when combining \fB\-\-rsyncable\fR with many parallel worker threads\. This feature does not work with \fB\-\-single\-thread\fR\. You probably don't want to use it with long range mode, since it will decrease the effectiveness of the synchronization points, but your mileage may vary\. +\fB\-\-rsyncable\fR: \fBzstd\fR will periodically synchronize the compression state to make the compressed file more rsync\-friendly\. There is a negligible impact to compression ratio, and a potential impact to compression speed, perceptible at higher speeds, for example when combining \fB\-\-rsyncable\fR with many parallel worker threads\. This feature does not work with \fB\-\-single\-thread\fR\. You probably don\'t want to use it with long range mode, since it will decrease the effectiveness of the synchronization points, but your mileage may vary\. +. .IP "\(bu" 4 \fB\-C\fR, \fB\-\-[no\-]check\fR: add integrity check computed from uncompressed data (default: enabled) +. .IP "\(bu" 4 \fB\-\-[no\-]content\-size\fR: enable / disable whether or not the original size of the file is placed in the header of the compressed file\. The default option is \fB\-\-content\-size\fR (meaning that the original size will be placed in the header)\. +. .IP "\(bu" 4 -\fB\-\-no\-dictID\fR: do not store dictionary ID within frame header (dictionary compression)\. The decoder will have to rely on implicit knowledge about which dictionary to use, it won't be able to check if it's correct\. +\fB\-\-no\-dictID\fR: do not store dictionary ID within frame header (dictionary compression)\. The decoder will have to rely on implicit knowledge about which dictionary to use, it won\'t be able to check if it\'s correct\. +. .IP "\(bu" 4 \fB\-M#\fR, \fB\-\-memory=#\fR: Set a memory usage limit\. By default, \fBzstd\fR uses 128 MiB for decompression as the maximum amount of memory the decompressor is allowed to use, but you can override this manually if need be in either direction (i\.e\. you can increase or decrease it)\. +. .IP This is also used during compression when using with \fB\-\-patch\-from=\fR\. In this case, this parameter overrides that maximum size allowed for a dictionary\. (128 MiB)\. +. .IP Additionally, this can be used to limit memory for dictionary training\. This parameter overrides the default limit of 2 GiB\. zstd will load training samples up to the memory limit and ignore the rest\. +. .IP "\(bu" 4 \fB\-\-stream\-size=#\fR: Sets the pledged source size of input coming from a stream\. This value must be exact, as it will be included in the produced frame header\. Incorrect stream sizes will cause an error\. This information will be used to better optimize compression parameters, resulting in better and potentially faster compression, especially for smaller source sizes\. +. .IP "\(bu" 4 \fB\-\-size\-hint=#\fR: When handling input from a stream, \fBzstd\fR must guess how large the source size will be when optimizing compression parameters\. If the stream size is relatively small, this guess may be a poor one, resulting in a higher compression ratio than expected\. This feature allows for controlling the guess when needed\. Exact guesses result in better compression ratios\. Overestimates result in slightly degraded compression ratios, while underestimates may result in significant degradation\. +. .IP "\(bu" 4 \fB\-\-target\-compressed\-block\-size=#\fR: Attempt to produce compressed blocks of approximately this size\. This will split larger blocks in order to approach this target\. This feature is notably useful for improved latency, when the receiver can leverage receiving early incomplete data\. This parameter defines a loose target: compressed blocks will target this size "on average", but individual blocks can still be larger or smaller\. Enabling this feature can decrease compression speed by up to ~10% at level 1\. Higher levels will see smaller relative speed regression, becoming invisible at higher settings\. +. .IP "\(bu" 4 \fB\-f\fR, \fB\-\-force\fR: disable input and output checks\. Allows overwriting existing files, input from console, output to stdout, operating on links, block devices, etc\. During decompression and when the output destination is stdout, pass\-through unrecognized formats as\-is\. +. .IP "\(bu" 4 \fB\-c\fR, \fB\-\-stdout\fR: write to standard output (even if it is the console); keep original files (disable \fB\-\-rm\fR)\. +. .IP "\(bu" 4 \fB\-o FILE\fR: save result into \fBFILE\fR\. Note that this operation is in conflict with \fB\-c\fR\. If both operations are present on the command line, the last expressed one wins\. +. .IP "\(bu" 4 \fB\-\-[no\-]sparse\fR: enable / disable sparse FS support, to make files with many zeroes smaller on disk\. Creating sparse files may save disk space and speed up decompression by reducing the amount of disk I/O\. default: enabled when output is into a file, and disabled when output is stdout\. This setting overrides default and can force sparse mode over stdout\. +. .IP "\(bu" 4 \fB\-\-[no\-]pass\-through\fR enable / disable passing through uncompressed files as\-is\. During decompression when pass\-through is enabled, unrecognized formats will be copied as\-is from the input to the output\. By default, pass\-through will occur when the output destination is stdout and the force (\fB\-f\fR) option is set\. +. .IP "\(bu" 4 \fB\-\-rm\fR: remove source file(s) after successful compression or decompression\. This command is silently ignored if output is \fBstdout\fR\. If used in combination with \fB\-o\fR, triggers a confirmation prompt (which can be silenced with \fB\-f\fR), as this is a destructive operation\. +. .IP "\(bu" 4 \fB\-k\fR, \fB\-\-keep\fR: keep source file(s) after successful compression or decompression\. This is the default behavior\. +. .IP "\(bu" 4 \fB\-r\fR: operate recursively on directories\. It selects all files in the named directory and all its subdirectories\. This can be useful both to reduce command line typing, and to circumvent shell expansion limitations, when there are a lot of files and naming breaks the maximum size of a command line\. +. .IP "\(bu" 4 \fB\-\-filelist FILE\fR read a list of files to process as content from \fBFILE\fR\. Format is compatible with \fBls\fR output, with one file per line\. +. .IP "\(bu" 4 \fB\-\-output\-dir\-flat DIR\fR: resulting files are stored into target \fBDIR\fR directory, instead of same directory as origin file\. Be aware that this command can introduce name collision issues, if multiple files, from different directories, end up having the same name\. Collision resolution ensures first file with a given name will be present in \fBDIR\fR, while in combination with \fB\-f\fR, the last file will be present instead\. +. .IP "\(bu" 4 \fB\-\-output\-dir\-mirror DIR\fR: similar to \fB\-\-output\-dir\-flat\fR, the output files are stored underneath target \fBDIR\fR directory, but this option will replicate input directory hierarchy into output \fBDIR\fR\. +. .IP If input directory contains "\.\.", the files in this directory will be ignored\. If input directory is an absolute directory (i\.e\. "/var/tmp/abc"), it will be stored into the "output\-dir/var/tmp/abc"\. If there are multiple input files or directories, name collision resolution will follow the same rules as \fB\-\-output\-dir\-flat\fR\. +. .IP "\(bu" 4 \fB\-\-format=FORMAT\fR: compress and decompress in other formats\. If compiled with support, zstd can compress to or decompress from other compression algorithm formats\. Possibly available options are \fBzstd\fR, \fBgzip\fR, \fBxz\fR, \fBlzma\fR, and \fBlz4\fR\. If no such format is provided, \fBzstd\fR is the default\. +. .IP "\(bu" 4 \fB\-h\fR/\fB\-H\fR, \fB\-\-help\fR: display help/long help and exit +. .IP "\(bu" 4 \fB\-V\fR, \fB\-\-version\fR: display version number and immediately exit\. note that, since it exits, flags specified after \fB\-V\fR are effectively ignored\. Advanced: \fB\-vV\fR also displays supported formats\. \fB\-vvV\fR also displays POSIX support\. \fB\-qV\fR will only display the version number, suitable for machine reading\. +. .IP "\(bu" 4 \fB\-v\fR, \fB\-\-verbose\fR: verbose mode, display more information +. .IP "\(bu" 4 \fB\-q\fR, \fB\-\-quiet\fR: suppress warnings, interactivity, and notifications\. specify twice to suppress errors too\. +. .IP "\(bu" 4 \fB\-\-no\-progress\fR: do not display the progress bar, but keep all other messages\. +. .IP "\(bu" 4 \fB\-\-show\-default\-cparams\fR: shows the default compression parameters that will be used for a particular input file, based on the provided compression level and the input size\. If the provided file is not a regular file (e\.g\. a pipe), this flag will output the parameters used for inputs of unknown size\. +. .IP "\(bu" 4 \fB\-\-exclude\-compressed\fR: only compress files that are not already compressed\. +. .IP "\(bu" 4 \fB\-\-\fR: All arguments after \fB\-\-\fR are treated as files +. .IP "" 0 +. .SS "gzip Operation Modifiers" When invoked via a \fBgzip\fR symlink, \fBzstd\fR will support further options that intend to mimic the \fBgzip\fR behavior: +. .TP \fB\-n\fR, \fB\-\-no\-name\fR do not store the original filename and timestamps when compressing a file\. This is the default behavior and hence a no\-op\. +. .TP \fB\-\-best\fR alias to the option \fB\-9\fR\. +. .SS "Environment Variables" Employing environment variables to set parameters has security implications\. Therefore, this avenue is intentionally limited\. Only \fBZSTD_CLEVEL\fR and \fBZSTD_NBTHREADS\fR are currently supported\. They set the default compression level and number of threads to use during compression, respectively\. +. .P \fBZSTD_CLEVEL\fR can be used to set the level between 1 and 19 (the "normal" range)\. If the value of \fBZSTD_CLEVEL\fR is not a valid integer, it will be ignored with a warning message\. \fBZSTD_CLEVEL\fR just replaces the default compression level (\fB3\fR)\. +. .P -\fBZSTD_NBTHREADS\fR can be used to set the number of threads \fBzstd\fR will attempt to use during compression\. If the value of \fBZSTD_NBTHREADS\fR is not a valid unsigned integer, it will be ignored with a warning message\. \fBZSTD_NBTHREADS\fR has a default value of (\fB1\fR), and is capped at ZSTDMT_NBWORKERS_MAX==200\. \fBzstd\fR must be compiled with multithread support for this variable to have any effect\. +\fBZSTD_NBTHREADS\fR can be used to set the number of threads \fBzstd\fR will attempt to use during compression\. If the value of \fBZSTD_NBTHREADS\fR is not a valid unsigned integer, it will be ignored with a warning message\. \fBZSTD_NBTHREADS\fR has a default value of \fBmax(1, min(4, nbCores/4))\fR, and is capped at ZSTDMT_NBWORKERS_MAX==200\. \fBzstd\fR must be compiled with multithread support for this variable to have any effect\. +. .P They can both be overridden by corresponding command line arguments: \fB\-#\fR for compression level and \fB\-T#\fR for number of compression threads\. +. .SH "ADVANCED COMPRESSION OPTIONS" \fBzstd\fR provides 22 predefined regular compression levels plus the fast levels\. A compression level is translated internally into multiple advanced parameters that control the behavior of the compressor (one can observe the result of this translation with \fB\-\-show\-default\-cparams\fR)\. These advanced parameters can be overridden using advanced compression options\. +. .SS "\-\-zstd[=options]:" The \fIoptions\fR are provided as a comma\-separated list\. You may specify only the options you want to change and the rest will be taken from the selected or default compression level\. The list of available \fIoptions\fR: +. .TP \fBstrategy\fR=\fIstrat\fR, \fBstrat\fR=\fIstrat\fR Specify a strategy used by a match finder\. +. .IP There are 9 strategies numbered from 1 to 9, from fastest to strongest: 1=\fBZSTD_fast\fR, 2=\fBZSTD_dfast\fR, 3=\fBZSTD_greedy\fR, 4=\fBZSTD_lazy\fR, 5=\fBZSTD_lazy2\fR, 6=\fBZSTD_btlazy2\fR, 7=\fBZSTD_btopt\fR, 8=\fBZSTD_btultra\fR, 9=\fBZSTD_btultra2\fR\. +. .TP \fBwindowLog\fR=\fIwlog\fR, \fBwlog\fR=\fIwlog\fR Specify the maximum number of bits for a match distance\. +. .IP The higher number of increases the chance to find a match which usually improves compression ratio\. It also increases memory requirements for the compressor and decompressor\. The minimum \fIwlog\fR is 10 (1 KiB) and the maximum is 30 (1 GiB) on 32\-bit platforms and 31 (2 GiB) on 64\-bit platforms\. +. .IP Note: If \fBwindowLog\fR is set to larger than 27, \fB\-\-long=windowLog\fR or \fB\-\-memory=windowSize\fR needs to be passed to the decompressor\. +. .TP \fBhashLog\fR=\fIhlog\fR, \fBhlog\fR=\fIhlog\fR Specify the maximum number of bits for a hash table\. +. .IP Bigger hash tables cause fewer collisions which usually makes compression faster, but requires more memory during compression\. +. .IP The minimum \fIhlog\fR is 6 (64 entries / 256 B) and the maximum is 30 (1B entries / 4 GiB)\. +. .TP \fBchainLog\fR=\fIclog\fR, \fBclog\fR=\fIclog\fR Specify the maximum number of bits for the secondary search structure, whose form depends on the selected \fBstrategy\fR\. +. .IP Higher numbers of bits increases the chance to find a match which usually improves compression ratio\. It also slows down compression speed and increases memory requirements for compression\. This option is ignored for the \fBZSTD_fast\fR \fBstrategy\fR, which only has the primary hash table\. +. .IP The minimum \fIclog\fR is 6 (64 entries / 256 B) and the maximum is 29 (512M entries / 2 GiB) on 32\-bit platforms and 30 (1B entries / 4 GiB) on 64\-bit platforms\. +. .TP \fBsearchLog\fR=\fIslog\fR, \fBslog\fR=\fIslog\fR Specify the maximum number of searches in a hash chain or a binary tree using logarithmic scale\. +. .IP More searches increases the chance to find a match which usually increases compression ratio but decreases compression speed\. +. .IP -The minimum \fIslog\fR is 1 and the maximum is 'windowLog' \- 1\. +The minimum \fIslog\fR is 1 and the maximum is \'windowLog\' \- 1\. +. .TP \fBminMatch\fR=\fImml\fR, \fBmml\fR=\fImml\fR Specify the minimum searched length of a match in a hash table\. +. .IP Larger search lengths usually decrease compression ratio but improve decompression speed\. +. .IP The minimum \fImml\fR is 3 and the maximum is 7\. +. .TP \fBtargetLength\fR=\fItlen\fR, \fBtlen\fR=\fItlen\fR The impact of this field vary depending on selected strategy\. +. .IP For \fBZSTD_btopt\fR, \fBZSTD_btultra\fR and \fBZSTD_btultra2\fR, it specifies the minimum match length that causes match finder to stop searching\. A larger \fBtargetLength\fR usually improves compression ratio but decreases compression speed\. +. .IP For \fBZSTD_fast\fR, it triggers ultra\-fast mode when > 0\. The value represents the amount of data skipped between match sampling\. Impact is reversed: a larger \fBtargetLength\fR increases compression speed but decreases compression ratio\. +. .IP For all other strategies, this field has no impact\. +. .IP The minimum \fItlen\fR is 0 and the maximum is 128 KiB\. +. .TP \fBoverlapLog\fR=\fIovlog\fR, \fBovlog\fR=\fIovlog\fR Determine \fBoverlapSize\fR, amount of data reloaded from previous job\. This parameter is only available when multithreading is enabled\. Reloading more data improves compression ratio, but decreases speed\. +. .IP The minimum \fIovlog\fR is 0, and the maximum is 9\. 1 means "no overlap", hence completely independent jobs\. 9 means "full overlap", meaning up to \fBwindowSize\fR is reloaded from previous job\. Reducing \fIovlog\fR by 1 reduces the reloaded amount by a factor 2\. For example, 8 means "windowSize/2", and 6 means "windowSize/8"\. Value 0 is special and means "default": \fIovlog\fR is automatically determined by \fBzstd\fR\. In which case, \fIovlog\fR will range from 6 to 9, depending on selected \fIstrat\fR\. -.TP -\fBldmHashLog\fR=\fIlhlog\fR, \fBlhlog\fR=\fIlhlog\fR -Specify the maximum size for a hash table used for long distance matching\. -.IP -This option is ignored unless long distance matching is enabled\. -.IP -Bigger hash tables usually improve compression ratio at the expense of more memory during compression and a decrease in compression speed\. -.IP -The minimum \fIlhlog\fR is 6 and the maximum is 30 (default: 20)\. -.TP -\fBldmMinMatch\fR=\fIlmml\fR, \fBlmml\fR=\fIlmml\fR -Specify the minimum searched length of a match for long distance matching\. -.IP -This option is ignored unless long distance matching is enabled\. -.IP -Larger/very small values usually decrease compression ratio\. -.IP -The minimum \fIlmml\fR is 4 and the maximum is 4096 (default: 64)\. -.TP -\fBldmBucketSizeLog\fR=\fIlblog\fR, \fBlblog\fR=\fIlblog\fR -Specify the size of each bucket for the hash table used for long distance matching\. -.IP -This option is ignored unless long distance matching is enabled\. -.IP -Larger bucket sizes improve collision resolution but decrease compression speed\. -.IP -The minimum \fIlblog\fR is 1 and the maximum is 8 (default: 3)\. +. .TP \fBldmHashRateLog\fR=\fIlhrlog\fR, \fBlhrlog\fR=\fIlhrlog\fR Specify the frequency of inserting entries into the long distance matching hash table\. +. .IP This option is ignored unless long distance matching is enabled\. +. .IP Larger values will improve compression speed\. Deviating far from the default value will likely result in a decrease in compression ratio\. +. .IP -The default value is \fBwlog \- lhlog\fR\. +The default value varies between 4 and 7, depending on \fBstrategy\fR\. +. +.TP +\fBldmHashLog\fR=\fIlhlog\fR, \fBlhlog\fR=\fIlhlog\fR +Specify the maximum size for a hash table used for long distance matching\. +. +.IP +This option is ignored unless long distance matching is enabled\. +. +.IP +Bigger hash tables usually improve compression ratio at the expense of more memory during compression and a decrease in compression speed\. +. +.IP +The minimum \fIlhlog\fR is 6 and the maximum is 30 (default: \fBwindowLog \- ldmHashRateLog\fR)\. +. +.TP +\fBldmMinMatch\fR=\fIlmml\fR, \fBlmml\fR=\fIlmml\fR +Specify the minimum searched length of a match for long distance matching\. +. +.IP +This option is ignored unless long distance matching is enabled\. +. +.IP +Larger/very small values usually decrease compression ratio\. +. +.IP +The minimum \fIlmml\fR is 4 and the maximum is 4096 (default: 32 to 64, depending on \fBstrategy\fR)\. +. +.TP +\fBldmBucketSizeLog\fR=\fIlblog\fR, \fBlblog\fR=\fIlblog\fR +Specify the size of each bucket for the hash table used for long distance matching\. +. +.IP +This option is ignored unless long distance matching is enabled\. +. +.IP +Larger bucket sizes improve collision resolution but decrease compression speed\. +. +.IP +The minimum \fIlblog\fR is 1 and the maximum is 8 (default: 4 to 8, depending on \fBstrategy\fR)\. +. .SS "Example" The following parameters sets advanced compression options to something similar to predefined level 19 for files bigger than 256 KB: +. .P \fB\-\-zstd\fR=wlog=23,clog=23,hlog=22,slog=6,mml=3,tlen=48,strat=6 +. .SS "\-B#:" Specify the size of each compression job\. This parameter is only available when multi\-threading is enabled\. Each compression job is run in parallel, so this value indirectly impacts the nb of active threads\. Default job size varies depending on compression level (generally \fB4 * windowSize\fR)\. \fB\-B#\fR makes it possible to manually select a custom size\. Note that job size must respect a minimum value which is enforced transparently\. This minimum is either 512 KB, or \fBoverlapSize\fR, whichever is largest\. Different job sizes will lead to non\-identical compressed frames\. +. .SH "DICTIONARY BUILDER" -\fBzstd\fR offers \fIdictionary\fR compression, which greatly improves efficiency on small files and messages\. It's possible to train \fBzstd\fR with a set of samples, the result of which is saved into a file called a \fBdictionary\fR\. Then, during compression and decompression, reference the same dictionary, using command \fB\-D dictionaryFileName\fR\. Compression of small files similar to the sample set will be greatly improved\. +\fBzstd\fR offers \fIdictionary\fR compression, which greatly improves efficiency on small files and messages\. It\'s possible to train \fBzstd\fR with a set of samples, the result of which is saved into a file called a \fBdictionary\fR\. Then, during compression and decompression, reference the same dictionary, using command \fB\-D dictionaryFileName\fR\. Compression of small files similar to the sample set will be greatly improved\. +. .TP \fB\-\-train FILEs\fR Use FILEs as training set to create a dictionary\. The training set should ideally contain a lot of samples (> 100), and weight typically 100x the target dictionary size (for example, ~10 MB for a 100 KB dictionary)\. \fB\-\-train\fR can be combined with \fB\-r\fR to indicate a directory rather than listing all the files, which can be useful to circumvent shell expansion limits\. +. .IP Since dictionary compression is mostly effective for small files, the expectation is that the training set will only contain small files\. In the case where some samples happen to be large, only the first 128 KiB of these samples will be used for training\. +. .IP \fB\-\-train\fR supports multithreading if \fBzstd\fR is compiled with threading support (default)\. Additional advanced parameters can be specified with \fB\-\-train\-fastcover\fR\. The legacy dictionary builder can be accessed with \fB\-\-train\-legacy\fR\. The slower cover dictionary builder can be accessed with \fB\-\-train\-cover\fR\. Default \fB\-\-train\fR is equivalent to \fB\-\-train\-fastcover=d=8,steps=4\fR\. +. .TP \fB\-o FILE\fR Dictionary saved into \fBFILE\fR (default name: dictionary)\. +. .TP \fB\-\-maxdict=#\fR -Limit dictionary to specified size (default: 112640 bytes)\. As usual, quantities are expressed in bytes by default, and it's possible to employ suffixes (like \fBKB\fR or \fBMB\fR) to specify larger values\. +Limit dictionary to specified size (default: 112640 bytes)\. As usual, quantities are expressed in bytes by default, and it\'s possible to employ suffixes (like \fBKB\fR or \fBMB\fR) to specify larger values\. +. .TP \fB\-#\fR Use \fB#\fR compression level during training (optional)\. Will generate statistics more tuned for selected compression level, resulting in a \fIsmall\fR compression ratio improvement for this level\. +. .TP \fB\-B#\fR Split input files into blocks of size # (default: no split) +. .TP \fB\-M#\fR, \fB\-\-memory=#\fR Limit the amount of sample data loaded for training (default: 2 GB)\. Note that the default (2 GB) is also the maximum\. This parameter can be useful in situations where the training set size is not well controlled and could be potentially very large\. Since speed of the training process is directly correlated to the size of the training sample set, a smaller sample set leads to faster training\. +. .IP In situations where the training set is larger than maximum memory, the CLI will randomly select samples among the available ones, up to the maximum allowed memory budget\. This is meant to improve dictionary relevance by mitigating the potential impact of clustering, such as selecting only files from the beginning of a list sorted by modification date, or sorted by alphabetical order\. The randomization process is deterministic, so training of the same list of files with the same parameters will lead to the creation of the same dictionary\. +. .TP \fB\-\-dictID=#\fR -A dictionary ID is a locally unique ID\. The decoder will use this value to verify it is using the right dictionary\. By default, zstd will create a 4\-bytes random number ID\. It's possible to provide an explicit number ID instead\. It's up to the dictionary manager to not assign twice the same ID to 2 different dictionaries\. Note that short numbers have an advantage: an ID < 256 will only need 1 byte in the compressed frame header, and an ID < 65536 will only need 2 bytes\. This compares favorably to 4 bytes default\. +A dictionary ID is a locally unique ID\. The decoder will use this value to verify it is using the right dictionary\. By default, zstd will create a 4\-bytes random number ID\. It\'s possible to provide an explicit number ID instead\. It\'s up to the dictionary manager to not assign twice the same ID to 2 different dictionaries\. Note that short numbers have an advantage: an ID < 256 will only need 1 byte in the compressed frame header, and an ID < 65536 will only need 2 bytes\. This compares favorably to 4 bytes default\. +. .IP -Note that RFC8878 reserves IDs less than 32768 and greater than or equal to 2\e^31, so they should not be used in public\. +Note that RFC8878 reserves IDs less than 32768 and greater than or equal to 2^31, so they should not be used in public\. +. .TP \fB\-\-train\-cover[=k#,d=#,steps=#,split=#,shrink[=#]]\fR Select parameters for the default dictionary builder algorithm named cover\. If \fId\fR is not specified, then it tries \fId\fR = 6 and \fId\fR = 8\. If \fIk\fR is not specified, then it tries \fIsteps\fR values in the range [50, 2000]\. If \fIsteps\fR is not specified, then the default value of 40 is used\. If \fIsplit\fR is not specified or split <= 0, then the default value of 100 is used\. Requires that \fId\fR <= \fIk\fR\. If \fIshrink\fR flag is not used, then the default value for \fIshrinkDict\fR of 0 is used\. If \fIshrink\fR is not specified, then the default value for \fIshrinkDictMaxRegression\fR of 1 is used\. +. .IP Selects segments of size \fIk\fR with highest score to put in the dictionary\. The score of a segment is computed by the sum of the frequencies of all the subsegments of size \fId\fR\. Generally \fId\fR should be in the range [6, 8], occasionally up to 16, but the algorithm will run faster with d <= \fI8\fR\. Good values for \fIk\fR vary widely based on the input data, but a safe range is [2 * \fId\fR, 2000]\. If \fIsplit\fR is 100, all input samples are used for both training and testing to find optimal \fId\fR and \fIk\fR to build dictionary\. Supports multithreading if \fBzstd\fR is compiled with threading support\. Having \fIshrink\fR enabled takes a truncated dictionary of minimum size and doubles in size until compression ratio of the truncated dictionary is at most \fIshrinkDictMaxRegression%\fR worse than the compression ratio of the largest dictionary\. +. .IP Examples: +. .IP \fBzstd \-\-train\-cover FILEs\fR +. .IP \fBzstd \-\-train\-cover=k=50,d=8 FILEs\fR +. .IP \fBzstd \-\-train\-cover=d=8,steps=500 FILEs\fR +. .IP \fBzstd \-\-train\-cover=k=50 FILEs\fR +. .IP \fBzstd \-\-train\-cover=k=50,split=60 FILEs\fR +. .IP \fBzstd \-\-train\-cover=shrink FILEs\fR +. .IP \fBzstd \-\-train\-cover=shrink=2 FILEs\fR +. .TP \fB\-\-train\-fastcover[=k#,d=#,f=#,steps=#,split=#,accel=#]\fR Same as cover but with extra parameters \fIf\fR and \fIaccel\fR and different default value of split If \fIsplit\fR is not specified, then it tries \fIsplit\fR = 75\. If \fIf\fR is not specified, then it tries \fIf\fR = 20\. Requires that 0 < \fIf\fR < 32\. If \fIaccel\fR is not specified, then it tries \fIaccel\fR = 1\. Requires that 0 < \fIaccel\fR <= 10\. Requires that \fId\fR = 6 or \fId\fR = 8\. +. .IP \fIf\fR is log of size of array that keeps track of frequency of subsegments of size \fId\fR\. The subsegment is hashed to an index in the range [0,2^\fIf\fR \- 1]\. It is possible that 2 different subsegments are hashed to the same index, and they are considered as the same subsegment when computing frequency\. Using a higher \fIf\fR reduces collision but takes longer\. +. .IP Examples: +. .IP \fBzstd \-\-train\-fastcover FILEs\fR +. .IP \fBzstd \-\-train\-fastcover=d=8,f=15,accel=2 FILEs\fR +. .TP \fB\-\-train\-legacy[=selectivity=#]\fR Use legacy dictionary builder algorithm with the given dictionary \fIselectivity\fR (default: 9)\. The smaller the \fIselectivity\fR value, the denser the dictionary, improving its efficiency but reducing its achievable maximum size\. \fB\-\-train\-legacy=s=#\fR is also accepted\. +. .IP Examples: +. .IP \fBzstd \-\-train\-legacy FILEs\fR +. .IP \fBzstd \-\-train\-legacy=selectivity=8 FILEs\fR +. .SH "BENCHMARK" -The \fBzstd\fR CLI provides a benchmarking mode that can be used to easily find suitable compression parameters, or alternatively to benchmark a computer's performance\. \fBzstd \-b [FILE(s)]\fR will benchmark \fBzstd\fR for both compression and decompression using default compression level\. Note that results are very dependent on the content being compressed\. It's possible to pass multiple files to the benchmark, and even a directory with \fB\-r DIRECTORY\fR\. When no \fBFILE\fR is provided, the benchmark will use a procedurally generated \fBlorem ipsum\fR text\. +The \fBzstd\fR CLI provides a benchmarking mode that can be used to easily find suitable compression parameters, or alternatively to benchmark a computer\'s performance\. \fBzstd \-b [FILE(s)]\fR will benchmark \fBzstd\fR for both compression and decompression using default compression level\. Note that results are very dependent on the content being compressed\. +. +.P +It\'s possible to pass multiple files to the benchmark, and even a directory with \fB\-r DIRECTORY\fR\. When no \fBFILE\fR is provided, the benchmark will use a procedurally generated \fBlorem ipsum\fR text\. +. +.P +Benchmarking will employ \fBmax(1, min(4, nbCores/4))\fR worker threads by default in order to match the behavior of the normal CLI I/O\. +. .IP "\(bu" 4 \fB\-b#\fR: benchmark file(s) using compression level # +. .IP "\(bu" 4 \fB\-e#\fR: benchmark file(s) using multiple compression levels, from \fB\-b#\fR to \fB\-e#\fR (inclusive) +. .IP "\(bu" 4 \fB\-d\fR: benchmark decompression speed only (requires providing a zstd\-compressed content) +. .IP "\(bu" 4 \fB\-i#\fR: minimum evaluation time, in seconds (default: 3s), benchmark mode only +. .IP "\(bu" 4 \fB\-B#\fR, \fB\-\-block\-size=#\fR: cut file(s) into independent chunks of size # (default: no chunking) +. .IP "\(bu" 4 \fB\-S\fR: output one benchmark result per input file (default: consolidated result) +. .IP "\(bu" 4 \fB\-D dictionary\fR benchmark using dictionary +. .IP "\(bu" 4 \fB\-\-priority=rt\fR: set process priority to real\-time (Windows) +. .IP "" 0 +. .P Beyond compression levels, benchmarking is also compatible with other parameters, such as number of threads (\fB\-T#\fR), advanced compression parameters (\fB\-\-zstd=###\fR), dictionary compression (\fB\-D dictionary\fR), or even disabling checksum verification for example\. +. .P \fBOutput Format:\fR CompressionLevel#Filename: InputSize \-> OutputSize (CompressionRatio), CompressionSpeed, DecompressionSpeed +. .P \fBMethodology:\fR For speed measurement, the entire input is compressed/decompressed in\-memory to measure speed\. A run lasts at least 1 sec, so when files are small, they are compressed/decompressed several times per run, in order to improve measurement accuracy\. +. .SH "SEE ALSO" \fBzstdgrep\fR(1), \fBzstdless\fR(1), \fBgzip\fR(1), \fBxz\fR(1) +. .P -The \fIzstandard\fR format is specified in Y\. Collet, "Zstandard Compression and the 'application/zstd' Media Type", https://www\.ietf\.org/rfc/rfc8878\.txt, Internet RFC 8878 (February 2021)\. +The \fIzstandard\fR format is specified in Y\. Collet, "Zstandard Compression and the \'application/zstd\' Media Type", https://www\.ietf\.org/rfc/rfc8878\.txt, Internet RFC 8878 (February 2021)\. +. .SH "BUGS" Report bugs at: https://github\.com/facebook/zstd/issues +. .SH "AUTHOR" Yann Collet diff --git a/programs/zstdgrep.1 b/programs/zstdgrep.1 index d7fda5833..fc79e82e3 100644 --- a/programs/zstdgrep.1 +++ b/programs/zstdgrep.1 @@ -1,5 +1,5 @@ . -.TH "ZSTDGREP" "1" "March 2024" "zstd 1.5.6" "User Commands" +.TH "ZSTDGREP" "1" "February 2025" "zstd 1.5.7" "User Commands" . .SH "NAME" \fBzstdgrep\fR \- print lines matching a pattern in zstandard\-compressed files diff --git a/programs/zstdless.1 b/programs/zstdless.1 index 7dd65f8fc..ad5048a02 100644 --- a/programs/zstdless.1 +++ b/programs/zstdless.1 @@ -1,5 +1,5 @@ . -.TH "ZSTDLESS" "1" "March 2024" "zstd 1.5.6" "User Commands" +.TH "ZSTDLESS" "1" "February 2025" "zstd 1.5.7" "User Commands" . .SH "NAME" \fBzstdless\fR \- view zstandard\-compressed files From 4690d66c7e41e8476838da588226ee2c185af5e8 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 20 Feb 2025 11:46:14 -0800 Subject: [PATCH 004/245] add CI check for zstd_manual before release ensures it's properly updated --- .github/workflows/dev-short-tests.yml | 2 +- .github/workflows/release_check.yml | 31 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/release_check.yml diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 7df105532..38a3a0f92 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -41,7 +41,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 - - name: ensure zstd can be build with c89/c90 compilers (+ long long support + variadic macros) + - name: ensure zstd can be built with c89/c90 compilers (+ long long support + variadic macros) run: | make c89build V=1 diff --git a/.github/workflows/release_check.yml b/.github/workflows/release_check.yml new file mode 100644 index 000000000..aa1e817f4 --- /dev/null +++ b/.github/workflows/release_check.yml @@ -0,0 +1,31 @@ +name: check_manual + +on: + push: + branches: + - release + pull_request: + branches: + - release + +permissions: read-all + +jobs: + verify-manual: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v3 + + - name: Save current manual + run: mv doc/zstd_manual.html doc/zstd_manual_saved.html + + - name: Generate new manual + run: make manual + + - name: Compare manuals + run: | + if ! cmp -s doc/zstd_manual.html doc/zstd_manual_saved.html; then + echo "The manual was not updated before release !" + exit 1 + fi From c2ab0f9c4e6333f51b582676362946591d3278b6 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 20 Feb 2025 13:14:11 -0800 Subject: [PATCH 005/245] check man page update --- .github/workflows/release_check.yml | 37 +++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release_check.yml b/.github/workflows/release_check.yml index aa1e817f4..160e4d516 100644 --- a/.github/workflows/release_check.yml +++ b/.github/workflows/release_check.yml @@ -1,4 +1,4 @@ -name: check_manual +name: release_checks on: push: @@ -26,6 +26,39 @@ jobs: - name: Compare manuals run: | if ! cmp -s doc/zstd_manual.html doc/zstd_manual_saved.html; then - echo "The manual was not updated before release !" + echo "The API manual was not updated before release !" exit 1 fi + + verify-man-pages: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v3 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y ruby ruby-dev + sudo gem install ronn + + - name: Display ronn version + run: ronn --version + + - name: Save current man pages + run: | + mv programs/zstd.1 programs/zstd.1.saved + mv programs/zstdgrep.1 programs/zstdgrep.1.saved + mv programs/zstdless.1 programs/zstdless.1.saved + + - name: Generate new manual pages + run: make -C programs man + + - name: Compare man pages + run: | + for file in zstd.1 zstdgrep.1 zstdless.1; do + if ! cmp -s programs/$file programs/$file.saved; then + echo "The man page $file should have been updated." + exit 1 + fi + done From 0c3345d6ec207c5207cb2b9bd50a32a0c709228b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 20 Feb 2025 15:21:48 -0800 Subject: [PATCH 006/245] [cmake] use target_compile_definitions which is considered best practice. --- build/cmake/lib/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt index 4e902a1fb..0a93e8d31 100644 --- a/build/cmake/lib/CMakeLists.txt +++ b/build/cmake/lib/CMakeLists.txt @@ -112,7 +112,7 @@ endif() macro (add_definition target var) if (NOT ("${${var}}" STREQUAL "")) - set_property(TARGET ${target} APPEND PROPERTY COMPILE_DEFINITIONS "${var}=__attribute__((visibility(\"${${var}}\")))") + target_compile_definitions(${target} PUBLIC "${var}=__attribute__((visibility(\"${${var}}\")))") endif () endmacro () @@ -126,7 +126,7 @@ if (ZSTD_BUILD_SHARED) target_include_directories(libzstd_shared INTERFACE $) list(APPEND library_targets libzstd_shared) if (ZSTD_MULTITHREAD_SUPPORT) - set_property(TARGET libzstd_shared APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_MULTITHREAD") + target_compile_definitions(libzstd_shared PUBLIC ZSTD_MULTITHREAD) if (UNIX) target_link_libraries(libzstd_shared ${THREADS_LIBS}) endif () @@ -140,7 +140,7 @@ if (ZSTD_BUILD_STATIC) target_include_directories(libzstd_static INTERFACE $) list(APPEND library_targets libzstd_static) if (ZSTD_MULTITHREAD_SUPPORT) - set_property(TARGET libzstd_static APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_MULTITHREAD") + target_compile_definitions(libzstd_static PUBLIC ZSTD_MULTITHREAD) if (UNIX) target_link_libraries(libzstd_static ${THREADS_LIBS}) endif () @@ -207,7 +207,7 @@ if (ZSTD_BUILD_SHARED) OUTPUT_NAME zstd VERSION ${ZSTD_FULL_VERSION} SOVERSION ${zstd_VERSION_MAJOR}) - + if (ZSTD_FRAMEWORK) set_target_properties( libzstd_shared From 8ff47f3df0cdc79af358912eee4c96b863a5054b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 21 Feb 2025 09:57:55 -0800 Subject: [PATCH 007/245] added musl compilation test in CI --- .github/workflows/dev-short-tests.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 7df105532..56a46a744 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -684,6 +684,17 @@ jobs: make -C programs zstd-pgo ./programs/zstd -b + musl-build: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - name: Install musl-tools + run: | + sudo apt install -y musl-tools + - name: Compile the project with musl-gcc + run: | + CC=musl-gcc make -j V=1 zstd + intel-cet-compatibility: runs-on: ubuntu-latest steps: From ebfa660b8297170fb0742ac8959aa64940292853 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 21 Feb 2025 11:36:30 -0800 Subject: [PATCH 008/245] introduce ZSTD_USE_C90_QSORT --- .github/workflows/dev-short-tests.yml | 2 +- lib/dictBuilder/cover.c | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 56a46a744..56401db0a 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -693,7 +693,7 @@ jobs: sudo apt install -y musl-tools - name: Compile the project with musl-gcc run: | - CC=musl-gcc make -j V=1 zstd + CC=musl-gcc CPPFLAGS=-DZSTD_USE_C90_QSORT make -j V=1 zstd intel-cet-compatibility: runs-on: ubuntu-latest diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 2ef33c73e..29820d7e1 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -24,9 +24,9 @@ /* qsort_r is an extension. */ #if defined(__linux) || defined(__linux__) || defined(linux) || defined(__gnu_linux__) || \ defined(__CYGWIN__) || defined(__MSYS__) -#if !defined(_GNU_SOURCE) && !defined(__ANDROID__) /* NDK doesn't ship qsort_r(). */ -#define _GNU_SOURCE -#endif +# if !defined(_GNU_SOURCE) && !defined(__ANDROID__) /* NDK doesn't ship qsort_r(). */ +# define _GNU_SOURCE +# endif #endif #include /* fprintf */ @@ -241,8 +241,9 @@ typedef struct { unsigned d; } COVER_ctx_t; -#if !defined(_GNU_SOURCE) && !defined(__APPLE__) && !defined(_MSC_VER) -/* C90 only offers qsort() that needs a global context. */ +#if defined(ZSTD_USE_C90_QSORT) \ + || (!defined(_GNU_SOURCE) && !defined(__APPLE__) && !defined(_MSC_VER)) +/* Use global context for non-reentrant sort functions */ static COVER_ctx_t *g_coverCtx = NULL; #endif @@ -328,7 +329,7 @@ static void stableSort(COVER_ctx_t *ctx) { qsort_r(ctx->suffix, ctx->suffixSize, sizeof(U32), ctx, (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); -#elif defined(_GNU_SOURCE) +#elif defined(_GNU_SOURCE) && !defined(ZSTD_USE_C90_QSORT) qsort_r(ctx->suffix, ctx->suffixSize, sizeof(U32), (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp), ctx); @@ -342,7 +343,7 @@ static void stableSort(COVER_ctx_t *ctx) { (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); #else /* C90 fallback.*/ g_coverCtx = ctx; - /* TODO(cavalcanti): implement a reentrant qsort() when is not available. */ + /* TODO(cavalcanti): implement a reentrant qsort() when _r is not available. */ qsort(ctx->suffix, ctx->suffixSize, sizeof(U32), (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); #endif From fd5498a1793f26b3a6995009449e1216a8c90dd0 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 21 Feb 2025 12:48:26 -0800 Subject: [PATCH 009/245] document ZSTD_USE_C90_QSORT --- lib/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/README.md b/lib/README.md index b37f5fc4f..9df516c5a 100644 --- a/lib/README.md +++ b/lib/README.md @@ -193,6 +193,10 @@ The file structure is designed to make this selection manually achievable for an and assembly decoding loops. You may want to use this macro if these loops are slower on your platform. +- The macro `ZSTD_USE_C90_QSORT` forces usage of C90's `qsort()`, + for situations where the code cannot determine that `qsort_r()` is not supported, + such as, for example, older versions of `musl`. + #### Windows : using MinGW+MSYS to create DLL DLL can be created using MinGW+MSYS with the `make libzstd` command. From b40dabeda2893509c5c903c9c2647fe41e5d6c4d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 05:44:05 +0000 Subject: [PATCH 010/245] Bump ossf/scorecard-action from 2.4.0 to 2.4.1 Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.4.0 to 2.4.1. - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/62b2cac7ed8198b15735ed49ab1e5cf35480ba46...f49aabe0b5af0936a0987cfb85d86b75731b0186) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index e532b03bf..6d49b886a 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -32,7 +32,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # tag=v2.4.0 + uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # tag=v2.4.1 with: results_file: results.sarif results_format: sarif From e1e2f3873d0cd068d69b49659f7732dd18027115 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 05:44:08 +0000 Subject: [PATCH 011/245] Bump msys2/setup-msys2 from 2.26.0 to 2.27.0 Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.26.0 to 2.27.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/d44ca8e88d8b43d56cf5670f91747359d5537f97...61f9e5e925871ba6c9e3e8da24ede83ea27fa91f) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dev-long-tests.yml | 2 +- .github/workflows/dev-short-tests.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 0aa85ff7e..c0dbe38d0 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -260,7 +260,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 - - uses: msys2/setup-msys2@d44ca8e88d8b43d56cf5670f91747359d5537f97 # tag=v2.26.0 + - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # tag=v2.27.0 with: msystem: MINGW64 install: make diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 7df105532..aa098489d 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -544,7 +544,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 - - uses: msys2/setup-msys2@d44ca8e88d8b43d56cf5670f91747359d5537f97 # tag=v2.26.0 + - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # tag=v2.27.0 with: msystem: ${{ matrix.msystem }} install: make diffutils diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 35999476e..0334f1446 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -24,7 +24,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3 - - uses: msys2/setup-msys2@d44ca8e88d8b43d56cf5670f91747359d5537f97 # tag=v2.26.0 + - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # tag=v2.27.0 with: msystem: ${{ matrix.msystem }} install: make zlib git p7zip mingw-w64-${{matrix.env}}-gcc From 2840631dc1a5923ee51f76792ea427e41b1a0de4 Mon Sep 17 00:00:00 2001 From: hirohira Date: Wed, 26 Feb 2025 08:23:48 +0900 Subject: [PATCH 012/245] Fix function signature mismatch for ZSTD_convertBlockSequences --- lib/compress/zstd_compress_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compress/zstd_compress_internal.h b/lib/compress/zstd_compress_internal.h index ca5e2a4c5..c6bd166b1 100644 --- a/lib/compress/zstd_compress_internal.h +++ b/lib/compress/zstd_compress_internal.h @@ -1523,7 +1523,7 @@ typedef struct { /* for benchmark */ size_t ZSTD_convertBlockSequences(ZSTD_CCtx* cctx, const ZSTD_Sequence* const inSeqs, size_t nbSequences, - int const repcodeResolution); + int repcodeResolution); typedef struct { size_t nbSequences; From 30281d889ff3217bd62d906d550f24c9303c651c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 26 Feb 2025 07:41:34 -0800 Subject: [PATCH 013/245] fix conversion warning --- lib/common/bits.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/bits.h b/lib/common/bits.h index f452f0889..910ffa388 100644 --- a/lib/common/bits.h +++ b/lib/common/bits.h @@ -21,7 +21,7 @@ MEM_STATIC unsigned ZSTD_countTrailingZeros32_fallback(U32 val) 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; - return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27]; + return DeBruijnBytePos[((U32) ((val & (0-val)) * 0x077CB531U)) >> 27]; } } From e635221f1bf1ba5cf0d1d2d31bfa24b8d995b21f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 26 Feb 2025 08:07:51 -0800 Subject: [PATCH 014/245] fixed -Wconversion for zdict --- lib/dictBuilder/zdict.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c index d5e60a4da..befa616b8 100644 --- a/lib/dictBuilder/zdict.c +++ b/lib/dictBuilder/zdict.c @@ -168,7 +168,7 @@ static void ZDICT_initDictItem(dictItem* d) #define MINMATCHLENGTH 7 /* heuristic determined experimentally */ static dictItem ZDICT_analyzePos( BYTE* doneMarks, - const int* suffix, U32 start, + const unsigned* suffix, U32 start, const void* buffer, U32 minRatio, U32 notificationLevel) { U32 lengthList[LLIMIT] = {0}; @@ -293,8 +293,10 @@ static dictItem ZDICT_analyzePos( for (i=(int)(maxLength-2); i>=0; i--) cumulLength[i] = cumulLength[i+1] + lengthList[i]; - for (i=LLIMIT-1; i>=MINMATCHLENGTH; i--) if (cumulLength[i]>=minRatio) break; - maxLength = i; + { unsigned u; + for (u=LLIMIT-1; u>=MINMATCHLENGTH; u--) if (cumulLength[u]>=minRatio) break; + maxLength = u; + } /* reduce maxLength in case of final into repetitive data */ { U32 l = (U32)maxLength; @@ -306,8 +308,10 @@ static dictItem ZDICT_analyzePos( /* calculate savings */ savings[5] = 0; - for (i=MINMATCHLENGTH; i<=(int)maxLength; i++) - savings[i] = savings[i-1] + (lengthList[i] * (i-3)); + { unsigned u; + for (u=MINMATCHLENGTH; u<=maxLength; u++) + savings[u] = savings[u-1] + (lengthList[u] * (u-3)); + } DISPLAYLEVEL(4, "Selected dict at position %u, of length %u : saves %u (ratio: %.2f) \n", (unsigned)pos, (unsigned)maxLength, (unsigned)savings[maxLength], (double)savings[maxLength] / (double)maxLength); @@ -383,11 +387,11 @@ static U32 ZDICT_tryMerge(dictItem* table, dictItem elt, U32 eltNbToSkip, const if ((table[u].pos + table[u].length >= elt.pos) && (table[u].pos < elt.pos)) { /* overlap, existing < new */ /* append */ - int const addedLength = (int)eltEnd - (int)(table[u].pos + table[u].length); + int const addedLength = (int)eltEnd - (int)(table[u].pos + table[u].length); /* note: can be negative */ table[u].savings += elt.length / 8; /* rough approx bonus */ if (addedLength > 0) { /* otherwise, elt fully included into existing */ - table[u].length += addedLength; - table[u].savings += elt.savings * addedLength / elt.length; /* rough approx */ + table[u].length += (unsigned)addedLength; + table[u].savings += elt.savings * (unsigned)addedLength / elt.length; /* rough approx */ } /* sort : improve rank */ elt = table[u]; @@ -399,7 +403,7 @@ static U32 ZDICT_tryMerge(dictItem* table, dictItem elt, U32 eltNbToSkip, const if (MEM_read64(buf + table[u].pos) == MEM_read64(buf + elt.pos + 1)) { if (isIncluded(buf + table[u].pos, buf + elt.pos + 1, table[u].length)) { - size_t const addedLength = MAX( (int)elt.length - (int)table[u].length , 1 ); + size_t const addedLength = MAX( elt.length - table[u].length , 1 ); table[u].pos = elt.pos; table[u].savings += (U32)(elt.savings * addedLength / elt.length); table[u].length = MIN(elt.length, table[u].length + 1); @@ -467,8 +471,8 @@ static size_t ZDICT_trainBuffer_legacy(dictItem* dictList, U32 dictListSize, const size_t* fileSizes, unsigned nbFiles, unsigned minRatio, U32 notificationLevel) { - int* const suffix0 = (int*)malloc((bufferSize+2)*sizeof(*suffix0)); - int* const suffix = suffix0+1; + unsigned* const suffix0 = (unsigned*)malloc((bufferSize+2)*sizeof(*suffix0)); + unsigned* const suffix = suffix0+1; U32* reverseSuffix = (U32*)malloc((bufferSize)*sizeof(*reverseSuffix)); BYTE* doneMarks = (BYTE*)malloc((bufferSize+16)*sizeof(*doneMarks)); /* +16 for overflow security */ U32* filePos = (U32*)malloc(nbFiles * sizeof(*filePos)); @@ -503,11 +507,11 @@ static size_t ZDICT_trainBuffer_legacy(dictItem* dictList, U32 dictListSize, /* sort */ DISPLAYLEVEL(2, "sorting %u files of total size %u MB ...\n", nbFiles, (unsigned)(bufferSize>>20)); - { int const divSuftSortResult = divsufsort((const unsigned char*)buffer, suffix, (int)bufferSize, 0); + { int const divSuftSortResult = divsufsort((const unsigned char*)buffer, (int*)suffix, (int)bufferSize, 0); if (divSuftSortResult != 0) { result = ERROR(GENERIC); goto _cleanup; } } - suffix[bufferSize] = (int)bufferSize; /* leads into noise */ - suffix0[0] = (int)bufferSize; /* leads into noise */ + suffix[bufferSize] = (unsigned)bufferSize; /* leads into noise */ + suffix0[0] = (unsigned)bufferSize; /* leads into noise */ /* build reverse suffix sort */ { size_t pos; for (pos=0; pos < bufferSize; pos++) From 8ffa27d93b5f2d5b0a7f0b3e051e983410575de5 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 26 Feb 2025 08:12:11 -0800 Subject: [PATCH 015/245] fixed -Wconversion for divsufsort.c --- lib/dictBuilder/divsufsort.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/dictBuilder/divsufsort.c b/lib/dictBuilder/divsufsort.c index a2870fb3b..e5b117b29 100644 --- a/lib/dictBuilder/divsufsort.c +++ b/lib/dictBuilder/divsufsort.c @@ -199,8 +199,8 @@ ss_isqrt(int x) { int y, e; if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; } - e = (x & 0xffff0000) ? - ((x & 0xff000000) ? + e = ((unsigned)x & 0xffff0000) ? + (((unsigned)x & 0xff000000) ? 24 + lg_table[(x >> 24) & 0xff] : 16 + lg_table[(x >> 16) & 0xff]) : ((x & 0x0000ff00) ? @@ -909,8 +909,8 @@ sssort(const unsigned char *T, const int *PA, static INLINE int tr_ilg(int n) { - return (n & 0xffff0000) ? - ((n & 0xff000000) ? + return ((unsigned)n & 0xffff0000) ? + (((unsigned)n & 0xff000000) ? 24 + lg_table[(n >> 24) & 0xff] : 16 + lg_table[(n >> 16) & 0xff]) : ((n & 0x0000ff00) ? From 2413f1732268351b87aea8711f1d7fe6f1aaddbc Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 26 Feb 2025 08:33:01 -0800 Subject: [PATCH 016/245] fixed -Wconversion for cover.c --- lib/dictBuilder/cover.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 2ef33c73e..a71370c72 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -1183,7 +1183,7 @@ ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize); const unsigned shrinkDict = 0; /* Local variables */ - const int displayLevel = parameters->zParams.notificationLevel; + const int displayLevel = (int)parameters->zParams.notificationLevel; unsigned iteration = 1; unsigned d; unsigned k; @@ -1261,7 +1261,7 @@ ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( data->parameters.splitPoint = splitPoint; data->parameters.steps = kSteps; data->parameters.shrinkDict = shrinkDict; - data->parameters.zParams.notificationLevel = g_displayLevel; + data->parameters.zParams.notificationLevel = (unsigned)g_displayLevel; /* Check the parameters */ if (!COVER_checkParameters(data->parameters, dictBufferCapacity)) { DISPLAYLEVEL(1, "Cover parameters incorrect\n"); From db2d205ada0c57a8b5611303a400987c278f15a6 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 26 Feb 2025 10:01:05 -0800 Subject: [PATCH 017/245] fixed -Wconversion for lib/decompress/zstd_decompress_block.c --- lib/common/compiler.h | 12 +-- lib/common/zstd_internal.h | 2 +- lib/compress/zstd_compress_internal.h | 4 +- lib/decompress/zstd_decompress_block.c | 116 +++++++++++++------------ 4 files changed, 71 insertions(+), 63 deletions(-) diff --git a/lib/common/compiler.h b/lib/common/compiler.h index 1f7da50e6..944774a7a 100644 --- a/lib/common/compiler.h +++ b/lib/common/compiler.h @@ -357,9 +357,9 @@ ptrdiff_t ZSTD_wrappedPtrDiff(unsigned char const* lhs, unsigned char const* rhs */ MEM_STATIC ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -unsigned char const* ZSTD_wrappedPtrAdd(unsigned char const* ptr, ptrdiff_t add) +const void* ZSTD_wrappedPtrAdd(const void* ptr, ptrdiff_t add) { - return ptr + add; + return (const char*)ptr + add; } /** @@ -370,9 +370,9 @@ unsigned char const* ZSTD_wrappedPtrAdd(unsigned char const* ptr, ptrdiff_t add) */ MEM_STATIC ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -unsigned char const* ZSTD_wrappedPtrSub(unsigned char const* ptr, ptrdiff_t sub) +const void* ZSTD_wrappedPtrSub(const void* ptr, ptrdiff_t sub) { - return ptr - sub; + return (const char*)ptr - sub; } /** @@ -382,9 +382,9 @@ unsigned char const* ZSTD_wrappedPtrSub(unsigned char const* ptr, ptrdiff_t sub) * @returns `ptr + add` except it defines `NULL + 0 == NULL`. */ MEM_STATIC -unsigned char* ZSTD_maybeNullPtrAdd(unsigned char* ptr, ptrdiff_t add) +void* ZSTD_maybeNullPtrAdd(void* ptr, ptrdiff_t add) { - return add > 0 ? ptr + add : ptr; + return add > 0 ? (char*)ptr + add : ptr; } /* Issue #3240 reports an ASAN failure on an llvm-mingw build. Out of an diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 2789a3591..c1647689b 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -213,7 +213,7 @@ typedef enum { * The src buffer must be before the dst buffer. */ MEM_STATIC FORCE_INLINE_ATTR -void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e const ovtype) +void ZSTD_wildcopy(void* dst, const void* src, size_t length, ZSTD_overlap_e const ovtype) { ptrdiff_t diff = (BYTE*)dst - (const BYTE*)src; const BYTE* ip = (const BYTE*)src; diff --git a/lib/compress/zstd_compress_internal.h b/lib/compress/zstd_compress_internal.h index ca5e2a4c5..90202003f 100644 --- a/lib/compress/zstd_compress_internal.h +++ b/lib/compress/zstd_compress_internal.h @@ -707,7 +707,7 @@ ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE con { assert(iend > ilimit_w); if (ip <= ilimit_w) { - ZSTD_wildcopy(op, ip, ilimit_w - ip, ZSTD_no_overlap); + ZSTD_wildcopy(op, ip, (size_t)(ilimit_w - ip), ZSTD_no_overlap); op += ilimit_w - ip; ip = ilimit_w; } @@ -800,7 +800,7 @@ ZSTD_storeSeq(SeqStore_t* seqStorePtr, ZSTD_STATIC_ASSERT(WILDCOPY_OVERLENGTH >= 16); ZSTD_copy16(seqStorePtr->lit, literals); if (litLength > 16) { - ZSTD_wildcopy(seqStorePtr->lit+16, literals+16, (ptrdiff_t)litLength-16, ZSTD_no_overlap); + ZSTD_wildcopy(seqStorePtr->lit+16, literals+16, litLength-16, ZSTD_no_overlap); } } else { ZSTD_safecopyLiterals(seqStorePtr->lit, literals, litEnd, litLimit_w); diff --git a/lib/decompress/zstd_decompress_block.c b/lib/decompress/zstd_decompress_block.c index 862785a49..ec8ebcda7 100644 --- a/lib/decompress/zstd_decompress_block.c +++ b/lib/decompress/zstd_decompress_block.c @@ -16,14 +16,13 @@ *********************************************************/ #include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ #include "../common/compiler.h" /* prefetch */ -#include "../common/cpu.h" /* bmi2 */ #include "../common/mem.h" /* low level memory routines */ +#include #define FSE_STATIC_LINKING_ONLY #include "../common/fse.h" #include "../common/huf.h" #include "../common/zstd_internal.h" #include "zstd_decompress_internal.h" /* ZSTD_DCtx */ -#include "zstd_ddict.h" /* ZSTD_DDictDictContent */ #include "zstd_decompress_block.h" #include "../common/bits.h" /* ZSTD_highbit32 */ @@ -734,9 +733,10 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, ip++; /* Build DTables */ + assert(ip <= iend); { size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr, LLtype, MaxLL, LLFSELog, - ip, iend-ip, + ip, (size_t)(iend-ip), LL_base, LL_bits, LL_defaultDTable, dctx->fseEntropy, dctx->ddictIsCold, nbSeq, @@ -746,9 +746,10 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, ip += llhSize; } + assert(ip <= iend); { size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr, OFtype, MaxOff, OffFSELog, - ip, iend-ip, + ip, (size_t)(iend-ip), OF_base, OF_bits, OF_defaultDTable, dctx->fseEntropy, dctx->ddictIsCold, nbSeq, @@ -758,9 +759,10 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, ip += ofhSize; } + assert(ip <= iend); { size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr, MLtype, MaxML, MLFSELog, - ip, iend-ip, + ip, (size_t)(iend-ip), ML_base, ML_bits, ML_defaultDTable, dctx->fseEntropy, dctx->ddictIsCold, nbSeq, @@ -771,7 +773,7 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, } } - return ip-istart; + return (size_t)(ip-istart); } @@ -801,7 +803,8 @@ typedef struct { * Precondition: *ip <= *op * Postcondition: *op - *op >= 8 */ -HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { +HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) +{ assert(*ip <= *op); if (offset < 8) { /* close range match, overlap */ @@ -834,7 +837,9 @@ HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { * - ZSTD_overlap_src_before_dst: The src and dst may overlap and may be any distance apart. * The src buffer must be before the dst buffer. */ -static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { +static void +ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, size_t length, ZSTD_overlap_e ovtype) +{ ptrdiff_t const diff = op - ip; BYTE* const oend = op + length; @@ -849,7 +854,8 @@ static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, pt if (ovtype == ZSTD_overlap_src_before_dst) { /* Copy 8 bytes and ensure the offset >= 8 when there can be overlap. */ assert(length >= 8); - ZSTD_overlapCopy8(&op, &ip, diff); + assert(diff > 0); + ZSTD_overlapCopy8(&op, &ip, (size_t)diff); length -= 8; assert(op - ip >= 8); assert(op <= oend); @@ -863,7 +869,7 @@ static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, pt if (op <= oend_w) { /* Wildcopy until we get close to the end. */ assert(oend > oend_w); - ZSTD_wildcopy(op, ip, oend_w - op, ovtype); + ZSTD_wildcopy(op, ip, (size_t)(oend_w - op), ovtype); ip += oend_w - op; op += oend_w - op; } @@ -874,7 +880,8 @@ static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, pt /* ZSTD_safecopyDstBeforeSrc(): * This version allows overlap with dst before src, or handles the non-overlap case with dst after src * Kept separate from more common ZSTD_safecopy case to avoid performance impact to the safecopy common case */ -static void ZSTD_safecopyDstBeforeSrc(BYTE* op, const BYTE* ip, ptrdiff_t length) { +static void ZSTD_safecopyDstBeforeSrc(BYTE* op, const BYTE* ip, size_t length) +{ ptrdiff_t const diff = op - ip; BYTE* const oend = op + length; @@ -885,7 +892,7 @@ static void ZSTD_safecopyDstBeforeSrc(BYTE* op, const BYTE* ip, ptrdiff_t length } if (op <= oend - WILDCOPY_OVERLENGTH && diff < -WILDCOPY_VECLEN) { - ZSTD_wildcopy(op, ip, oend - WILDCOPY_OVERLENGTH - op, ZSTD_no_overlap); + ZSTD_wildcopy(op, ip, (size_t)(oend - WILDCOPY_OVERLENGTH - op), ZSTD_no_overlap); ip += oend - WILDCOPY_OVERLENGTH - op; op += oend - WILDCOPY_OVERLENGTH - op; } @@ -936,11 +943,11 @@ size_t ZSTD_execSequenceEnd(BYTE* op, return sequenceLength; } /* span extDict & currentPrefixSegment */ - { size_t const length1 = dictEnd - match; - ZSTD_memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = prefixStart; + { size_t const length1 = (size_t)(dictEnd - match); + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; } } ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); @@ -985,11 +992,11 @@ size_t ZSTD_execSequenceEndSplitLitBuffer(BYTE* op, return sequenceLength; } /* span extDict & currentPrefixSegment */ - { size_t const length1 = dictEnd - match; - ZSTD_memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = prefixStart; + { size_t const length1 = (size_t)(dictEnd - match); + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; } } ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); @@ -1058,11 +1065,11 @@ size_t ZSTD_execSequence(BYTE* op, return sequenceLength; } /* span extDict & currentPrefixSegment */ - { size_t const length1 = dictEnd - match; - ZSTD_memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = prefixStart; + { size_t const length1 = (size_t)(dictEnd - match); + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; } } /* Match within prefix of 1 or more bytes */ @@ -1079,7 +1086,7 @@ size_t ZSTD_execSequence(BYTE* op, * longer than literals (in general). In silesia, ~10% of matches are longer * than 16 bytes. */ - ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); + ZSTD_wildcopy(op, match, sequence.matchLength, ZSTD_no_overlap); return sequenceLength; } assert(sequence.offset < WILDCOPY_VECLEN); @@ -1090,7 +1097,7 @@ size_t ZSTD_execSequence(BYTE* op, /* If the match length is > 8 bytes, then continue with the wildcopy. */ if (sequence.matchLength > 8) { assert(op < oMatchEnd); - ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8, ZSTD_overlap_src_before_dst); + ZSTD_wildcopy(op, match, sequence.matchLength - 8, ZSTD_overlap_src_before_dst); } return sequenceLength; } @@ -1151,7 +1158,7 @@ size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, return sequenceLength; } /* span extDict & currentPrefixSegment */ - { size_t const length1 = dictEnd - match; + { size_t const length1 = (size_t)(dictEnd - match); ZSTD_memmove(oLitEnd, match, length1); op = oLitEnd + length1; sequence.matchLength -= length1; @@ -1171,7 +1178,7 @@ size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, * longer than literals (in general). In silesia, ~10% of matches are longer * than 16 bytes. */ - ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); + ZSTD_wildcopy(op, match, sequence.matchLength, ZSTD_no_overlap); return sequenceLength; } assert(sequence.offset < WILDCOPY_VECLEN); @@ -1182,7 +1189,7 @@ size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, /* If the match length is > 8 bytes, then continue with the wildcopy. */ if (sequence.matchLength > 8) { assert(op < oMatchEnd); - ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8, ZSTD_overlap_src_before_dst); + ZSTD_wildcopy(op, match, sequence.matchLength-8, ZSTD_overlap_src_before_dst); } return sequenceLength; } @@ -1405,10 +1412,8 @@ ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, const void* seqStart, size_t seqSize, int nbSeq, const ZSTD_longOffset_e isLongOffset) { - const BYTE* ip = (const BYTE*)seqStart; - const BYTE* const iend = ip + seqSize; BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = ZSTD_maybeNullPtrAdd(ostart, maxDstSize); + BYTE* const oend = ZSTD_maybeNullPtrAdd(ostart, (ptrdiff_t)maxDstSize); BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; const BYTE* litBufferEnd = dctx->litBufferEnd; @@ -1423,7 +1428,7 @@ ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, dctx->fseEntropy = 1; { U32 i; for (i=0; ientropy.rep[i]; } RETURN_ERROR_IF( - ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), + ERR_isError(BIT_initDStream(&seqState.DStream, seqStart, seqSize)), corruption_detected, ""); ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); @@ -1515,7 +1520,8 @@ ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, /* If there are more sequences, they will need to read literals from litExtraBuffer; copy over the remainder from dst and update litPtr and litEnd */ if (nbSeq > 0) { - const size_t leftoverLit = dctx->litBufferEnd - litPtr; + const size_t leftoverLit = (size_t)(dctx->litBufferEnd - litPtr); + assert(dctx->litBufferEnd >= litPtr); DEBUGLOG(6, "There are %i sequences left, and %zu/%zu literals left in buffer", nbSeq, leftoverLit, sequence.litLength); if (leftoverLit) { RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); @@ -1617,10 +1623,10 @@ ZSTD_decompressSequences_body(ZSTD_DCtx* dctx, const void* seqStart, size_t seqSize, int nbSeq, const ZSTD_longOffset_e isLongOffset) { - const BYTE* ip = (const BYTE*)seqStart; - const BYTE* const iend = ip + seqSize; BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = dctx->litBufferLocation == ZSTD_not_in_dst ? ZSTD_maybeNullPtrAdd(ostart, maxDstSize) : dctx->litBuffer; + BYTE* const oend = (dctx->litBufferLocation == ZSTD_not_in_dst) ? + ZSTD_maybeNullPtrAdd(ostart, (ptrdiff_t)maxDstSize) : + dctx->litBuffer; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; const BYTE* const litEnd = litPtr + dctx->litSize; @@ -1635,7 +1641,7 @@ ZSTD_decompressSequences_body(ZSTD_DCtx* dctx, dctx->fseEntropy = 1; { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; } RETURN_ERROR_IF( - ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend - ip)), + ERR_isError(BIT_initDStream(&seqState.DStream, seqStart, seqSize)), corruption_detected, ""); ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); @@ -1719,7 +1725,7 @@ size_t ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence, { const BYTE* const matchBase = (sequence.offset > prefetchPos) ? dictEnd : prefixStart; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. * No consequence though : memory address is only used for prefetching, not for dereferencing */ - const BYTE* const match = ZSTD_wrappedPtrSub(ZSTD_wrappedPtrAdd(matchBase, prefetchPos), sequence.offset); + const BYTE* const match = ZSTD_wrappedPtrSub(ZSTD_wrappedPtrAdd(matchBase, (ptrdiff_t)prefetchPos), (ptrdiff_t)sequence.offset); PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ } return prefetchPos + sequence.matchLength; @@ -1736,10 +1742,10 @@ ZSTD_decompressSequencesLong_body( const void* seqStart, size_t seqSize, int nbSeq, const ZSTD_longOffset_e isLongOffset) { - const BYTE* ip = (const BYTE*)seqStart; - const BYTE* const iend = ip + seqSize; BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = dctx->litBufferLocation == ZSTD_in_dst ? dctx->litBuffer : ZSTD_maybeNullPtrAdd(ostart, maxDstSize); + BYTE* const oend = (dctx->litBufferLocation == ZSTD_in_dst) ? + dctx->litBuffer : + ZSTD_maybeNullPtrAdd(ostart, (ptrdiff_t)maxDstSize); BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; const BYTE* litBufferEnd = dctx->litBufferEnd; @@ -1761,9 +1767,8 @@ ZSTD_decompressSequencesLong_body( dctx->fseEntropy = 1; { int i; for (i=0; ientropy.rep[i]; } assert(dst != NULL); - assert(iend >= ip); RETURN_ERROR_IF( - ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), + ERR_isError(BIT_initDStream(&seqState.DStream, seqStart, seqSize)), corruption_detected, ""); ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); @@ -1782,9 +1787,9 @@ ZSTD_decompressSequencesLong_body( if (dctx->litBufferLocation == ZSTD_split && litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength > dctx->litBufferEnd) { /* lit buffer is reaching split point, empty out the first buffer and transition to litExtraBuffer */ - const size_t leftoverLit = dctx->litBufferEnd - litPtr; - if (leftoverLit) - { + const size_t leftoverLit = (size_t)(dctx->litBufferEnd - litPtr); + assert(dctx->litBufferEnd >= litPtr); + if (leftoverLit) { RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength -= leftoverLit; @@ -1828,7 +1833,8 @@ ZSTD_decompressSequencesLong_body( for ( ; seqNblitBufferLocation == ZSTD_split && litPtr + sequence->litLength > dctx->litBufferEnd) { - const size_t leftoverLit = dctx->litBufferEnd - litPtr; + const size_t leftoverLit = (size_t)(dctx->litBufferEnd - litPtr); + assert(dctx->litBufferEnd >= litPtr); if (leftoverLit) { RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); @@ -1867,7 +1873,8 @@ ZSTD_decompressSequencesLong_body( /* last literal segment */ if (dctx->litBufferLocation == ZSTD_split) { /* first deplete literal buffer in dst, then copy litExtraBuffer */ - size_t const lastLLSize = litBufferEnd - litPtr; + size_t const lastLLSize = (size_t)(litBufferEnd - litPtr); + assert(litBufferEnd >= litPtr); RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); if (op != NULL) { ZSTD_memmove(op, litPtr, lastLLSize); @@ -1876,7 +1883,8 @@ ZSTD_decompressSequencesLong_body( litPtr = dctx->litExtraBuffer; litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; } - { size_t const lastLLSize = litBufferEnd - litPtr; + { size_t const lastLLSize = (size_t)(litBufferEnd - litPtr); + assert(litBufferEnd >= litPtr); RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); if (op != NULL) { ZSTD_memmove(op, litPtr, lastLLSize); @@ -2094,7 +2102,7 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, * Additionally, take the min with dstCapacity to ensure that the totalHistorySize fits in a size_t. */ size_t const blockSizeMax = MIN(dstCapacity, ZSTD_blockSizeMax(dctx)); - size_t const totalHistorySize = ZSTD_totalHistorySize(ZSTD_maybeNullPtrAdd((BYTE*)dst, blockSizeMax), (BYTE const*)dctx->virtualStart); + size_t const totalHistorySize = ZSTD_totalHistorySize(ZSTD_maybeNullPtrAdd(dst, (ptrdiff_t)blockSizeMax), (BYTE const*)dctx->virtualStart); /* isLongOffset must be true if there are long offsets. * Offsets are long if they are larger than ZSTD_maxShortOffset(). * We don't expect that to be the case in 64-bit mode. From 97bc43cc68b2b2e7b55c1f00dfa68b30e8b8d6f8 Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Wed, 26 Feb 2025 19:27:44 +0100 Subject: [PATCH 018/245] build_package.bat: fix path to zstd_errors.h (it is in lib not in lib/common) closes gh-4318 --- lib/dll/example/build_package.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dll/example/build_package.bat b/lib/dll/example/build_package.bat index 8baabc7b2..6a93efa25 100644 --- a/lib/dll/example/build_package.bat +++ b/lib/dll/example/build_package.bat @@ -15,6 +15,6 @@ COPY lib\dll\example\Makefile bin\example\ COPY lib\dll\example\fullbench-dll.* bin\example\ COPY lib\dll\example\README.md bin\ COPY lib\zstd.h bin\include\ -COPY lib\common\zstd_errors.h bin\include\ +COPY lib\zstd_errors.h bin\include\ COPY lib\dictBuilder\zdict.h bin\include\ COPY programs\zstd.exe bin\zstd.exe From f0d31732030091886bbaa50fc0197bdf8588787d Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Wed, 26 Feb 2025 20:02:48 +0100 Subject: [PATCH 019/245] build_package.bat: don't swallow the error(s) by copy, exit with error if failed somewhere --- lib/dll/example/build_package.bat | 46 +++++++++++++++++++------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/lib/dll/example/build_package.bat b/lib/dll/example/build_package.bat index 6a93efa25..65ce367c2 100644 --- a/lib/dll/example/build_package.bat +++ b/lib/dll/example/build_package.bat @@ -1,20 +1,30 @@ @ECHO OFF MKDIR bin\dll bin\static bin\example bin\include -COPY tests\fullbench.c bin\example\ -COPY programs\datagen.c bin\example\ -COPY programs\datagen.h bin\example\ -COPY programs\util.h bin\example\ -COPY programs\platform.h bin\example\ -COPY lib\common\mem.h bin\example\ -COPY lib\common\zstd_internal.h bin\example\ -COPY lib\common\error_private.h bin\example\ -COPY lib\common\xxhash.h bin\example\ -COPY lib\libzstd.a bin\static\libzstd_static.lib -COPY lib\dll\libzstd.* bin\dll\ -COPY lib\dll\example\Makefile bin\example\ -COPY lib\dll\example\fullbench-dll.* bin\example\ -COPY lib\dll\example\README.md bin\ -COPY lib\zstd.h bin\include\ -COPY lib\zstd_errors.h bin\include\ -COPY lib\dictBuilder\zdict.h bin\include\ -COPY programs\zstd.exe bin\zstd.exe +SET CpyError= +COPY tests\fullbench.c bin\example\ || (SET CpyError=%CpyError% tests\fullbench.c) +COPY programs\datagen.c bin\example\ || (SET CpyError=%CpyError% programs\datagen.c) +COPY programs\datagen.h bin\example\ || (SET CpyError=%CpyError% programs\datagen.h) +COPY programs\util.h bin\example\ || (SET CpyError=%CpyError% programs\util.h) +COPY programs\platform.h bin\example\ || (SET CpyError=%CpyError% programs\platform.h) +COPY lib\common\mem.h bin\example\ || (SET CpyError=%CpyError% lib\common\mem.h) +COPY lib\common\zstd_internal.h bin\example\ || (SET CpyError=%CpyError% lib\common\zstd_internal.h) +COPY lib\common\error_private.h bin\example\ || (SET CpyError=%CpyError% lib\common\error_private.h) +COPY lib\common\xxhash.h bin\example\ || (SET CpyError=%CpyError% lib\common\xxhash.h) +COPY lib\libzstd.a bin\static\libzstd_static.lib || (SET CpyError=%CpyError% lib\libzstd.a) +COPY lib\dll\libzstd.* bin\dll\ || (SET CpyError=%CpyError% lib\dll\libzstd.*) +COPY lib\dll\example\Makefile bin\example\ || (SET CpyError=%CpyError% lib\dll\example\Makefile) +COPY lib\dll\example\fullbench-dll.* bin\example\ || (SET CpyError=%CpyError% lib\dll\example\fullbench) +COPY lib\dll\example\README.md bin\ || (SET CpyError=%CpyError% lib\dll\example\README.md) +COPY lib\zstd.h bin\include\ || (SET CpyError=%CpyError% lib\zstd.h) +COPY lib\zstd_errors.h bin\include\ || (SET CpyError=%CpyError% lib\zstd_errors.h) +COPY lib\dictBuilder\zdict.h bin\include\ || (SET CpyError=%CpyError% lib\dictBuilder\zdict.h) +COPY programs\zstd.exe bin\zstd.exe || (SET CpyError=%CpyError% programs\zstd.exe) + +IF "[%CpyError%]" == "[]" goto :EOF + +:error +echo Failed with error #%errorlevel%: unable to copy following files: +echo %CpyError% +exit /b %errorlevel% + +:EOF From 4d81b0000df94fe42477ceae755ea256595cba12 Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Wed, 26 Feb 2025 20:13:44 +0100 Subject: [PATCH 020/245] GHA/windows-artifacts.yml: don't ignore the error if build-package batch failed --- .github/workflows/windows-artifacts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 0334f1446..9b74969d3 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -46,7 +46,7 @@ jobs: - name: Create artifacts run: | - ./lib/dll/example/build_package.bat + ./lib/dll/example/build_package.bat || exit 1 mv bin/ zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ 7z a -tzip -mx9 zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ cd .. From dca9791862698f73a6d230feef64b4bb406481ff Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 26 Feb 2025 14:30:29 -0800 Subject: [PATCH 021/245] fixed minor C++ compat warnings --- lib/decompress/huf_decompress.c | 11 ++++++----- lib/decompress/zstd_decompress_block.c | 12 ++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/decompress/huf_decompress.c b/lib/decompress/huf_decompress.c index f85dd0bee..c7e342648 100644 --- a/lib/decompress/huf_decompress.c +++ b/lib/decompress/huf_decompress.c @@ -15,6 +15,7 @@ /* ************************************************************** * Dependencies ****************************************************************/ +#include /* size_t */ #include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ #include "../common/compiler.h" #include "../common/bitstream.h" /* BIT_* */ @@ -195,7 +196,7 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds const BYTE* const istart = (const BYTE*)src; - BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize); + BYTE* const oend = (BYTE*)ZSTD_maybeNullPtrAdd(dst, (ptrdiff_t)dstSize); /* The fast decoding loop assumes 64-bit little-endian. * This condition is false on x32. @@ -578,7 +579,7 @@ HUF_decompress1X1_usingDTable_internal_body( const HUF_DTable* DTable) { BYTE* op = (BYTE*)dst; - BYTE* const oend = ZSTD_maybeNullPtrAdd(op, dstSize); + BYTE* const oend = (BYTE*)ZSTD_maybeNullPtrAdd(op, (ptrdiff_t)dstSize); const void* dtPtr = DTable + 1; const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr; BIT_DStream_t bitD; @@ -845,7 +846,7 @@ HUF_decompress4X1_usingDTable_internal_fast( { void const* dt = DTable + 1; BYTE const* const ilowest = (BYTE const*)cSrc; - BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize); + BYTE* const oend = (BYTE*)ZSTD_maybeNullPtrAdd(dst, (ptrdiff_t)dstSize); HUF_DecompressFastArgs args; { size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); FORWARD_IF_ERROR(ret, "Failed to init fast loop args"); @@ -1362,7 +1363,7 @@ HUF_decompress1X2_usingDTable_internal_body( /* decode */ { BYTE* const ostart = (BYTE*) dst; - BYTE* const oend = ZSTD_maybeNullPtrAdd(ostart, dstSize); + BYTE* const oend = (BYTE*)ZSTD_maybeNullPtrAdd(ostart, (ptrdiff_t)dstSize); const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */ const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr; DTableDesc const dtd = HUF_getDTableDesc(DTable); @@ -1671,7 +1672,7 @@ HUF_decompress4X2_usingDTable_internal_fast( HUF_DecompressFastLoopFn loopFn) { void const* dt = DTable + 1; const BYTE* const ilowest = (const BYTE*)cSrc; - BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize); + BYTE* const oend = (BYTE*)ZSTD_maybeNullPtrAdd(dst, (ptrdiff_t)dstSize); HUF_DecompressFastArgs args; { size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); diff --git a/lib/decompress/zstd_decompress_block.c b/lib/decompress/zstd_decompress_block.c index ec8ebcda7..3a8e634f9 100644 --- a/lib/decompress/zstd_decompress_block.c +++ b/lib/decompress/zstd_decompress_block.c @@ -1413,7 +1413,7 @@ ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, const ZSTD_longOffset_e isLongOffset) { BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = ZSTD_maybeNullPtrAdd(ostart, (ptrdiff_t)maxDstSize); + BYTE* const oend = (BYTE*)ZSTD_maybeNullPtrAdd(ostart, (ptrdiff_t)maxDstSize); BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; const BYTE* litBufferEnd = dctx->litBufferEnd; @@ -1625,7 +1625,7 @@ ZSTD_decompressSequences_body(ZSTD_DCtx* dctx, { BYTE* const ostart = (BYTE*)dst; BYTE* const oend = (dctx->litBufferLocation == ZSTD_not_in_dst) ? - ZSTD_maybeNullPtrAdd(ostart, (ptrdiff_t)maxDstSize) : + (BYTE*)ZSTD_maybeNullPtrAdd(ostart, (ptrdiff_t)maxDstSize) : dctx->litBuffer; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; @@ -1725,7 +1725,7 @@ size_t ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence, { const BYTE* const matchBase = (sequence.offset > prefetchPos) ? dictEnd : prefixStart; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. * No consequence though : memory address is only used for prefetching, not for dereferencing */ - const BYTE* const match = ZSTD_wrappedPtrSub(ZSTD_wrappedPtrAdd(matchBase, (ptrdiff_t)prefetchPos), (ptrdiff_t)sequence.offset); + const BYTE* const match = (const BYTE*)ZSTD_wrappedPtrSub(ZSTD_wrappedPtrAdd(matchBase, (ptrdiff_t)prefetchPos), (ptrdiff_t)sequence.offset); PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ } return prefetchPos + sequence.matchLength; @@ -1745,7 +1745,7 @@ ZSTD_decompressSequencesLong_body( BYTE* const ostart = (BYTE*)dst; BYTE* const oend = (dctx->litBufferLocation == ZSTD_in_dst) ? dctx->litBuffer : - ZSTD_maybeNullPtrAdd(ostart, (ptrdiff_t)maxDstSize); + (BYTE*)ZSTD_maybeNullPtrAdd(ostart, (ptrdiff_t)maxDstSize); BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; const BYTE* litBufferEnd = dctx->litBufferEnd; @@ -2001,9 +2001,9 @@ ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx, * both the prefix and the extDict. At @p op any offset larger than this * is invalid. */ -static size_t ZSTD_totalHistorySize(BYTE* op, BYTE const* virtualStart) +static size_t ZSTD_totalHistorySize(void* curPtr, const void* virtualStart) { - return (size_t)(op - virtualStart); + return (size_t)((char*)curPtr - (const char*)virtualStart); } typedef struct { From bbf2801ddd6d68a1f36edc18a7b31114b27d2a66 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 27 Feb 2025 15:44:40 -0800 Subject: [PATCH 022/245] try to fix the meson windows build apparently could be just a missing include --- contrib/pzstd/Logging.h | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/pzstd/Logging.h b/contrib/pzstd/Logging.h index 84a08d200..aa73a976b 100644 --- a/contrib/pzstd/Logging.h +++ b/contrib/pzstd/Logging.h @@ -10,6 +10,7 @@ #include #include +#include namespace pzstd { From e94e09dd7b16e9897c76809697e506c5c97851d4 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 27 Feb 2025 11:36:25 -0800 Subject: [PATCH 023/245] ensure that a copy error results in the task failing clearly error code != 0, red status checked by intentionally inserting an error in another run --- lib/dll/example/build_package.bat | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/dll/example/build_package.bat b/lib/dll/example/build_package.bat index 65ce367c2..4c9ffa049 100644 --- a/lib/dll/example/build_package.bat +++ b/lib/dll/example/build_package.bat @@ -23,6 +23,7 @@ COPY programs\zstd.exe bin\zstd.exe || (SET CpyError=%CpyError% programs\zstd.ex IF "[%CpyError%]" == "[]" goto :EOF :error +SET errorlevel=1 echo Failed with error #%errorlevel%: unable to copy following files: echo %CpyError% exit /b %errorlevel% From 77e58994d21870fb23911df2704e669e4d359943 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 27 Feb 2025 11:38:04 -0800 Subject: [PATCH 024/245] updated zlib version to more recent v1.3.1 --- .github/workflows/windows-artifacts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 9b74969d3..d6f934904 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -37,7 +37,7 @@ jobs: - name: Building zlib to static link run: | - git clone --depth 1 --branch v1.2.11 https://github.com/madler/zlib + git clone --depth 1 --branch v1.3.1 https://github.com/madler/zlib make -C zlib -f win32/Makefile.gcc libz.a - name: Building zstd programs From 7340657c6f378d3dfbb8793cad04ed06b875ed40 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 27 Feb 2025 12:43:11 -0800 Subject: [PATCH 025/245] update build_package.bat by using a subrouting --- lib/dll/example/build_package.bat | 57 ++++++++++++++++--------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/lib/dll/example/build_package.bat b/lib/dll/example/build_package.bat index 4c9ffa049..4b750137e 100644 --- a/lib/dll/example/build_package.bat +++ b/lib/dll/example/build_package.bat @@ -1,31 +1,32 @@ -@ECHO OFF -MKDIR bin\dll bin\static bin\example bin\include -SET CpyError= -COPY tests\fullbench.c bin\example\ || (SET CpyError=%CpyError% tests\fullbench.c) -COPY programs\datagen.c bin\example\ || (SET CpyError=%CpyError% programs\datagen.c) -COPY programs\datagen.h bin\example\ || (SET CpyError=%CpyError% programs\datagen.h) -COPY programs\util.h bin\example\ || (SET CpyError=%CpyError% programs\util.h) -COPY programs\platform.h bin\example\ || (SET CpyError=%CpyError% programs\platform.h) -COPY lib\common\mem.h bin\example\ || (SET CpyError=%CpyError% lib\common\mem.h) -COPY lib\common\zstd_internal.h bin\example\ || (SET CpyError=%CpyError% lib\common\zstd_internal.h) -COPY lib\common\error_private.h bin\example\ || (SET CpyError=%CpyError% lib\common\error_private.h) -COPY lib\common\xxhash.h bin\example\ || (SET CpyError=%CpyError% lib\common\xxhash.h) -COPY lib\libzstd.a bin\static\libzstd_static.lib || (SET CpyError=%CpyError% lib\libzstd.a) -COPY lib\dll\libzstd.* bin\dll\ || (SET CpyError=%CpyError% lib\dll\libzstd.*) -COPY lib\dll\example\Makefile bin\example\ || (SET CpyError=%CpyError% lib\dll\example\Makefile) -COPY lib\dll\example\fullbench-dll.* bin\example\ || (SET CpyError=%CpyError% lib\dll\example\fullbench) -COPY lib\dll\example\README.md bin\ || (SET CpyError=%CpyError% lib\dll\example\README.md) -COPY lib\zstd.h bin\include\ || (SET CpyError=%CpyError% lib\zstd.h) -COPY lib\zstd_errors.h bin\include\ || (SET CpyError=%CpyError% lib\zstd_errors.h) -COPY lib\dictBuilder\zdict.h bin\include\ || (SET CpyError=%CpyError% lib\dictBuilder\zdict.h) -COPY programs\zstd.exe bin\zstd.exe || (SET CpyError=%CpyError% programs\zstd.exe) +@echo off +setlocal -IF "[%CpyError%]" == "[]" goto :EOF +rem Create required directories. +mkdir bin\dll bin\static bin\example bin\include -:error -SET errorlevel=1 -echo Failed with error #%errorlevel%: unable to copy following files: -echo %CpyError% -exit /b %errorlevel% +rem Copy files using a subroutine. Exits immediately on failure. +call :copyFile "tests\fullbench.c" "bin\example\" +call :copyFile "programs\datagen.c" "bin\example\" +call :copyFile "programs\datagen.h" "bin\example\" +call :copyFile "programs\util.h" "bin\example\" +call :copyFile "programs\platform.h" "bin\example\" +call :copyFile "lib\common\mem.h" "bin\example\" +call :copyFile "lib\common\zstd_internal.h" "bin\example\" +call :copyFile "lib\common\error_private.h" "bin\example\" +call :copyFile "lib\common\xxhash.h" "bin\example\" +call :copyFile "lib\libzstd.a" "bin\static\libzstd_static.lib" +call :copyFile "lib\dll\libzstd.*" "bin\dll\" +call :copyFile "lib\dll\example\Makefile" "bin\example\" +call :copyFile "lib\dll\example\fullbench-dll.*" "bin\example\" +call :copyFile "lib\dll\example\README.md" "bin\" +call :copyFile "lib\zstd.h" "bin\include\" +call :copyFile "lib\zstd_errors.h" "bin\include\" +call :copyFile "lib\dictBuilder\zdict.h" "bin\include\" +call :copyFile "programs\zstd.exe" "bin\zstd.exe" -:EOF +endlocal +exit /b + +:copyFile +copy "%~1" "%~2" || (echo Failure processing "%~1" & exit /b %errorlevel%) +goto :eof From 4e1723a7e47afb97a5ed55d0536706f719ed066e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 27 Feb 2025 14:33:49 -0800 Subject: [PATCH 026/245] fixed the script so that it fails when a copy fails and also: fix the list of files, as `zdict.h` was incorrectly set. --- lib/dll/example/build_package.bat | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/dll/example/build_package.bat b/lib/dll/example/build_package.bat index 4b750137e..5a03bdf25 100644 --- a/lib/dll/example/build_package.bat +++ b/lib/dll/example/build_package.bat @@ -21,12 +21,16 @@ call :copyFile "lib\dll\example\fullbench-dll.*" "bin\example\" call :copyFile "lib\dll\example\README.md" "bin\" call :copyFile "lib\zstd.h" "bin\include\" call :copyFile "lib\zstd_errors.h" "bin\include\" -call :copyFile "lib\dictBuilder\zdict.h" "bin\include\" +call :copyFile "lib\zdict.h" "bin\include\" call :copyFile "programs\zstd.exe" "bin\zstd.exe" endlocal -exit /b +exit /b 0 :copyFile -copy "%~1" "%~2" || (echo Failure processing "%~1" & exit /b %errorlevel%) -goto :eof +copy "%~1" "%~2" +if errorlevel 1 ( + echo Failed to copy "%~1" + exit 1 +) +exit /b From 88100bc62f8b28c1981a6d0d2cf28e4a7ec8a2b2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 27 Feb 2025 16:59:40 -0800 Subject: [PATCH 027/245] proper usage of standard variables --- .github/workflows/windows-artifacts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index d6f934904..bb8c127b9 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -42,7 +42,7 @@ jobs: - name: Building zstd programs run: | - CPPFLAGS=-I../zlib LDFLAGS=../zlib/libz.a make -j allzstd MOREFLAGS=-static V=1 + CPPFLAGS=-I../zlib LDLIBS=../zlib/libz.a LDFLAGS=-static make -j allzstd V=1 - name: Create artifacts run: | From a6d232dcad9602e8d840f2021dcfe96226a00ef6 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 28 Feb 2025 09:33:22 -0800 Subject: [PATCH 028/245] avoid double zipping --- .github/workflows/windows-artifacts.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index bb8c127b9..335389593 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -27,7 +27,7 @@ jobs: - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # tag=v2.27.0 with: msystem: ${{ matrix.msystem }} - install: make zlib git p7zip mingw-w64-${{matrix.env}}-gcc + install: make zlib git mingw-w64-${{matrix.env}}-gcc update: true - name: display versions @@ -48,11 +48,10 @@ jobs: run: | ./lib/dll/example/build_package.bat || exit 1 mv bin/ zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ - 7z a -tzip -mx9 zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ - cd .. - name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1 with: - path: ${{ github.workspace }}/zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip - name: zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip + compression-level: 9 # maximum compression + path: ${{ github.workspace }}/zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ + name: zstd-${{ github.ref_name }}-${{matrix.ziparch}} From bbbb2379ed0524496a531ba840953f31b62ee881 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 28 Feb 2025 09:42:50 -0800 Subject: [PATCH 029/245] test win artifact generation on pushing to release this will get a chance to check that win artifact generation works correctly before creating the release tag. --- .github/workflows/windows-artifacts.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 335389593..079552414 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -2,7 +2,7 @@ name: windows-artifacts on: push: - branches: [ test_artifacts, win_artifacts ] + branches: [ test_artifacts, win_artifacts, release ] release: types: - published @@ -53,5 +53,6 @@ jobs: uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1 with: compression-level: 9 # maximum compression + if-no-files-found: error # defaults to `warn` path: ${{ github.workspace }}/zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ name: zstd-${{ github.ref_name }}-${{matrix.ziparch}} From e99be473a6e6c9c2852a21b3c5608029a2cbad00 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 28 Feb 2025 12:04:06 -0800 Subject: [PATCH 030/245] automatically upload windows artifact on Release Tag creation --- .github/workflows/windows-artifacts.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 079552414..4c79c9420 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -11,6 +11,8 @@ permissions: read-all jobs: windows-artifacts: + permissions: + contents: write # to fetch code and upload artifacts # see https://ariya.io/2020/07/on-github-actions-with-msys2 runs-on: windows-latest # see https://github.com/msys2/setup-msys2 @@ -27,7 +29,7 @@ jobs: - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # tag=v2.27.0 with: msystem: ${{ matrix.msystem }} - install: make zlib git mingw-w64-${{matrix.env}}-gcc + install: make zlib p7zip git mingw-w64-${{matrix.env}}-gcc update: true - name: display versions @@ -49,10 +51,24 @@ jobs: ./lib/dll/example/build_package.bat || exit 1 mv bin/ zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ - - name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip + - name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip for manual inspection uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1 with: compression-level: 9 # maximum compression if-no-files-found: error # defaults to `warn` path: ${{ github.workspace }}/zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ name: zstd-${{ github.ref_name }}-${{matrix.ziparch}} + + - name: Package artifact for upload + run: | + 7z a -tzip -mx9 "$(cygpath -u '${{ github.workspace }}/zstd-${{ github.ref_name }}-${{ matrix.ziparch }}.zip')" "$(cygpath -u '${{ github.workspace }}/zstd-${{ github.ref_name }}-${{ matrix.ziparch }}')" + + - name: Upload release asset + if: github.event_name == 'release' + shell: pwsh + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload "${{ github.ref_name }}" "$env:GITHUB_WORKSPACE/zstd-${{ github.ref_name }}-${{ matrix.ziparch }}.zip" --clobber + + From 0727fc5ff9f1201b0873b403257c0b9a57e31096 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Mon, 2 Sep 2024 19:55:49 +0900 Subject: [PATCH 031/245] lib: zstd: export API needed for dictionary support Patch series "zram: introduce custom comp backends API", v7. This series introduces support for run-time compression algorithms tuning, so users, for instance, can adjust compression/acceleration levels and provide pre-trained compression/decompression dictionaries which certain algorithms support. At this point we stop supporting (old/deprecated) comp API. We may add new acomp API support in the future, but before that zram needs to undergo some major rework (we are not ready for async compression). Some benchmarks for reference (look at column #2) *** init zstd /sys/block/zram0/mm_stat 1750659072 504622188 514355200 0 514355200 1 0 34204 34204 *** init zstd dict=/home/ss/zstd-dict-amd64 /sys/block/zram0/mm_stat 1750650880 465908890 475398144 0 475398144 1 0 34185 34185 *** init zstd level=8 dict=/home/ss/zstd-dict-amd64 /sys/block/zram0/mm_stat 1750654976 430803319 439873536 0 439873536 1 0 34185 34185 *** init lz4 /sys/block/zram0/mm_stat 1750646784 664266564 677060608 0 677060608 1 0 34288 34288 *** init lz4 dict=/home/ss/lz4-dict-amd64 /sys/block/zram0/mm_stat 1750650880 619990300 632102912 0 632102912 1 0 34278 34278 *** init lz4hc /sys/block/zram0/mm_stat 1750630400 609023822 621232128 0 621232128 1 0 34288 34288 *** init lz4hc dict=/home/ss/lz4-dict-amd64 /sys/block/zram0/mm_stat 1750659072 505133172 515231744 0 515231744 1 0 34278 34278 Recompress init zram zstd (prio=0), zstd level=5 (prio 1), zstd with dict (prio 2) *** zstd /sys/block/zram0/mm_stat 1750982656 504630584 514269184 0 514269184 1 0 34204 34204 *** idle recompress priority=1 (zstd level=5) /sys/block/zram0/mm_stat 1750982656 488645601 525438976 0 514269184 1 0 34204 34204 *** idle recompress priority=2 (zstd dict) /sys/block/zram0/mm_stat 1750982656 460869640 517914624 0 514269184 1 0 34185 34204 This patch (of 24): We need to export a number of API functions that enable advanced zstd usage - C/D dictionaries, dictionaries sharing between contexts, etc. Link: https://lkml.kernel.org/r/20240902105656.1383858-1-senozhatsky@chromium.org Link: https://lkml.kernel.org/r/20240902105656.1383858-2-senozhatsky@chromium.org Signed-off-by: Sergey Senozhatsky Cc: Nick Terrell Cc: Minchan Kim Cc: Sergey Senozhatsky Signed-off-by: Andrew Morton --- contrib/linux-kernel/linux_zstd.h | 166 ++++++++++++++++++ contrib/linux-kernel/zstd_compress_module.c | 49 ++++++ contrib/linux-kernel/zstd_decompress_module.c | 36 ++++ 3 files changed, 251 insertions(+) diff --git a/contrib/linux-kernel/linux_zstd.h b/contrib/linux-kernel/linux_zstd.h index dda8a2d7d..2f2a3c8b8 100644 --- a/contrib/linux-kernel/linux_zstd.h +++ b/contrib/linux-kernel/linux_zstd.h @@ -77,6 +77,30 @@ int zstd_min_clevel(void); */ int zstd_max_clevel(void); +/** + * zstd_default_clevel() - default compression level + * + * Return: Default compression level. + */ +int zstd_default_clevel(void); + +/** + * struct zstd_custom_mem - custom memory allocation + */ +typedef ZSTD_customMem zstd_custom_mem; + +/** + * struct zstd_dict_load_method - Dictionary load method. + * See zstd_lib.h. + */ +typedef ZSTD_dictLoadMethod_e zstd_dict_load_method; + +/** + * struct zstd_dict_content_type - Dictionary context type. + * See zstd_lib.h. + */ +typedef ZSTD_dictContentType_e zstd_dict_content_type; + /* ====== Parameter Selection ====== */ /** @@ -136,6 +160,18 @@ typedef ZSTD_parameters zstd_parameters; zstd_parameters zstd_get_params(int level, unsigned long long estimated_src_size); +/** + * zstd_get_cparams() - returns zstd_compression_parameters for selected level + * @level: The compression level + * @estimated_src_size: The estimated source size to compress or 0 + * if unknown. + * @dict_size: Dictionary size. + * + * Return: The selected zstd_compression_parameters. + */ +zstd_compression_parameters zstd_get_cparams(int level, + unsigned long long estimated_src_size, size_t dict_size); + typedef ZSTD_CCtx zstd_cctx; typedef ZSTD_cParameter zstd_cparameter; @@ -205,6 +241,71 @@ zstd_cctx *zstd_init_cctx(void *workspace, size_t workspace_size); size_t zstd_compress_cctx(zstd_cctx *cctx, void *dst, size_t dst_capacity, const void *src, size_t src_size, const zstd_parameters *parameters); +/** + * zstd_create_cctx_advanced() - Create compression context + * @custom_mem: Custom allocator. + * + * Return: NULL on error, pointer to compression context otherwise. + */ +zstd_cctx *zstd_create_cctx_advanced(zstd_custom_mem custom_mem); + +/** + * zstd_free_cctx() - Free compression context + * @cdict: Pointer to compression context. + * + * Return: Always 0. + */ +size_t zstd_free_cctx(zstd_cctx* cctx); + +/** + * struct zstd_cdict - Compression dictionary. + * See zstd_lib.h. + */ +typedef ZSTD_CDict zstd_cdict; + +/** + * zstd_create_cdict_byreference() - Create compression dictionary + * @dict: Pointer to dictionary buffer. + * @dict_size: Size of the dictionary buffer. + * @dict_load_method: Dictionary load method. + * @dict_content_type: Dictionary content type. + * @custom_mem: Memory allocator. + * + * Note, this uses @dict by reference (ZSTD_dlm_byRef), so it should be + * free before zstd_cdict is destroyed. + * + * Return: NULL on error, pointer to compression dictionary + * otherwise. + */ +zstd_cdict *zstd_create_cdict_byreference(const void *dict, size_t dict_size, + zstd_compression_parameters cparams, + zstd_custom_mem custom_mem); + +/** + * zstd_free_cdict() - Free compression dictionary + * @cdict: Pointer to compression dictionary. + * + * Return: Always 0. + */ +size_t zstd_free_cdict(zstd_cdict* cdict); + +/** + * zstd_compress_using_cdict() - compress src into dst using a dictionary + * @cctx: The context. Must have been initialized with zstd_init_cctx(). + * @dst: The buffer to compress src into. + * @dst_capacity: The size of the destination buffer. May be any size, but + * ZSTD_compressBound(srcSize) is guaranteed to be large enough. + * @src: The data to compress. + * @src_size: The size of the data to compress. + * @cdict: The dictionary to be used. + * + * Return: The compressed size or an error, which can be checked using + * zstd_is_error(). + */ +size_t zstd_compress_using_cdict(zstd_cctx *cctx, void *dst, + size_t dst_capacity, const void *src, size_t src_size, + const zstd_cdict *cdict); + /* ====== Single-pass Decompression ====== */ typedef ZSTD_DCtx zstd_dctx; @@ -245,6 +346,71 @@ zstd_dctx *zstd_init_dctx(void *workspace, size_t workspace_size); size_t zstd_decompress_dctx(zstd_dctx *dctx, void *dst, size_t dst_capacity, const void *src, size_t src_size); +/** + * struct zstd_ddict - Decompression dictionary. + * See zstd_lib.h. + */ +typedef ZSTD_DDict zstd_ddict; + +/** + * zstd_create_ddict_byreference() - Create decompression dictionary + * @dict: Pointer to dictionary buffer. + * @dict_size: Size of the dictionary buffer. + * @dict_load_method: Dictionary load method. + * @dict_content_type: Dictionary content type. + * @custom_mem: Memory allocator. + * + * Note, this uses @dict by reference (ZSTD_dlm_byRef), so it should be + * free before zstd_ddict is destroyed. + * + * Return: NULL on error, pointer to decompression dictionary + * otherwise. + */ +zstd_ddict *zstd_create_ddict_byreference(const void *dict, size_t dict_size, + zstd_custom_mem custom_mem); +/** + * zstd_free_ddict() - Free decompression dictionary + * @dict: Pointer to the dictionary. + * + * Return: Always 0. + */ +size_t zstd_free_ddict(zstd_ddict *ddict); + +/** + * zstd_create_dctx_advanced() - Create decompression context + * @custom_mem: Custom allocator. + * + * Return: NULL on error, pointer to decompression context otherwise. + */ +zstd_dctx *zstd_create_dctx_advanced(zstd_custom_mem custom_mem); + +/** + * zstd_free_dctx() -- Free decompression context + * @dctx: Pointer to decompression context. + * Return: Always 0. + */ +size_t zstd_free_dctx(zstd_dctx *dctx); + +/** + * zstd_decompress_using_ddict() - decompress src into dst using a dictionary + * @dctx: The decompression context. + * @dst: The buffer to decompress src into. + * @dst_capacity: The size of the destination buffer. Must be at least as large + * as the decompressed size. If the caller cannot upper bound the + * decompressed size, then it's better to use the streaming API. + * @src: The zstd compressed data to decompress. Multiple concatenated + * frames and skippable frames are allowed. + * @src_size: The exact size of the data to decompress. + * @ddict: The dictionary to be used. + * + * Return: The decompressed size or an error, which can be checked using + * zstd_is_error(). + */ +size_t zstd_decompress_using_ddict(zstd_dctx *dctx, + void *dst, size_t dst_capacity, const void *src, size_t src_size, + const zstd_ddict *ddict); + + /* ====== Streaming Buffers ====== */ /** diff --git a/contrib/linux-kernel/zstd_compress_module.c b/contrib/linux-kernel/zstd_compress_module.c index 804efe6d5..7651b5355 100644 --- a/contrib/linux-kernel/zstd_compress_module.c +++ b/contrib/linux-kernel/zstd_compress_module.c @@ -67,6 +67,12 @@ int zstd_max_clevel(void) } EXPORT_SYMBOL(zstd_max_clevel); +int zstd_default_clevel(void) +{ + return ZSTD_defaultCLevel(); +} +EXPORT_SYMBOL(zstd_default_clevel); + size_t zstd_compress_bound(size_t src_size) { return ZSTD_compressBound(src_size); @@ -80,6 +86,13 @@ zstd_parameters zstd_get_params(int level, } EXPORT_SYMBOL(zstd_get_params); +zstd_compression_parameters zstd_get_cparams(int level, + unsigned long long estimated_src_size, size_t dict_size) +{ + return ZSTD_getCParams(level, estimated_src_size, dict_size); +} +EXPORT_SYMBOL(zstd_get_cparams); + size_t zstd_cctx_set_param(zstd_cctx *cctx, ZSTD_cParameter param, int value) { return ZSTD_CCtx_setParameter(cctx, param, value); @@ -146,6 +159,33 @@ zstd_cctx *zstd_init_cctx(void *workspace, size_t workspace_size) } EXPORT_SYMBOL(zstd_init_cctx); +zstd_cctx *zstd_create_cctx_advanced(zstd_custom_mem custom_mem) +{ + return ZSTD_createCCtx_advanced(custom_mem); +} +EXPORT_SYMBOL(zstd_create_cctx_advanced); + +size_t zstd_free_cctx(zstd_cctx *cctx) +{ + return ZSTD_freeCCtx(cctx); +} +EXPORT_SYMBOL(zstd_free_cctx); + +zstd_cdict *zstd_create_cdict_byreference(const void *dict, size_t dict_size, + zstd_compression_parameters cparams, + zstd_custom_mem custom_mem) +{ + return ZSTD_createCDict_advanced(dict, dict_size, ZSTD_dlm_byRef, + ZSTD_dct_auto, cparams, custom_mem); +} +EXPORT_SYMBOL(zstd_create_cdict_byreference); + +size_t zstd_free_cdict(zstd_cdict *cdict) +{ + return ZSTD_freeCDict(cdict); +} +EXPORT_SYMBOL(zstd_free_cdict); + size_t zstd_compress_cctx(zstd_cctx *cctx, void *dst, size_t dst_capacity, const void *src, size_t src_size, const zstd_parameters *parameters) { @@ -154,6 +194,15 @@ size_t zstd_compress_cctx(zstd_cctx *cctx, void *dst, size_t dst_capacity, } EXPORT_SYMBOL(zstd_compress_cctx); +size_t zstd_compress_using_cdict(zstd_cctx *cctx, void *dst, + size_t dst_capacity, const void *src, size_t src_size, + const ZSTD_CDict *cdict) +{ + return ZSTD_compress_usingCDict(cctx, dst, dst_capacity, + src, src_size, cdict); +} +EXPORT_SYMBOL(zstd_compress_using_cdict); + size_t zstd_cstream_workspace_bound(const zstd_compression_parameters *cparams) { return ZSTD_estimateCStreamSize_usingCParams(*cparams); diff --git a/contrib/linux-kernel/zstd_decompress_module.c b/contrib/linux-kernel/zstd_decompress_module.c index 7d31518e9..0ae819f0c 100644 --- a/contrib/linux-kernel/zstd_decompress_module.c +++ b/contrib/linux-kernel/zstd_decompress_module.c @@ -44,6 +44,33 @@ size_t zstd_dctx_workspace_bound(void) } EXPORT_SYMBOL(zstd_dctx_workspace_bound); +zstd_dctx *zstd_create_dctx_advanced(zstd_custom_mem custom_mem) +{ + return ZSTD_createDCtx_advanced(custom_mem); +} +EXPORT_SYMBOL(zstd_create_dctx_advanced); + +size_t zstd_free_dctx(zstd_dctx *dctx) +{ + return ZSTD_freeDCtx(dctx); +} +EXPORT_SYMBOL(zstd_free_dctx); + +zstd_ddict *zstd_create_ddict_byreference(const void *dict, size_t dict_size, + zstd_custom_mem custom_mem) +{ + return ZSTD_createDDict_advanced(dict, dict_size, ZSTD_dlm_byRef, + ZSTD_dct_auto, custom_mem); + +} +EXPORT_SYMBOL(zstd_create_ddict_byreference); + +size_t zstd_free_ddict(zstd_ddict *ddict) +{ + return ZSTD_freeDDict(ddict); +} +EXPORT_SYMBOL(zstd_free_ddict); + zstd_dctx *zstd_init_dctx(void *workspace, size_t workspace_size) { if (workspace == NULL) @@ -59,6 +86,15 @@ size_t zstd_decompress_dctx(zstd_dctx *dctx, void *dst, size_t dst_capacity, } EXPORT_SYMBOL(zstd_decompress_dctx); +size_t zstd_decompress_using_ddict(zstd_dctx *dctx, + void *dst, size_t dst_capacity, const void* src, size_t src_size, + const zstd_ddict* ddict) +{ + return ZSTD_decompress_usingDDict(dctx, dst, dst_capacity, src, + src_size, ddict); +} +EXPORT_SYMBOL(zstd_decompress_using_ddict); + size_t zstd_dstream_workspace_bound(size_t max_window_size) { return ZSTD_estimateDStreamSize(max_window_size); From 83db5376d71f55e1394a7c5cdc49b9d3e37e0e93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 05:44:17 +0000 Subject: [PATCH 032/245] Bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/android-ndk-build.yml | 2 +- .github/workflows/dev-long-tests.yml | 52 ++++++------ .github/workflows/dev-short-tests.yml | 82 +++++++++---------- .../workflows/publish-release-artifacts.yml | 2 +- .github/workflows/release_check.yml | 4 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 7 files changed, 73 insertions(+), 73 deletions(-) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index 175add4ff..5746d86f7 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: Set up JDK 17 uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index c0dbe38d0..275b22297 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -15,7 +15,7 @@ jobs: make-all: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: make all run: make all @@ -26,7 +26,7 @@ jobs: DEVNULLRIGHTS: 1 READFROMBLOCKDEVICE: 1 steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: make test run: make test @@ -34,7 +34,7 @@ jobs: make-test-macos: runs-on: macos-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: make test on macos run: make test @@ -45,7 +45,7 @@ jobs: DEVNULLRIGHTS: 1 READFROMBLOCKDEVICE: 1 steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: make test # note: `make -j test success` seems to require a clean state run: | sudo apt-get -qqq update @@ -56,21 +56,21 @@ jobs: no-intrinsics-fuzztest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: no intrinsics fuzztest run: MOREFLAGS="-DZSTD_NO_INTRINSICS" make -C tests fuzztest tsan-zstreamtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: thread sanitizer zstreamtest run: CC=clang ZSTREAM_TESTTIME=-T3mn make tsan-test-zstream uasan-zstreamtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: ub + address sanitizer on zstreamtest run: CC=clang make uasan-test-zstream @@ -78,7 +78,7 @@ jobs: tsan-fuzztest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: thread sanitizer fuzztest run: CC=clang make tsan-fuzztest @@ -86,7 +86,7 @@ jobs: big-tests-zstreamtest32: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: zstream tests in 32bit mode, with big tests run: | sudo apt-get -qqq update @@ -97,7 +97,7 @@ jobs: gcc-8-asan-ubsan-testzstd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: gcc-8 + ASan + UBSan + Test Zstd # See https://askubuntu.com/a/1428822 run: | @@ -109,14 +109,14 @@ jobs: clang-asan-ubsan-testzstd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: clang + ASan + UBSan + Test Zstd run: CC=clang make -j uasan-test-zstd Date: Sun, 2 Mar 2025 23:10:09 -0800 Subject: [PATCH 033/245] Update publish-release-artifacts.yml fix version comment --- .github/workflows/publish-release-artifacts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-release-artifacts.yml b/.github/workflows/publish-release-artifacts.yml index 0d06ccbed..24d86db96 100644 --- a/.github/workflows/publish-release-artifacts.yml +++ b/.github/workflows/publish-release-artifacts.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: Archive env: From 3c6c472f01d2cdaa52fc87fbb65eaa9808205de0 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 2 Mar 2025 23:11:08 -0800 Subject: [PATCH 034/245] Update scorecards.yml edit version comment --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index f7bc9913e..4ca5b5312 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -27,7 +27,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 with: persist-credentials: false From cab2a29c36c81d218e41ec48559dd2cdee4f0943 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 2 Mar 2025 23:11:35 -0800 Subject: [PATCH 035/245] Update windows-artifacts.yml edit version comment --- .github/workflows/windows-artifacts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 3cfa841cb..79e910b57 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -25,7 +25,7 @@ jobs: run: shell: msys2 {0} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # tag=v2.27.0 with: msystem: ${{ matrix.msystem }} From 9ec1a7c0ac0ee1e93520424782b85b4df99a537c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 3 Mar 2025 14:27:43 -0800 Subject: [PATCH 036/245] update zstd build recipe to also support lz4 format --- .github/workflows/windows-artifacts.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 79e910b57..0394ec983 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -29,7 +29,7 @@ jobs: - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # tag=v2.27.0 with: msystem: ${{ matrix.msystem }} - install: make zlib p7zip git mingw-w64-${{matrix.env}}-gcc + install: make zlib mingw-w64-x86_64-lz4 p7zip git mingw-w64-${{matrix.env}}-gcc update: true - name: display versions @@ -42,9 +42,16 @@ jobs: git clone --depth 1 --branch v1.3.1 https://github.com/madler/zlib make -C zlib -f win32/Makefile.gcc libz.a + - name: Building lz4 to static link + run: | + git clone --depth 1 --branch v1.10.0 https://github.com/lz4/lz4 + # ensure both libraries use the same version of libxxhash + cp lib/common/xxhash.* lz4/lib + CPPFLAGS=-DXXH_NAMESPACE=LZ4_ make -C lz4/lib liblz4.a V=1 + - name: Building zstd programs run: | - CPPFLAGS=-I../zlib LDLIBS=../zlib/libz.a LDFLAGS=-static make -j allzstd V=1 + CPPFLAGS="-I../zlib -I../lz4/lib" LDLIBS="../zlib/libz.a ../lz4/lib/liblz4.a" LDFLAGS=-static make -j allzstd V=1 - name: Create artifacts run: | From bceb8f2dbc6c28f3e0d546d5222a89b753bdeede Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 3 Mar 2025 15:54:29 -0800 Subject: [PATCH 037/245] attempt to no longer depend on system library presence for autodetection use explicit opt-in and path setting --- .github/workflows/windows-artifacts.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 0394ec983..4baa2f555 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -29,7 +29,7 @@ jobs: - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # tag=v2.27.0 with: msystem: ${{ matrix.msystem }} - install: make zlib mingw-w64-x86_64-lz4 p7zip git mingw-w64-${{matrix.env}}-gcc + install: make p7zip git mingw-w64-${{matrix.env}}-gcc update: true - name: display versions @@ -51,7 +51,7 @@ jobs: - name: Building zstd programs run: | - CPPFLAGS="-I../zlib -I../lz4/lib" LDLIBS="../zlib/libz.a ../lz4/lib/liblz4.a" LDFLAGS=-static make -j allzstd V=1 + CPPFLAGS="-I../zlib -I../lz4/lib" LDFLAGS=-static make -j allzstd V=1 HAVE_ZLIB=1 HAVE_LZ4=1 HAVE_LZMA=0 LDLIBS="../zlib/libz.a ../lz4/lib/liblz4.a" - name: Create artifacts run: | From d5dbdd6ece53ac5bcab2b91fcd7a1b776b84dfb1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 4 Mar 2025 12:51:39 -0800 Subject: [PATCH 038/245] changed command --blocksize into --split to reduce confusion with the concept of "blocks" inside a Zstandard frame. We are now talking about "independent chunks" being produced by a `split` operation. updated documentation accordingly. Note: old commands "-B#` and `--blocksize=#` remain supported, to maintain compatibility with existing scripts. --- programs/benchzstd.h | 4 +-- programs/zstd.1.md | 18 ++++++------ programs/zstdcli.c | 66 +++++++++++++++++++++++++------------------- 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/programs/benchzstd.h b/programs/benchzstd.h index 4fd0e5a8a..db4d72f9d 100644 --- a/programs/benchzstd.h +++ b/programs/benchzstd.h @@ -92,9 +92,9 @@ typedef enum { } BMK_mode_t; typedef struct { - BMK_mode_t mode; /* 0: all, 1: compress only 2: decode only */ + BMK_mode_t mode; /* 0: both, 1: compress only 2: decode only */ unsigned nbSeconds; /* default timing is in nbSeconds */ - size_t blockSize; /* Maximum size of each block*/ + size_t blockSize; /* Maximum size of each independent chunk */ size_t targetCBlockSize;/* Approximative size of compressed blocks */ int nbWorkers; /* multithreading */ unsigned realTime; /* real time priority */ diff --git a/programs/zstd.1.md b/programs/zstd.1.md index e5c1b7fd2..3b7bc342a 100644 --- a/programs/zstd.1.md +++ b/programs/zstd.1.md @@ -113,7 +113,11 @@ the last one takes effect. Because the compressor's behavior highly depends on the content to compress, there's no guarantee of a smooth progression from one level to another. * `--ultra`: unlocks high compression levels 20+ (maximum 22), using a lot more memory. - Note that decompression will also require more memory when using these levels. + Decompression will also need more memory when using these levels. +* `--max`: + set advanced parameters to reach maximum compression. + warning: this setting is very slow and uses a lot of resources. + It's inappropriate for 32-bit mode and therefore disabled in this mode. * `--fast[=#]`: switch to ultra-fast compression levels. If `=#` is not present, it defaults to `1`. @@ -161,10 +165,6 @@ the last one takes effect. Note: If `windowLog` is set to larger than 27, `--long=windowLog` or `--memory=windowSize` needs to be passed to the decompressor. -* `--max`: - set advanced parameters to maximum compression. - warning: this setting is very slow and uses a lot of resources. - It's inappropriate for 32-bit mode and therefore disabled in this mode. * `-D DICT`: use `DICT` as Dictionary to compress or decompress FILE(s) * `--patch-from FILE`: @@ -554,8 +554,8 @@ Compression of small files similar to the sample set will be greatly improved. Use `#` compression level during training (optional). Will generate statistics more tuned for selected compression level, resulting in a _small_ compression ratio improvement for this level. -* `-B#`: - Split input files into blocks of size # (default: no split) +* `--split=#`: + Split input files into independent chunks of size # (default: no split) * `-M#`, `--memory=#`: Limit the amount of sample data loaded for training (default: 2 GB). Note that the default (2 GB) is also the maximum. @@ -683,8 +683,8 @@ Benchmarking will employ `max(1, min(4, nbCores/4))` worker threads by default i benchmark decompression speed only (requires providing a zstd-compressed content) * `-i#`: minimum evaluation time, in seconds (default: 3s), benchmark mode only -* `-B#`, `--block-size=#`: - cut file(s) into independent chunks of size # (default: no chunking) +* `--split=#`: + split input file(s) into independent chunks of size # (default: no chunking) * `-S`: output one benchmark result per input file (default: consolidated result) * `-D dictionary` diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 83d9b881e..38d00225f 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -307,7 +307,7 @@ static void usageAdvanced(const char* programName) DISPLAYOUT(" -b# Perform benchmarking with compression level #. [Default: %d]\n", ZSTDCLI_CLEVEL_DEFAULT); DISPLAYOUT(" -e# Test all compression levels up to #; starting level is `-b#`. [Default: 1]\n"); DISPLAYOUT(" -i# Set the minimum evaluation to time # seconds. [Default: 3]\n"); - DISPLAYOUT(" -B# Cut file into independent chunks of size #. [Default: No chunking]\n"); + DISPLAYOUT(" --split=# Split input into independent chunks of size #. [Default: No chunking]\n"); DISPLAYOUT(" -S Output one benchmark result per input file. [Default: Consolidated result]\n"); DISPLAYOUT(" -D dictionary Benchmark using dictionary \n"); DISPLAYOUT(" --priority=rt Set process priority to real-time.\n"); @@ -773,7 +773,7 @@ static int init_cLevel(void) { } #ifdef ZSTD_MULTITHREAD -static unsigned default_nbThreads(void) { +static int default_nbThreads(void) { const char* const env = getenv(ENV_NBTHREADS); if (env != NULL) { const char* ptr = env; @@ -783,7 +783,7 @@ static unsigned default_nbThreads(void) { DISPLAYLEVEL(2, "Ignore environment variable setting %s=%s: numeric value too large \n", ENV_NBTHREADS, env); return ZSTDCLI_NBTHREADS_DEFAULT; } else if (*ptr == 0) { - return nbThreads; + return (int)nbThreads; } } DISPLAYLEVEL(2, "Ignore environment variable setting %s=%s: not a valid unsigned value \n", ENV_NBTHREADS, env); @@ -810,22 +810,31 @@ static unsigned default_nbThreads(void) { CLEAN_RETURN(1); \ } } } -#define NEXT_UINT32(val32) { \ - const char* __nb; \ - NEXT_FIELD(__nb); \ - val32 = readU32FromChar(&__nb); \ - if(*__nb != 0) { \ +#define NEXT_INT32(_vari32) { \ + const char* __nb; \ + NEXT_FIELD(__nb); \ + _vari32 = (int)readU32FromChar(&__nb); \ + if(*__nb != 0) { \ errorOut("error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed"); \ - } \ + } \ } -#define NEXT_TSIZE(valTsize) { \ - const char* __nb; \ - NEXT_FIELD(__nb); \ - valTsize = readSizeTFromChar(&__nb); \ - if(*__nb != 0) { \ +#define NEXT_UINT32(_varu32) { \ + const char* __nb; \ + NEXT_FIELD(__nb); \ + _varu32 = readU32FromChar(&__nb); \ + if(*__nb != 0) { \ errorOut("error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed"); \ - } \ + } \ +} + +#define NEXT_TSIZE(_varTsize) { \ + const char* __nb; \ + NEXT_FIELD(__nb); \ + _varTsize = readSizeTFromChar(&__nb); \ + if(*__nb != 0) { \ + errorOut("error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed"); \ + } \ } typedef enum { zom_compress, zom_decompress, zom_test, zom_bench, zom_train, zom_list } zstd_operation_mode; @@ -871,7 +880,7 @@ int main(int argCount, const char* argv[]) int nbWorkers = -1; /* -1 means unset */ double compressibility = -1.0; /* lorem ipsum generator */ unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */ - size_t blockSize = 0; + size_t chunkSize = 0; FIO_prefs_t* const prefs = FIO_createPreferences(); FIO_ctx_t* const fCtx = FIO_createContext(); @@ -1069,11 +1078,12 @@ int main(int argCount, const char* argv[]) continue; } #endif - if (longCommandWArg(&argument, "--threads")) { NEXT_UINT32(nbWorkers); continue; } + if (longCommandWArg(&argument, "--threads")) { NEXT_INT32(nbWorkers); continue; } if (longCommandWArg(&argument, "--memlimit")) { NEXT_UINT32(memLimit); continue; } if (longCommandWArg(&argument, "--memory")) { NEXT_UINT32(memLimit); continue; } if (longCommandWArg(&argument, "--memlimit-decompress")) { NEXT_UINT32(memLimit); continue; } - if (longCommandWArg(&argument, "--block-size")) { NEXT_TSIZE(blockSize); continue; } + if (longCommandWArg(&argument, "--block-size")) { NEXT_TSIZE(chunkSize); continue; } /* hidden command, prefer --split below */ + if (longCommandWArg(&argument, "--split")) { NEXT_TSIZE(chunkSize); continue; } if (longCommandWArg(&argument, "--maxdict")) { NEXT_UINT32(maxDictSize); continue; } if (longCommandWArg(&argument, "--dictID")) { NEXT_UINT32(dictID); continue; } if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); } ; cType = FIO_zstdCompression; continue; } @@ -1256,10 +1266,10 @@ int main(int argCount, const char* argv[]) bench_nbSeconds = readU32FromChar(&argument); break; - /* cut input into blocks (benchmark only) */ + /* cut input into independent chunks (benchmark only) */ case 'B': argument++; - blockSize = readU32FromChar(&argument); + chunkSize = readU32FromChar(&argument); break; /* benchmark files separately (hidden option) */ @@ -1273,7 +1283,7 @@ int main(int argCount, const char* argv[]) /* nb of threads (hidden option) */ case 'T': argument++; - nbWorkers = readU32FromChar(&argument); + nbWorkers = (int)readU32FromChar(&argument); break; /* Dictionary Selection level */ @@ -1324,10 +1334,10 @@ int main(int argCount, const char* argv[]) if ((nbWorkers==0) && (!singleThread)) { /* automatically set # workers based on # of reported cpus */ if (defaultLogicalCores) { - nbWorkers = (unsigned)UTIL_countLogicalCores(); + nbWorkers = UTIL_countLogicalCores(); DISPLAYLEVEL(3, "Note: %d logical core(s) detected \n", nbWorkers); } else { - nbWorkers = (unsigned)UTIL_countPhysicalCores(); + nbWorkers = UTIL_countPhysicalCores(); DISPLAYLEVEL(3, "Note: %d physical core(s) detected \n", nbWorkers); } } @@ -1404,7 +1414,7 @@ int main(int argCount, const char* argv[]) DISPLAYLEVEL(1, "benchmark mode is only compatible with zstd format \n"); CLEAN_RETURN(1); } - benchParams.blockSize = blockSize; + benchParams.blockSize = chunkSize; benchParams.targetCBlockSize = targetCBlockSize; benchParams.nbWorkers = (int)nbWorkers; benchParams.realTime = (unsigned)setRealTimePrio; @@ -1464,18 +1474,18 @@ int main(int argCount, const char* argv[]) int const optimize = !coverParams.k || !coverParams.d; coverParams.nbThreads = (unsigned)nbWorkers; coverParams.zParams = zParams; - operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenames->fileNames, (int)filenames->tableSize, blockSize, NULL, &coverParams, NULL, optimize, memLimit); + operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenames->fileNames, (int)filenames->tableSize, chunkSize, NULL, &coverParams, NULL, optimize, memLimit); } else if (dict == fastCover) { int const optimize = !fastCoverParams.k || !fastCoverParams.d; fastCoverParams.nbThreads = (unsigned)nbWorkers; fastCoverParams.zParams = zParams; - operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenames->fileNames, (int)filenames->tableSize, blockSize, NULL, NULL, &fastCoverParams, optimize, memLimit); + operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenames->fileNames, (int)filenames->tableSize, chunkSize, NULL, NULL, &fastCoverParams, optimize, memLimit); } else { ZDICT_legacy_params_t dictParams; memset(&dictParams, 0, sizeof(dictParams)); dictParams.selectivityLevel = dictSelect; dictParams.zParams = zParams; - operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenames->fileNames, (int)filenames->tableSize, blockSize, &dictParams, NULL, NULL, 0, memLimit); + operationResult = DiB_trainFromFiles(outFileName, maxDictSize, filenames->fileNames, (int)filenames->tableSize, chunkSize, &dictParams, NULL, NULL, 0, memLimit); } #else (void)dictCLevel; (void)dictSelect; (void)dictID; (void)maxDictSize; /* not used when ZSTD_NODICT set */ @@ -1583,7 +1593,7 @@ int main(int argCount, const char* argv[]) FIO_setCompressionType(prefs, cType); FIO_setContentSize(prefs, contentSize); FIO_setNbWorkers(prefs, (int)nbWorkers); - FIO_setBlockSize(prefs, (int)blockSize); + FIO_setBlockSize(prefs, (int)chunkSize); if (g_overlapLog!=OVERLAP_LOG_DEFAULT) FIO_setOverlapLog(prefs, (int)g_overlapLog); FIO_setLdmFlag(prefs, (unsigned)ldmFlag); FIO_setLdmHashLog(prefs, (int)g_ldmHashLog); From fcfb3160dcc58fa478e790cff0a625bddbe6bca7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 4 Mar 2025 13:04:59 -0800 Subject: [PATCH 039/245] convert benchmark unit to use the new naming scheme chunks instead of blocks --- programs/benchzstd.c | 113 +++++++++++++++++++------------------------ programs/benchzstd.h | 2 +- programs/zstdcli.c | 2 +- 3 files changed, 53 insertions(+), 64 deletions(-) diff --git a/programs/benchzstd.c b/programs/benchzstd.c index f9274a517..f55c86975 100644 --- a/programs/benchzstd.c +++ b/programs/benchzstd.c @@ -208,7 +208,7 @@ BMK_advancedParams_t BMK_initAdvancedParams(void) BMK_advancedParams_t const res = { BMK_both, /* mode */ BMK_TIMETEST_DEFAULT_S, /* nbSeconds */ - 0, /* blockSize */ + 0, /* chunkSizeMax */ 0, /* targetCBlockSize */ 0, /* nbWorkers */ 0, /* realTime */ @@ -227,16 +227,6 @@ BMK_advancedParams_t BMK_initAdvancedParams(void) /* ******************************************************** * Bench functions **********************************************************/ -typedef struct { - const void* srcPtr; - size_t srcSize; - void* cPtr; - size_t cRoom; - size_t cSize; - void* resPtr; - size_t resSize; -} blockParam_t; - #undef MIN #undef MAX #define MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -435,16 +425,16 @@ static BMK_benchOutcome_t BMK_benchMemAdvancedNoAlloc( const char* displayName, const BMK_advancedParams_t* adv) { - size_t const blockSize = - ((adv->blockSize >= 32 && (adv->mode != BMK_decodeOnly)) - ? adv->blockSize + size_t const chunkSizeMax = + ((adv->chunkSizeMax >= 32 && (adv->mode != BMK_decodeOnly)) + ? adv->chunkSizeMax : srcSize) + (!srcSize); /* avoid div by 0 */ BMK_benchResult_t benchResult; size_t const loadedCompressedSize = srcSize; size_t cSize = 0; double ratio = 0.; - U32 nbBlocks; + U32 nbChunks = 0; assert(cctx != NULL); assert(dctx != NULL); @@ -500,41 +490,42 @@ static BMK_benchOutcome_t BMK_benchMemAdvancedNoAlloc( } } - /* Init data blocks */ + /* Init data chunks */ { const char* srcPtr = (const char*)srcBuffer; char* cPtr = (char*)compressedBuffer; char* resPtr = (char*)(*resultBufferPtr); - U32 fileNb; - for (nbBlocks = 0, fileNb = 0; fileNb < nbFiles; fileNb++) { + U32 fileNb, chunkID; + for (chunkID = 0, fileNb = 0; fileNb < nbFiles; fileNb++) { size_t remaining = fileSizes[fileNb]; - U32 const nbBlocksforThisFile = (adv->mode == BMK_decodeOnly) + U32 const nbChunksforThisFile = (adv->mode == BMK_decodeOnly) ? 1 - : (U32)((remaining + (blockSize - 1)) / blockSize); - U32 const blockEnd = nbBlocks + nbBlocksforThisFile; - for (; nbBlocks < blockEnd; nbBlocks++) { - size_t const thisBlockSize = MIN(remaining, blockSize); - srcPtrs[nbBlocks] = srcPtr; - srcSizes[nbBlocks] = thisBlockSize; - cPtrs[nbBlocks] = cPtr; - cCapacities[nbBlocks] = (adv->mode == BMK_decodeOnly) - ? thisBlockSize - : ZSTD_compressBound(thisBlockSize); - resPtrs[nbBlocks] = resPtr; - resSizes[nbBlocks] = (adv->mode == BMK_decodeOnly) + : (U32)((remaining + (chunkSizeMax - 1)) / chunkSizeMax); + U32 const chunkIdEnd = chunkID + nbChunksforThisFile; + for (; chunkID < chunkIdEnd; chunkID++) { + size_t const chunkSize = MIN(remaining, chunkSizeMax); + srcPtrs[chunkID] = srcPtr; + srcSizes[chunkID] = chunkSize; + cPtrs[chunkID] = cPtr; + cCapacities[chunkID] = (adv->mode == BMK_decodeOnly) + ? chunkSize + : ZSTD_compressBound(chunkSize); + resPtrs[chunkID] = resPtr; + resSizes[chunkID] = (adv->mode == BMK_decodeOnly) ? (size_t)ZSTD_findDecompressedSize( - srcPtr, thisBlockSize) - : thisBlockSize; - srcPtr += thisBlockSize; - cPtr += cCapacities[nbBlocks]; - resPtr += thisBlockSize; - remaining -= thisBlockSize; + srcPtr, chunkSize) + : chunkSize; + srcPtr += chunkSize; + cPtr += cCapacities[chunkID]; + resPtr += chunkSize; + remaining -= chunkSize; if (adv->mode == BMK_decodeOnly) { - cSizes[nbBlocks] = thisBlockSize; - benchResult.cSize = thisBlockSize; + cSizes[chunkID] = chunkSize; + benchResult.cSize = chunkSize; } } } + nbChunks = chunkID; } /* warming up `compressedBuffer` */ @@ -569,7 +560,7 @@ static BMK_benchOutcome_t BMK_benchMemAdvancedNoAlloc( cbp.initFn = local_initCCtx; /* BMK_initCCtx */ cbp.initPayload = &cctxprep; cbp.errorFn = ZSTD_isError; - cbp.blockCount = nbBlocks; + cbp.blockCount = nbChunks; cbp.srcBuffers = srcPtrs; cbp.srcSizes = srcSizes; cbp.dstBuffers = cPtrs; @@ -588,7 +579,7 @@ static BMK_benchOutcome_t BMK_benchMemAdvancedNoAlloc( dbp.initFn = local_initDCtx; dbp.initPayload = &dctxprep; dbp.errorFn = ZSTD_isError; - dbp.blockCount = nbBlocks; + dbp.blockCount = nbChunks; dbp.srcBuffers = (const void* const*)cPtrs; dbp.srcSizes = cSizes; dbp.dstBuffers = resPtrs; @@ -690,8 +681,7 @@ static BMK_benchOutcome_t BMK_benchMemAdvancedNoAlloc( } /* while (!(compressionCompleted && decompressionCompleted)) */ /* CRC Checking */ - { - const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr); + { const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr); U64 const crcCheck = XXH64(resultBuffer, srcSize, 0); if ((adv->mode == BMK_both) && (crcOrig != crcCheck)) { size_t u; @@ -704,14 +694,14 @@ static BMK_benchOutcome_t BMK_benchMemAdvancedNoAlloc( unsigned segNb, bNb, pos; size_t bacc = 0; DISPLAY("Decoding error at pos %u ", (unsigned)u); - for (segNb = 0; segNb < nbBlocks; segNb++) { + for (segNb = 0; segNb < nbChunks; segNb++) { if (bacc + srcSizes[segNb] > u) break; bacc += srcSizes[segNb]; } pos = (U32)(u - bacc); bNb = pos / (128 KB); - DISPLAY("(sample %u, block %u, pos %u) \n", + DISPLAY("(sample %u, chunk %u, pos %u) \n", segNb, bNb, pos); @@ -795,25 +785,24 @@ BMK_benchOutcome_t BMK_benchMemAdvanced( int const dstParamsError = !dstBuffer ^ !dstCapacity; /* must be both NULL or none */ - size_t const blockSize = - ((adv->blockSize >= 32 && (adv->mode != BMK_decodeOnly)) - ? adv->blockSize + size_t const chunkSize = + ((adv->chunkSizeMax >= 32 && (adv->mode != BMK_decodeOnly)) + ? adv->chunkSizeMax : srcSize) + (!srcSize) /* avoid div by 0 */; - U32 const maxNbBlocks = - (U32)((srcSize + (blockSize - 1)) / blockSize) + nbFiles; + U32 const nbChunksMax = + (U32)((srcSize + (chunkSize - 1)) / chunkSize) + nbFiles; - /* these are the blockTable parameters, just split up */ const void** const srcPtrs = - (const void**)malloc(maxNbBlocks * sizeof(void*)); - size_t* const srcSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t)); + (const void**)malloc(nbChunksMax * sizeof(void*)); + size_t* const srcSizes = (size_t*)malloc(nbChunksMax * sizeof(size_t)); - void** const cPtrs = (void**)malloc(maxNbBlocks * sizeof(void*)); - size_t* const cSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t)); - size_t* const cCapacities = (size_t*)malloc(maxNbBlocks * sizeof(size_t)); + void** const cPtrs = (void**)malloc(nbChunksMax * sizeof(void*)); + size_t* const cSizes = (size_t*)malloc(nbChunksMax * sizeof(size_t)); + size_t* const cCapacities = (size_t*)malloc(nbChunksMax * sizeof(size_t)); - void** const resPtrs = (void**)malloc(maxNbBlocks * sizeof(void*)); - size_t* const resSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t)); + void** const resPtrs = (void**)malloc(nbChunksMax * sizeof(void*)); + size_t* const resSizes = (size_t*)malloc(nbChunksMax * sizeof(size_t)); BMK_timedFnState_t* timeStateCompress = BMK_createTimedFnState( adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS); @@ -825,7 +814,7 @@ BMK_benchOutcome_t BMK_benchMemAdvanced( const size_t maxCompressedSize = dstCapacity ? dstCapacity - : ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024); + : ZSTD_compressBound(srcSize) + (nbChunksMax * 1024); void* const internalDstBuffer = dstBuffer ? NULL : malloc(maxCompressedSize); @@ -964,12 +953,12 @@ static int BMK_benchCLevels( } if (displayLevel == 1 && !adv->additionalParam) /* --quiet mode */ - OUTPUT("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n", + OUTPUT("bench %s %s: input %u bytes, %u seconds, %u KB chunks\n", ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING, (unsigned)benchedSize, adv->nbSeconds, - (unsigned)(adv->blockSize >> 10)); + (unsigned)(adv->chunkSizeMax >> 10)); for (level = startCLevel; level <= endCLevel; level++) { BMK_benchOutcome_t res = BMK_benchMemAdvanced( @@ -1000,7 +989,7 @@ int BMK_syntheticTest( { char nameBuff[20] = { 0 }; const char* name = nameBuff; - size_t const benchedSize = adv->blockSize ? adv->blockSize : 10000000; + size_t const benchedSize = adv->chunkSizeMax ? adv->chunkSizeMax : 10000000; /* Memory allocation */ void* const srcBuffer = malloc(benchedSize); diff --git a/programs/benchzstd.h b/programs/benchzstd.h index db4d72f9d..d62a33c0a 100644 --- a/programs/benchzstd.h +++ b/programs/benchzstd.h @@ -94,7 +94,7 @@ typedef enum { typedef struct { BMK_mode_t mode; /* 0: both, 1: compress only 2: decode only */ unsigned nbSeconds; /* default timing is in nbSeconds */ - size_t blockSize; /* Maximum size of each independent chunk */ + size_t chunkSizeMax; /* Maximum size of each independent chunk */ size_t targetCBlockSize;/* Approximative size of compressed blocks */ int nbWorkers; /* multithreading */ unsigned realTime; /* real time priority */ diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 38d00225f..7395e9585 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1414,7 +1414,7 @@ int main(int argCount, const char* argv[]) DISPLAYLEVEL(1, "benchmark mode is only compatible with zstd format \n"); CLEAN_RETURN(1); } - benchParams.blockSize = chunkSize; + benchParams.chunkSizeMax = chunkSize; benchParams.targetCBlockSize = targetCBlockSize; benchParams.nbWorkers = (int)nbWorkers; benchParams.realTime = (unsigned)setRealTimePrio; From 19ffcf81b88909f28757d7d367696d298f2c5e46 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 4 Mar 2025 13:17:10 -0800 Subject: [PATCH 040/245] changed -B# command into --jobsize to reduce confusion with the term "block". -B# remains supported for existing scripts, but it's no longer documented, so it's effectively a hidden shortcut. --- programs/zstd.1.md | 8 ++++---- programs/zstdcli.c | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/programs/zstd.1.md b/programs/zstd.1.md index 3b7bc342a..cf1810d59 100644 --- a/programs/zstd.1.md +++ b/programs/zstd.1.md @@ -503,12 +503,12 @@ similar to predefined level 19 for files bigger than 256 KB: `--zstd`=wlog=23,clog=23,hlog=22,slog=6,mml=3,tlen=48,strat=6 -### -B#: +### --jobsize=#: Specify the size of each compression job. -This parameter is only available when multi-threading is enabled. -Each compression job is run in parallel, so this value indirectly impacts the nb of active threads. +This parameter is only meaningful when multi-threading is enabled. +Each compression job is run in parallel, so this value can indirectly impact the nb of active threads. Default job size varies depending on compression level (generally `4 * windowSize`). -`-B#` makes it possible to manually select a custom size. +`--jobsize=#` makes it possible to manually select a custom size. Note that job size must respect a minimum value which is enforced transparently. This minimum is either 512 KB, or `overlapSize`, whichever is largest. Different job sizes will lead to non-identical compressed frames. diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 7395e9585..4b7f496d0 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1084,6 +1084,7 @@ int main(int argCount, const char* argv[]) if (longCommandWArg(&argument, "--memlimit-decompress")) { NEXT_UINT32(memLimit); continue; } if (longCommandWArg(&argument, "--block-size")) { NEXT_TSIZE(chunkSize); continue; } /* hidden command, prefer --split below */ if (longCommandWArg(&argument, "--split")) { NEXT_TSIZE(chunkSize); continue; } + if (longCommandWArg(&argument, "--jobsize")) { NEXT_TSIZE(chunkSize); continue; } /* note: overloaded variable */ if (longCommandWArg(&argument, "--maxdict")) { NEXT_UINT32(maxDictSize); continue; } if (longCommandWArg(&argument, "--dictID")) { NEXT_UINT32(dictID); continue; } if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); } ; cType = FIO_zstdCompression; continue; } @@ -1266,7 +1267,7 @@ int main(int argCount, const char* argv[]) bench_nbSeconds = readU32FromChar(&argument); break; - /* cut input into independent chunks (benchmark only) */ + /* hidden shortcut for --split=# and --jobsize=# */ case 'B': argument++; chunkSize = readU32FromChar(&argument); From 9b8b4148338da8ffc81c2e7a2e180ff5316cd31d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 4 Mar 2025 13:22:01 -0800 Subject: [PATCH 041/245] updated playTests.sh to employ the new commands --- tests/playTests.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/playTests.sh b/tests/playTests.sh index 5435ff5b3..65aa5c0b1 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -1093,8 +1093,8 @@ println "\n===> dictionary tests " println "- Test high/low compressibility corpus training" datagen -g12M -P90 > tmpCorpusHighCompress datagen -g12M -P5 > tmpCorpusLowCompress -zstd --train -B2K tmpCorpusHighCompress -o tmpDictHighCompress -zstd --train -B2K tmpCorpusLowCompress -o tmpDictLowCompress +zstd --train --split=2K tmpCorpusHighCompress -o tmpDictHighCompress +zstd --train --split=2K tmpCorpusLowCompress -o tmpDictLowCompress rm -f tmpCorpusHighCompress tmpCorpusLowCompress tmpDictHighCompress tmpDictLowCompress println "- Test with raw dict (content only) " datagen > tmpDict @@ -1179,8 +1179,8 @@ rm -f tmp* dictionary println "- Test --memory for dictionary compression" datagen -g12M -P90 > tmpCorpusHighCompress -zstd --train -B2K tmpCorpusHighCompress -o tmpDictHighCompress --memory=10K && die "Dictionary training should fail : --memory too low (10K)" -zstd --train -B2K tmpCorpusHighCompress -o tmpDictHighCompress --memory=5MB 2> zstTrainWithMemLimitStdErr +zstd --train --split=2K tmpCorpusHighCompress -o tmpDictHighCompress --memory=10K && die "Dictionary training should fail : --memory too low (10K)" +zstd --train --split=2K tmpCorpusHighCompress -o tmpDictHighCompress --memory=5MB 2> zstTrainWithMemLimitStdErr cat zstTrainWithMemLimitStdErr | $GREP "setting manual memory limit for dictionary training data at 5 MB" cat zstTrainWithMemLimitStdErr | $GREP "Training samples set too large (12 MB); training on 5 MB only..." rm zstTrainWithMemLimitStdErr @@ -1555,7 +1555,7 @@ then roundTripTest -g4M "1 -T0 --auto-threads=logical" roundTripTest -g8M "3 -T2" roundTripTest -g8000K "2 --threads=2" - fileRoundTripTest -g4M "19 -T2 -B1M" + fileRoundTripTest -g4M "19 -T2 --split=1M" println "\n===> zstdmt long distance matching round-trip tests " roundTripTest -g8M "3 --long=24 -T2" @@ -1770,7 +1770,7 @@ then println "\n===> rsyncable mode " roundTripTest -g10M " --rsyncable" - roundTripTest -g10M " --rsyncable -B100K" + roundTripTest -g10M " --rsyncable --split=100K" println "===> test: --rsyncable must fail with --single-thread" zstd -f -vv --rsyncable --single-thread tmp && die "--rsyncable must fail with --single-thread" fi From 0298df50f956ab889daf8e5c7e1db8765db1ab11 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 4 Mar 2025 14:43:06 -0800 Subject: [PATCH 042/245] update cli-tests --- programs/dibio.c | 6 +++--- programs/zstdcli.c | 4 ++-- tests/cli-tests/dict-builder/no-inputs.sh.stderr.exact | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/programs/dibio.c b/programs/dibio.c index 7ba22d15b..63c455a22 100644 --- a/programs/dibio.c +++ b/programs/dibio.c @@ -362,9 +362,9 @@ int DiB_trainFromFiles(const char* dictFileName, size_t maxDictSize, DISPLAYLEVEL(2, "! As a consequence, only the first %u bytes of each sample are loaded \n", SAMPLESIZE_MAX); } if (fs.nbSamples < 5) { - DISPLAYLEVEL(2, "! Warning : nb of samples too low for proper processing ! \n"); - DISPLAYLEVEL(2, "! Please provide _one file per sample_. \n"); - DISPLAYLEVEL(2, "! Alternatively, split files into fixed-size blocks representative of samples, with -B# \n"); + DISPLAYLEVEL(2, "! Warning : nb of samples too low for proper processing !\n"); + DISPLAYLEVEL(2, "! Please provide _one file per sample_.\n"); + DISPLAYLEVEL(2, "! Alternatively, split file(s) into fixed-size samples, with --split=#\n"); EXM_THROW(14, "nb of samples too low"); /* we now clearly forbid this case */ } if (fs.totalSizeToLoad < (S64)maxDictSize * 8) { diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 4b7f496d0..8d3ebcefa 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -235,8 +235,8 @@ static void usageAdvanced(const char* programName) DISPLAYOUT(" --single-thread Share a single thread for I/O and compression (slightly different than `-T1`).\n"); DISPLAYOUT(" --auto-threads={physical|logical}\n"); DISPLAYOUT(" Use physical/logical cores when using `-T0`. [Default: Physical]\n\n"); - DISPLAYOUT(" -B# Set job size to #. [Default: 0 (automatic)]\n"); - DISPLAYOUT(" --rsyncable Compress using a rsync-friendly method (`-B` sets block size). \n"); + DISPLAYOUT(" --jobsize=# Set job size to #. [Default: 0 (automatic)]\n"); + DISPLAYOUT(" --rsyncable Compress using a rsync-friendly method (`--jobsize=#` sets unit size). \n"); DISPLAYOUT("\n"); # endif DISPLAYOUT(" --exclude-compressed Only compress files that are not already compressed.\n\n"); diff --git a/tests/cli-tests/dict-builder/no-inputs.sh.stderr.exact b/tests/cli-tests/dict-builder/no-inputs.sh.stderr.exact index d7b3ea020..61f217c34 100644 --- a/tests/cli-tests/dict-builder/no-inputs.sh.stderr.exact +++ b/tests/cli-tests/dict-builder/no-inputs.sh.stderr.exact @@ -1,5 +1,5 @@ zstd --train -! Warning : nb of samples too low for proper processing ! -! Please provide _one file per sample_. -! Alternatively, split files into fixed-size blocks representative of samples, with -B# +! Warning : nb of samples too low for proper processing ! +! Please provide _one file per sample_. +! Alternatively, split file(s) into fixed-size samples, with --split=# Error 14 : nb of samples too low From 0b40c513fdd7c922ea48838790c3cbd9a229eab1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 4 Mar 2025 14:55:25 -0800 Subject: [PATCH 043/245] update fileio to employ jobSize --- programs/fileio.c | 12 ++++++------ programs/fileio.h | 2 +- programs/fileio_types.h | 2 +- programs/zstdcli.c | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 0ecca40d2..3f4460594 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -288,7 +288,7 @@ FIO_prefs_t* FIO_createPreferences(void) ret->removeSrcFile = 0; ret->memLimit = 0; ret->nbWorkers = 1; - ret->blockSize = 0; + ret->jobSize = 0; ret->overlapLog = FIO_OVERLAP_LOG_NOTSET; ret->adaptiveMode = 0; ret->rsyncable = 0; @@ -377,10 +377,10 @@ void FIO_setExcludeCompressedFile(FIO_prefs_t* const prefs, int excludeCompresse void FIO_setAllowBlockDevices(FIO_prefs_t* const prefs, int allowBlockDevices) { prefs->allowBlockDevices = allowBlockDevices; } -void FIO_setBlockSize(FIO_prefs_t* const prefs, int blockSize) { - if (blockSize && prefs->nbWorkers==0) +void FIO_setJobSize(FIO_prefs_t* const prefs, int jobSize) { + if (jobSize && prefs->nbWorkers==0) DISPLAYLEVEL(2, "Setting block size is useless in single-thread mode \n"); - prefs->blockSize = blockSize; + prefs->jobSize = jobSize; } void FIO_setOverlapLog(FIO_prefs_t* const prefs, int overlapLog){ @@ -1183,7 +1183,7 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, #ifdef ZSTD_MULTITHREAD DISPLAYLEVEL(5,"set nb workers = %u \n", prefs->nbWorkers); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_nbWorkers, prefs->nbWorkers) ); - CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_jobSize, prefs->blockSize) ); + CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_jobSize, prefs->jobSize) ); if (prefs->overlapLog != FIO_OVERLAP_LOG_NOTSET) { DISPLAYLEVEL(3,"set overlapLog = %u \n", prefs->overlapLog); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_overlapLog, prefs->overlapLog) ); @@ -2118,7 +2118,7 @@ void FIO_displayCompressionParameters(const FIO_prefs_t* prefs) DISPLAY("%s", INDEX(sparseOptions, prefs->sparseFileSupport)); DISPLAY("%s", prefs->dictIDFlag ? "" : " --no-dictID"); DISPLAY("%s", INDEX(checkSumOptions, prefs->checksumFlag)); - DISPLAY(" --block-size=%d", prefs->blockSize); + DISPLAY(" --jobsize=%d", prefs->jobSize); if (prefs->adaptiveMode) DISPLAY(" --adapt=min=%d,max=%d", prefs->minAdaptLevel, prefs->maxAdaptLevel); DISPLAY("%s", INDEX(rowMatchFinderOptions, prefs->useRowMatchFinder)); diff --git a/programs/fileio.h b/programs/fileio.h index cb53ef537..5d7334ef5 100644 --- a/programs/fileio.h +++ b/programs/fileio.h @@ -70,7 +70,7 @@ void FIO_setAdaptiveMode(FIO_prefs_t* const prefs, int adapt); void FIO_setAdaptMin(FIO_prefs_t* const prefs, int minCLevel); void FIO_setAdaptMax(FIO_prefs_t* const prefs, int maxCLevel); void FIO_setUseRowMatchFinder(FIO_prefs_t* const prefs, int useRowMatchFinder); -void FIO_setBlockSize(FIO_prefs_t* const prefs, int blockSize); +void FIO_setJobSize(FIO_prefs_t* const prefs, int jobSize); void FIO_setChecksumFlag(FIO_prefs_t* const prefs, int checksumFlag); void FIO_setDictIDFlag(FIO_prefs_t* const prefs, int dictIDFlag); void FIO_setLdmBucketSizeLog(FIO_prefs_t* const prefs, int ldmBucketSizeLog); diff --git a/programs/fileio_types.h b/programs/fileio_types.h index 23bda4168..9bbb51549 100644 --- a/programs/fileio_types.h +++ b/programs/fileio_types.h @@ -37,7 +37,7 @@ typedef struct FIO_prefs_s { int sparseFileSupport; /* 0: no sparse allowed; 1: auto (file yes, stdout no); 2: force sparse */ int dictIDFlag; int checksumFlag; - int blockSize; + int jobSize; int overlapLog; int adaptiveMode; int useRowMatchFinder; diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 8d3ebcefa..c84e33858 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1089,7 +1089,7 @@ int main(int argCount, const char* argv[]) if (longCommandWArg(&argument, "--dictID")) { NEXT_UINT32(dictID); continue; } if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); } ; cType = FIO_zstdCompression; continue; } if (longCommandWArg(&argument, "--stream-size")) { NEXT_TSIZE(streamSrcSize); continue; } - if (longCommandWArg(&argument, "--target-compressed-block-size")) { NEXT_TSIZE(targetCBlockSize); continue; } + if (longCommandWArg(&argument, "--target-compressedlock-size")) { NEXT_TSIZE(targetCBlockSize); continue; } if (longCommandWArg(&argument, "--size-hint")) { NEXT_TSIZE(srcSizeHint); continue; } if (longCommandWArg(&argument, "--output-dir-flat")) { NEXT_FIELD(outDirName); @@ -1459,7 +1459,7 @@ int main(int argCount, const char* argv[]) } #else - (void)bench_nbSeconds; (void)blockSize; (void)setRealTimePrio; (void)separateFiles; (void)compressibility; + (void)bench_nbSeconds; (void)chunkSize; (void)setRealTimePrio; (void)separateFiles; (void)compressibility; #endif goto _end; } @@ -1594,7 +1594,7 @@ int main(int argCount, const char* argv[]) FIO_setCompressionType(prefs, cType); FIO_setContentSize(prefs, contentSize); FIO_setNbWorkers(prefs, (int)nbWorkers); - FIO_setBlockSize(prefs, (int)chunkSize); + FIO_setJobSize(prefs, (int)chunkSize); if (g_overlapLog!=OVERLAP_LOG_DEFAULT) FIO_setOverlapLog(prefs, (int)g_overlapLog); FIO_setLdmFlag(prefs, (unsigned)ldmFlag); FIO_setLdmHashLog(prefs, (int)g_ldmHashLog); From f5a0e047cbe3e4c4de2680e0aa30036330d0ee78 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 4 Mar 2025 15:12:35 -0800 Subject: [PATCH 044/245] fix typo --- programs/zstdcli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index c84e33858..e2771f534 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1089,7 +1089,7 @@ int main(int argCount, const char* argv[]) if (longCommandWArg(&argument, "--dictID")) { NEXT_UINT32(dictID); continue; } if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); } ; cType = FIO_zstdCompression; continue; } if (longCommandWArg(&argument, "--stream-size")) { NEXT_TSIZE(streamSrcSize); continue; } - if (longCommandWArg(&argument, "--target-compressedlock-size")) { NEXT_TSIZE(targetCBlockSize); continue; } + if (longCommandWArg(&argument, "--target-compressed-block-size")) { NEXT_TSIZE(targetCBlockSize); continue; } if (longCommandWArg(&argument, "--size-hint")) { NEXT_TSIZE(srcSizeHint); continue; } if (longCommandWArg(&argument, "--output-dir-flat")) { NEXT_FIELD(outDirName); From 5ae1cb9fa1f47a257d220dd5c07a2ecea4124f60 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 4 Mar 2025 15:24:43 -0800 Subject: [PATCH 045/245] added a cli test for new command --jobsize --- tests/cli-tests/compression/multi-threaded.sh | 1 + tests/cli-tests/compression/multi-threaded.sh.stderr.exact | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/cli-tests/compression/multi-threaded.sh b/tests/cli-tests/compression/multi-threaded.sh index 17a5eb518..ac094129e 100755 --- a/tests/cli-tests/compression/multi-threaded.sh +++ b/tests/cli-tests/compression/multi-threaded.sh @@ -9,6 +9,7 @@ zstd --rsyncable -f file -q ; zstd -t file.zst zstd -T0 -f file -q ; zstd -t file.zst zstd -T0 --auto-threads=logical -f file -q ; zstd -t file.zst zstd -T0 --auto-threads=physical -f file -q ; zstd -t file.zst +zstd -T0 --jobsize=1M -f file -q ; zstd -t file.zst # multi-thread decompression warning test zstd -T0 -f file -q ; zstd -t file.zst; zstd -T0 -d file.zst -o file3 diff --git a/tests/cli-tests/compression/multi-threaded.sh.stderr.exact b/tests/cli-tests/compression/multi-threaded.sh.stderr.exact index 11daff6ba..0dcf52ac4 100644 --- a/tests/cli-tests/compression/multi-threaded.sh.stderr.exact +++ b/tests/cli-tests/compression/multi-threaded.sh.stderr.exact @@ -7,5 +7,6 @@ file.zst : 65537 bytes file.zst : 65537 bytes file.zst : 65537 bytes file.zst : 65537 bytes +file.zst : 65537 bytes Warning : decompression does not support multi-threading file.zst : 65537 bytes From d5b84f5a27956284d1c07bbb75672c8c224518df Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 4 Mar 2025 14:55:39 -0500 Subject: [PATCH 046/245] [zstd] Backport D49756856 --- lib/decompress/zstd_decompress_block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/decompress/zstd_decompress_block.c b/lib/decompress/zstd_decompress_block.c index 3a8e634f9..6174a250b 100644 --- a/lib/decompress/zstd_decompress_block.c +++ b/lib/decompress/zstd_decompress_block.c @@ -1726,7 +1726,7 @@ size_t ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence, /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. * No consequence though : memory address is only used for prefetching, not for dereferencing */ const BYTE* const match = (const BYTE*)ZSTD_wrappedPtrSub(ZSTD_wrappedPtrAdd(matchBase, (ptrdiff_t)prefetchPos), (ptrdiff_t)sequence.offset); - PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ + PREFETCH_L1(match); PREFETCH_L1(ZSTD_wrappedPtrAdd(match, CACHELINE_SIZE)); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ } return prefetchPos + sequence.matchLength; } From 190a6209749a9461d11a2fd52cbe547d5c087f4a Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 4 Mar 2025 15:54:49 -0500 Subject: [PATCH 047/245] [zstd] Remove global variables in dictBuilder D50949782 fixed a race condition updating `g_displayLevel` by disabling display. Instead of disabling display, delete the global variable and always "capture" a local `displayLevel` variable. This also fixes `DISPLAYUPDATE()` by requiring the user to pass in the last update time as the first parameter. --- lib/dictBuilder/cover.c | 88 ++++++++++++++++++------------------- lib/dictBuilder/fastcover.c | 79 ++++++++++++++++----------------- 2 files changed, 82 insertions(+), 85 deletions(-) diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 6d8889669..cfb756ff2 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -62,38 +62,30 @@ /*-************************************* * Console display +* +* Captures the `displayLevel` variable in the local scope. ***************************************/ -#ifndef LOCALDISPLAYLEVEL -static int g_displayLevel = 0; -#endif #undef DISPLAY #define DISPLAY(...) \ { \ fprintf(stderr, __VA_ARGS__); \ fflush(stderr); \ } -#undef LOCALDISPLAYLEVEL -#define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ +#undef DISPLAYLEVEL +#define DISPLAYLEVEL(l, ...) \ if (displayLevel >= l) { \ DISPLAY(__VA_ARGS__); \ } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ -#undef DISPLAYLEVEL -#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__) -#ifndef LOCALDISPLAYUPDATE -static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; -static clock_t g_time = 0; -#endif -#undef LOCALDISPLAYUPDATE -#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \ +#undef DISPLAYUPDATE +#define DISPLAYUPDATE(lastUpdateTime, l, ...) \ if (displayLevel >= l) { \ - if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \ - g_time = clock(); \ + const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100; \ + if ((clock() - lastUpdateTime > refreshRate) || (displayLevel >= 4)) { \ + lastUpdateTime = clock(); \ DISPLAY(__VA_ARGS__); \ } \ } -#undef DISPLAYUPDATE -#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__) /*-************************************* * Hash table @@ -239,6 +231,7 @@ typedef struct { U32 *freqs; U32 *dmerAt; unsigned d; + int displayLevel; } COVER_ctx_t; #if defined(ZSTD_USE_C90_QSORT) \ @@ -602,7 +595,7 @@ static void COVER_ctx_destroy(COVER_ctx_t *ctx) { */ static size_t COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, - unsigned d, double splitPoint) + unsigned d, double splitPoint, int displayLevel) { const BYTE *const samples = (const BYTE *)samplesBuffer; const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples); @@ -611,6 +604,7 @@ static size_t COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer, const unsigned nbTestSamples = splitPoint < 1.0 ? nbSamples - nbTrainSamples : nbSamples; const size_t trainingSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes, nbTrainSamples) : totalSamplesSize; const size_t testSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes + nbTrainSamples, nbTestSamples) : totalSamplesSize; + ctx->displayLevel = displayLevel; /* Checks */ if (totalSamplesSize < MAX(d, sizeof(U64)) || totalSamplesSize >= (size_t)COVER_MAX_SAMPLES_SIZE) { @@ -695,14 +689,14 @@ void COVER_warnOnSmallCorpus(size_t maxDictSize, size_t nbDmers, int displayLeve if (ratio >= 10) { return; } - LOCALDISPLAYLEVEL(displayLevel, 1, - "WARNING: The maximum dictionary size %u is too large " - "compared to the source size %u! " - "size(source)/size(dictionary) = %f, but it should be >= " - "10! This may lead to a subpar dictionary! We recommend " - "training on sources at least 10x, and preferably 100x " - "the size of the dictionary! \n", (U32)maxDictSize, - (U32)nbDmers, ratio); + DISPLAYLEVEL(1, + "WARNING: The maximum dictionary size %u is too large " + "compared to the source size %u! " + "size(source)/size(dictionary) = %f, but it should be >= " + "10! This may lead to a subpar dictionary! We recommend " + "training on sources at least 10x, and preferably 100x " + "the size of the dictionary! \n", (U32)maxDictSize, + (U32)nbDmers, ratio); } COVER_epoch_info_t COVER_computeEpochs(U32 maxDictSize, @@ -737,6 +731,8 @@ static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs, const size_t maxZeroScoreRun = MAX(10, MIN(100, epochs.num >> 3)); size_t zeroScoreRun = 0; size_t epoch; + clock_t lastUpdateTime = 0; + const int displayLevel = ctx->displayLevel; DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n", (U32)epochs.num, (U32)epochs.size); /* Loop through the epochs until there are no more segments or the dictionary @@ -770,6 +766,7 @@ static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs, tail -= segmentSize; memcpy(dict + tail, ctx->samples + segment.begin, segmentSize); DISPLAYUPDATE( + lastUpdateTime, 2, "\r%u%% ", (unsigned)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity)); } @@ -785,9 +782,8 @@ ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_cover( BYTE* const dict = (BYTE*)dictBuffer; COVER_ctx_t ctx; COVER_map_t activeDmers; + const int displayLevel = parameters.zParams.notificationLevel; parameters.splitPoint = 1.0; - /* Initialize global data */ - g_displayLevel = (int)parameters.zParams.notificationLevel; /* Checks */ if (!COVER_checkParameters(parameters, dictBufferCapacity)) { DISPLAYLEVEL(1, "Cover parameters incorrect\n"); @@ -805,12 +801,12 @@ ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_cover( /* Initialize context and activeDmers */ { size_t const initVal = COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, - parameters.d, parameters.splitPoint); + parameters.d, parameters.splitPoint, displayLevel); if (ZSTD_isError(initVal)) { return initVal; } } - COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.suffixSize, g_displayLevel); + COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.suffixSize, displayLevel); if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) { DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n"); COVER_ctx_destroy(&ctx); @@ -1133,6 +1129,7 @@ static void COVER_tryParameters(void *opaque) BYTE* const dict = (BYTE*)malloc(dictBufferCapacity); COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC)); U32* const freqs = (U32*)malloc(ctx->suffixSize * sizeof(U32)); + const int displayLevel = ctx->displayLevel; if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) { DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n"); goto _cleanup; @@ -1184,21 +1181,22 @@ ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize); const unsigned shrinkDict = 0; /* Local variables */ - const int displayLevel = (int)parameters->zParams.notificationLevel; + int displayLevel = (int)parameters->zParams.notificationLevel; unsigned iteration = 1; unsigned d; unsigned k; COVER_best_t best; POOL_ctx *pool = NULL; int warned = 0; + clock_t lastUpdateTime = 0; /* Checks */ if (splitPoint <= 0 || splitPoint > 1) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n"); + DISPLAYLEVEL(1, "Incorrect parameters\n"); return ERROR(parameter_outOfBound); } if (kMinK < kMaxD || kMaxK < kMinK) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n"); + DISPLAYLEVEL(1, "Incorrect parameters\n"); return ERROR(parameter_outOfBound); } if (nbSamples == 0) { @@ -1218,19 +1216,19 @@ ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( } /* Initialization */ COVER_best_init(&best); - /* Turn down global display level to clean up display at level 2 and below */ - g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1; /* Loop through d first because each new value needs a new context */ - LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n", + DISPLAYLEVEL(2, "Trying %u different sets of parameters\n", kIterations); for (d = kMinD; d <= kMaxD; d += 2) { /* Initialize the context for this value of d */ COVER_ctx_t ctx; - LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d); + DISPLAYLEVEL(3, "d=%u\n", d); { - const size_t initVal = COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint); + /* Turn down global display level to clean up display at level 2 and below */ + const int childDisplayLevel = (displayLevel == 0) ? 0 : displayLevel - 1; + const size_t initVal = COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint, childDisplayLevel); if (ZSTD_isError(initVal)) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n"); + DISPLAYLEVEL(1, "Failed to initialize context\n"); COVER_best_destroy(&best); POOL_free(pool); return initVal; @@ -1245,9 +1243,9 @@ ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( /* Prepare the arguments */ COVER_tryParameters_data_t *data = (COVER_tryParameters_data_t *)malloc( sizeof(COVER_tryParameters_data_t)); - LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k); + DISPLAYLEVEL(3, "k=%u\n", k); if (!data) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n"); + DISPLAYLEVEL(1, "Failed to allocate parameters\n"); COVER_best_destroy(&best); COVER_ctx_destroy(&ctx); POOL_free(pool); @@ -1262,7 +1260,7 @@ ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( data->parameters.splitPoint = splitPoint; data->parameters.steps = kSteps; data->parameters.shrinkDict = shrinkDict; - data->parameters.zParams.notificationLevel = (unsigned)g_displayLevel; + data->parameters.zParams.notificationLevel = (unsigned)ctx.displayLevel; /* Check the parameters */ if (!COVER_checkParameters(data->parameters, dictBufferCapacity)) { DISPLAYLEVEL(1, "Cover parameters incorrect\n"); @@ -1277,14 +1275,14 @@ ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( COVER_tryParameters(data); } /* Print status */ - LOCALDISPLAYUPDATE(displayLevel, 2, "\r%u%% ", - (unsigned)((iteration * 100) / kIterations)); + DISPLAYUPDATE(lastUpdateTime, 2, "\r%u%% ", + (unsigned)((iteration * 100) / kIterations)); ++iteration; } COVER_best_wait(&best); COVER_ctx_destroy(&ctx); } - LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", ""); + DISPLAYLEVEL(2, "\r%79s\r", ""); /* Fill the output buffer and parameters with output of the best parameters */ { const size_t dictSize = best.dictSize; diff --git a/lib/dictBuilder/fastcover.c b/lib/dictBuilder/fastcover.c index a958eb337..56a081385 100644 --- a/lib/dictBuilder/fastcover.c +++ b/lib/dictBuilder/fastcover.c @@ -49,38 +49,30 @@ /*-************************************* * Console display +* +* Captures the `displayLevel` variable in the local scope. ***************************************/ -#ifndef LOCALDISPLAYLEVEL -static int g_displayLevel = 0; -#endif #undef DISPLAY #define DISPLAY(...) \ { \ fprintf(stderr, __VA_ARGS__); \ fflush(stderr); \ } -#undef LOCALDISPLAYLEVEL -#define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ +#undef DISPLAYLEVEL +#define DISPLAYLEVEL(l, ...) \ if (displayLevel >= l) { \ DISPLAY(__VA_ARGS__); \ } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ -#undef DISPLAYLEVEL -#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__) -#ifndef LOCALDISPLAYUPDATE -static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; -static clock_t g_time = 0; -#endif -#undef LOCALDISPLAYUPDATE -#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \ +#undef DISPLAYUPDATE +#define DISPLAYUPDATE(lastUpdateTime, l, ...) \ if (displayLevel >= l) { \ - if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \ - g_time = clock(); \ + const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100; \ + if ((clock() - lastUpdateTime > refreshRate) || (displayLevel >= 4)) { \ + lastUpdateTime = clock(); \ DISPLAY(__VA_ARGS__); \ } \ } -#undef DISPLAYUPDATE -#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__) /*-************************************* @@ -136,6 +128,7 @@ typedef struct { unsigned d; unsigned f; FASTCOVER_accel_t accelParams; + int displayLevel; } FASTCOVER_ctx_t; @@ -314,7 +307,8 @@ FASTCOVER_ctx_init(FASTCOVER_ctx_t* ctx, const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, unsigned d, double splitPoint, unsigned f, - FASTCOVER_accel_t accelParams) + FASTCOVER_accel_t accelParams, + int displayLevel) { const BYTE* const samples = (const BYTE*)samplesBuffer; const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples); @@ -323,6 +317,7 @@ FASTCOVER_ctx_init(FASTCOVER_ctx_t* ctx, const unsigned nbTestSamples = splitPoint < 1.0 ? nbSamples - nbTrainSamples : nbSamples; const size_t trainingSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes, nbTrainSamples) : totalSamplesSize; const size_t testSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes + nbTrainSamples, nbTestSamples) : totalSamplesSize; + ctx->displayLevel = displayLevel; /* Checks */ if (totalSamplesSize < MAX(d, sizeof(U64)) || @@ -409,7 +404,9 @@ FASTCOVER_buildDictionary(const FASTCOVER_ctx_t* ctx, const COVER_epoch_info_t epochs = COVER_computeEpochs( (U32)dictBufferCapacity, (U32)ctx->nbDmers, parameters.k, 1); const size_t maxZeroScoreRun = 10; + const int displayLevel = ctx->displayLevel; size_t zeroScoreRun = 0; + clock_t lastUpdateTime = 0; size_t epoch; DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n", (U32)epochs.num, (U32)epochs.size); @@ -447,6 +444,7 @@ FASTCOVER_buildDictionary(const FASTCOVER_ctx_t* ctx, tail -= segmentSize; memcpy(dict + tail, ctx->samples + segment.begin, segmentSize); DISPLAYUPDATE( + lastUpdateTime, 2, "\r%u%% ", (unsigned)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity)); } @@ -484,6 +482,7 @@ static void FASTCOVER_tryParameters(void* opaque) BYTE *const dict = (BYTE*)malloc(dictBufferCapacity); COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC)); U32* freqs = (U32*) malloc(((U64)1 << ctx->f) * sizeof(U32)); + const int displayLevel = ctx->displayLevel; if (!segmentFreqs || !dict || !freqs) { DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n"); goto _cleanup; @@ -555,8 +554,7 @@ ZDICT_trainFromBuffer_fastCover(void* dictBuffer, size_t dictBufferCapacity, FASTCOVER_ctx_t ctx; ZDICT_cover_params_t coverParams; FASTCOVER_accel_t accelParams; - /* Initialize global data */ - g_displayLevel = (int)parameters.zParams.notificationLevel; + const int displayLevel = (int)parameters.zParams.notificationLevel; /* Assign splitPoint and f if not provided */ parameters.splitPoint = 1.0; parameters.f = parameters.f == 0 ? DEFAULT_F : parameters.f; @@ -585,13 +583,13 @@ ZDICT_trainFromBuffer_fastCover(void* dictBuffer, size_t dictBufferCapacity, { size_t const initVal = FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, coverParams.d, parameters.splitPoint, parameters.f, - accelParams); + accelParams, displayLevel); if (ZSTD_isError(initVal)) { DISPLAYLEVEL(1, "Failed to initialize context\n"); return initVal; } } - COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.nbDmers, g_displayLevel); + COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.nbDmers, displayLevel); /* Build the dictionary */ DISPLAYLEVEL(2, "Building dictionary\n"); { @@ -646,25 +644,26 @@ ZDICT_optimizeTrainFromBuffer_fastCover( COVER_best_t best; POOL_ctx *pool = NULL; int warned = 0; + clock_t lastUpdateTime = 0; /* Checks */ if (splitPoint <= 0 || splitPoint > 1) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect splitPoint\n"); + DISPLAYLEVEL(1, "Incorrect splitPoint\n"); return ERROR(parameter_outOfBound); } if (accel == 0 || accel > FASTCOVER_MAX_ACCEL) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect accel\n"); + DISPLAYLEVEL(1, "Incorrect accel\n"); return ERROR(parameter_outOfBound); } if (kMinK < kMaxD || kMaxK < kMinK) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect k\n"); + DISPLAYLEVEL(1, "Incorrect k\n"); return ERROR(parameter_outOfBound); } if (nbSamples == 0) { - LOCALDISPLAYLEVEL(displayLevel, 1, "FASTCOVER must have at least one input file\n"); + DISPLAYLEVEL(1, "FASTCOVER must have at least one input file\n"); return ERROR(srcSize_wrong); } if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) { - LOCALDISPLAYLEVEL(displayLevel, 1, "dictBufferCapacity must be at least %u\n", + DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n", ZDICT_DICTSIZE_MIN); return ERROR(dstSize_tooSmall); } @@ -679,19 +678,18 @@ ZDICT_optimizeTrainFromBuffer_fastCover( memset(&coverParams, 0 , sizeof(coverParams)); FASTCOVER_convertToCoverParams(*parameters, &coverParams); accelParams = FASTCOVER_defaultAccelParameters[accel]; - /* Turn down global display level to clean up display at level 2 and below */ - g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1; /* Loop through d first because each new value needs a new context */ - LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n", - kIterations); + DISPLAYLEVEL(2, "Trying %u different sets of parameters\n", kIterations); for (d = kMinD; d <= kMaxD; d += 2) { /* Initialize the context for this value of d */ FASTCOVER_ctx_t ctx; - LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d); + DISPLAYLEVEL(3, "d=%u\n", d); { - size_t const initVal = FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint, f, accelParams); + /* Turn down global display level to clean up display at level 2 and below */ + const int childDisplayLevel = displayLevel == 0 ? 0 : displayLevel - 1; + size_t const initVal = FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint, f, accelParams, childDisplayLevel); if (ZSTD_isError(initVal)) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n"); + DISPLAYLEVEL(1, "Failed to initialize context\n"); COVER_best_destroy(&best); POOL_free(pool); return initVal; @@ -706,9 +704,9 @@ ZDICT_optimizeTrainFromBuffer_fastCover( /* Prepare the arguments */ FASTCOVER_tryParameters_data_t *data = (FASTCOVER_tryParameters_data_t *)malloc( sizeof(FASTCOVER_tryParameters_data_t)); - LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k); + DISPLAYLEVEL(3, "k=%u\n", k); if (!data) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n"); + DISPLAYLEVEL(1, "Failed to allocate parameters\n"); COVER_best_destroy(&best); FASTCOVER_ctx_destroy(&ctx); POOL_free(pool); @@ -723,7 +721,7 @@ ZDICT_optimizeTrainFromBuffer_fastCover( data->parameters.splitPoint = splitPoint; data->parameters.steps = kSteps; data->parameters.shrinkDict = shrinkDict; - data->parameters.zParams.notificationLevel = (unsigned)g_displayLevel; + data->parameters.zParams.notificationLevel = (unsigned)ctx.displayLevel; /* Check the parameters */ if (!FASTCOVER_checkParameters(data->parameters, dictBufferCapacity, data->ctx->f, accel)) { @@ -739,14 +737,15 @@ ZDICT_optimizeTrainFromBuffer_fastCover( FASTCOVER_tryParameters(data); } /* Print status */ - LOCALDISPLAYUPDATE(displayLevel, 2, "\r%u%% ", - (unsigned)((iteration * 100) / kIterations)); + DISPLAYUPDATE(lastUpdateTime, + 2, "\r%u%% ", + (unsigned)((iteration * 100) / kIterations)); ++iteration; } COVER_best_wait(&best); FASTCOVER_ctx_destroy(&ctx); } - LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", ""); + DISPLAYLEVEL(2, "\r%79s\r", ""); /* Fill the output buffer and parameters with output of the best parameters */ { const size_t dictSize = best.dictSize; From 0de49919425a82552bc0e5273c5e30537f0e1708 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 6 Mar 2025 17:31:57 -0500 Subject: [PATCH 048/245] Add a method for checking if ZSTD was compiled with flags that impact determinism --- lib/common/portability_macros.h | 19 +++++++++++++++++++ lib/common/zstd_common.c | 9 +++++++++ lib/zstd.h | 12 ++++++++++++ programs/zstdcli.c | 5 ++++- 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/common/portability_macros.h b/lib/common/portability_macros.h index 860734141..bcca634e4 100644 --- a/lib/common/portability_macros.h +++ b/lib/common/portability_macros.h @@ -168,4 +168,23 @@ # define ZSTD_CET_ENDBRANCH #endif +/** + * ZSTD_IS_DETERMINISTIC_BUILD must be set to 0 if any compilation macro is + * active that impacts the compressed output. + * + * NOTE: ZSTD_MULTITHREAD is allowed to be set or unset. + */ +#if defined(ZSTD_CLEVEL_DEFAULT) \ + || defined(ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR) \ + || defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \ + || defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \ + || defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \ + || defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \ + || defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \ + || defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR) +# define ZSTD_IS_DETERMINISTIC_BUILD 0 +#else +# define ZSTD_IS_DETERMINISTIC_BUILD 1 +#endif + #endif /* ZSTD_PORTABILITY_MACROS_H */ diff --git a/lib/common/zstd_common.c b/lib/common/zstd_common.c index 3f04c22ab..985420618 100644 --- a/lib/common/zstd_common.c +++ b/lib/common/zstd_common.c @@ -46,3 +46,12 @@ ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); } /*! ZSTD_getErrorString() : * provides error code string from enum */ const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); } + +int ZSTD_isDeterministicBuild(void) +{ +#if ZSTD_IS_DETERMINISTIC_BUILD + return 1; +#else + return 0; +#endif +} diff --git a/lib/zstd.h b/lib/zstd.h index b8c0644a7..4ce2f7742 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -3138,6 +3138,18 @@ ZSTDLIB_STATIC_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); +/*! ZSTD_isDeterministicBuild() : + * Returns 1 if the library is built using standard compilation flags, + * and participates in determinism guarantees with other builds of the + * same version. + * If this function returns 0, it means the library was compiled with + * non-standard compilation flags that change the output of the + * compressor. + * This is mainly used for Zstd's determinism test suite, which is only + * run when this function returns 1. + */ +ZSTDLIB_API int ZSTD_isDeterministicBuild(void); + /* ========================================= */ /** Block level API (DEPRECATED) */ diff --git a/programs/zstdcli.c b/programs/zstdcli.c index e2771f534..66e9d064b 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -695,7 +695,10 @@ static void printVersion(void) #ifdef PLATFORM_POSIX_VERSION DISPLAYOUT("PLATFORM_POSIX_VERSION defined: %ldL\n", (long) PLATFORM_POSIX_VERSION); #endif - } } + + if (!ZSTD_isDeterministicBuild()) { + DISPLAYOUT("non-deterministic build\n"); + } } } } #define ZSTD_NB_STRATEGIES 9 From b16d193512d3ded82fd584fa822c19ecf67b09a0 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 6 Mar 2025 14:14:38 -0500 Subject: [PATCH 049/245] [test] Add tests for determinism Run compression & validate the compressed file matches a known checksum. To update the output run: ``` make -C tests update-cli-tests ``` --- .github/workflows/dev-short-tests.yml | 3 + tests/Makefile | 6 +- tests/cli-tests/common/platform.sh | 11 + tests/cli-tests/determinism/basic.sh | 36 + .../determinism/basic.sh.stderr.exact | 0 .../determinism/basic.sh.stdout.exact | 880 ++++++++++++++++++ tests/cli-tests/determinism/multithread.sh | 45 + .../determinism/multithread.sh.stderr.exact | 0 .../determinism/multithread.sh.stdout.exact | 260 ++++++ tests/cli-tests/determinism/reuse.sh | 44 + .../determinism/reuse.sh.stderr.exact | 0 .../determinism/reuse.sh.stdout.exact | 19 + tests/cli-tests/determinism/setup | 5 + tests/cli-tests/determinism/setup_once | 30 + tests/cli-tests/run.py | 1 + 15 files changed, 1339 insertions(+), 1 deletion(-) create mode 100755 tests/cli-tests/determinism/basic.sh create mode 100644 tests/cli-tests/determinism/basic.sh.stderr.exact create mode 100644 tests/cli-tests/determinism/basic.sh.stdout.exact create mode 100755 tests/cli-tests/determinism/multithread.sh create mode 100644 tests/cli-tests/determinism/multithread.sh.stderr.exact create mode 100644 tests/cli-tests/determinism/multithread.sh.stdout.exact create mode 100755 tests/cli-tests/determinism/reuse.sh create mode 100644 tests/cli-tests/determinism/reuse.sh.stderr.exact create mode 100644 tests/cli-tests/determinism/reuse.sh.stdout.exact create mode 100755 tests/cli-tests/determinism/setup create mode 100755 tests/cli-tests/determinism/setup_once diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 2e476d72b..2a97c32d0 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -36,6 +36,7 @@ jobs: sudo apt update APT_PACKAGES="gcc-multilib" make apt-install CFLAGS="-m32 -O1 -fstack-protector" make check V=1 + CFLAGS="-m32 -O1 -fstack-protector" make V=1 -C tests test-cli-tests build-c89: runs-on: ubuntu-latest @@ -496,6 +497,7 @@ jobs: run: | make clean LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j check + LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j -C tests test-cli-tests # This test is only compatible with standard libraries that support BTI (Branch Target Identification). # Unfortunately, the standard library provided on Ubuntu 24.04 does not have this feature enabled. # make clean @@ -734,3 +736,4 @@ jobs: run: | source /opt/intel/oneapi/setvars.sh make CC=icx check + make CC=icx -C tests test-cli-tests diff --git a/tests/Makefile b/tests/Makefile index 406c7f20b..b96986cae 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -359,7 +359,11 @@ test-zstd test-zstd32 test-zstd-nolegacy test-zstd-dll: datagen test-cli-tests: ZSTD = $(PRGDIR)/zstd test-cli-tests: zstd datagen file $(ZSTD) - ./cli-tests/run.py --exec-prefix="$(QEMU_SYS)" --zstd="$(ZSTD)" --datagen=./datagen + ./cli-tests/run.py --exec-prefix="$(QEMU_SYS)" --zstd="$(ZSTD)" --datagen=./datagen $(CLI_TEST_ARGS) + +.PHONY: update-cli-tests +update-cli-tests: CLI_TEST_ARGS = --set-exact-output +update-cli-tests: test-cli-tests .PHONY: test-fullbench test-fullbench: fullbench datagen diff --git a/tests/cli-tests/common/platform.sh b/tests/cli-tests/common/platform.sh index a07f229dc..a5bd2f9dc 100644 --- a/tests/cli-tests/common/platform.sh +++ b/tests/cli-tests/common/platform.sh @@ -23,6 +23,11 @@ case "$UNAME" in *) MD5SUM="md5sum" ;; esac +md5hash() { + $MD5SUM | dd bs=1 count=32 status=none + echo +} + DIFF="diff" case "$UNAME" in SunOS) DIFF="gdiff" ;; @@ -34,3 +39,9 @@ then else hasMT="true" fi + +if zstd -vv --version | grep -q 'non-deterministic'; then + NON_DETERMINISTIC="true" +else + NON_DETERMINISTIC="" +fi diff --git a/tests/cli-tests/determinism/basic.sh b/tests/cli-tests/determinism/basic.sh new file mode 100755 index 000000000..7d49956c8 --- /dev/null +++ b/tests/cli-tests/determinism/basic.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +. "$COMMON/platform.sh" + +set -e + +# To update checksums on version change run this from the tests/ directory +# make update-cli-tests + +if [ -n "$NON_DETERMINISTIC" ]; then + # Skip tests if we have a non-deterministic build + cat "$CLI_TESTS/determinism/basic.sh.stdout.exact" + exit 0 +fi + +for level in $(seq 1 19); do + for file in $(ls files/); do + file="files/$file" + echo "level $level, file $file" + zstd --single-thread -q -$level $file -c | md5hash + done +done + +for file in $(ls files/); do + file="files/$file" + echo "level 1, long=18, file $file" + zstd --long=18 --single-thread -q -1 $file -c | md5hash + echo "level 19, long=18, file $file" + zstd --long=18 --single-thread -q -19 $file -c | md5hash +done + +for file in $(ls files/); do + file="files/$file" + echo "level -1, file $file" + zstd -q --single-thread --fast=1 $file -c | md5hash +done diff --git a/tests/cli-tests/determinism/basic.sh.stderr.exact b/tests/cli-tests/determinism/basic.sh.stderr.exact new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cli-tests/determinism/basic.sh.stdout.exact b/tests/cli-tests/determinism/basic.sh.stdout.exact new file mode 100644 index 000000000..bb1723b15 --- /dev/null +++ b/tests/cli-tests/determinism/basic.sh.stdout.exact @@ -0,0 +1,880 @@ +level 1, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 1, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 1, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 1, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 1, file files/g1000 +6bf2f4b179864fd8db4676037465feed +level 1, file files/g10000 +2ae44c4053b2b47724c8f612dfb60d24 +level 1, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 1, file files/g10000-P10 +2d0eeab6a966098583a1dfeafb5090c1 +level 1, file files/g10000-P100 +93436482b4da30ce2300d356448c8990 +level 1, file files/g10000-P25 +c64b5f512c44b6a647da81753791b9a7 +level 1, file files/g10000-P50 +3982325490d90c8307e734c1b25790df +level 1, file files/g10000-P75 +b7504f80fee16b5ba6a0f46571eb563a +level 1, file files/g10000-P90 +350892bec7f7ad6a7d6af01c5d8b07c7 +level 1, file files/g100000 +daa38a869130494c077290cf54f2d895 +level 1, file files/g1000000 +a1d548531221d408b95dc5d9c600b3f0 +level 1, file files/g20000 +1da5b56511e8693867c0cdd962c521aa +level 1, file files/g200000 +41fb3b3d46d4221f2f0b072c65dd6e0a +level 1, file files/g30000 +788bc5abca5e33d79bb79a4eca98b9cd +level 1, file files/g50000 +0bf9fafd84a2d56a788a9159f1f23f26 +level 1, file files/g500000 +73401d6df0657e091de20468f32579a9 +level 2, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 2, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 2, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 2, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 2, file files/g1000 +a14988fb331bc6f8b33d9eba3a0416dc +level 2, file files/g10000 +a8656ebab20efa8a3fb281327aab5d58 +level 2, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 2, file files/g10000-P10 +9db9877242632964c232ebd4485dba07 +level 2, file files/g10000-P100 +93436482b4da30ce2300d356448c8990 +level 2, file files/g10000-P25 +d7a7223240a607fe28a2e8fd641a969d +level 2, file files/g10000-P50 +86478908f9caa5ca4029454005063078 +level 2, file files/g10000-P75 +14f5dcdb347e87790d49c1eb99ac5069 +level 2, file files/g10000-P90 +05bdb42a2eeb5788d6288dc241cde12c +level 2, file files/g100000 +12c6a4c50fad3e479e0f0ffe1d4df324 +level 2, file files/g1000000 +4f9cdc0de37b22d657fd9d3c61ec5b44 +level 2, file files/g20000 +1e70c3fe429c1af41e9cb8a536fb6df1 +level 2, file files/g200000 +bb1cc37142783345db29c3fd5838ce4e +level 2, file files/g30000 +52528017fe0eec85b6c3244e6fceb4ed +level 2, file files/g50000 +a38bdd671b6d3bd76b479dfc01d1c7fb +level 2, file files/g500000 +cd2090a38bbd677b385238355c996c01 +level 3, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 3, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 3, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 3, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 3, file files/g1000 +3ec47dcb2d606b9fdef3f19b1304f8fe +level 3, file files/g10000 +69a9d518b84fe2a66b57dfb4ab8905ae +level 3, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 3, file files/g10000-P10 +ac9866ac355c4ed8939deb9fbeec1aef +level 3, file files/g10000-P100 +93436482b4da30ce2300d356448c8990 +level 3, file files/g10000-P25 +5e1fe7a3831f6632bc8c9873ab8b633d +level 3, file files/g10000-P50 +76295f181396a98565eb9cc69b96dc75 +level 3, file files/g10000-P75 +1f751dc70508e81fef197311e8583e99 +level 3, file files/g10000-P90 +47c7b061c299dc253c6aaaf489e936cb +level 3, file files/g100000 +4b30b2be3394f03f1cf1f37a08dcec12 +level 3, file files/g1000000 +4301dea72cc4dd6162e46caa59788a09 +level 3, file files/g20000 +30456361833d27c0962c2faaa254e615 +level 3, file files/g200000 +0f01c07c57d60298dd54c6b6b197c3d3 +level 3, file files/g30000 +0b3c506a1b1b6ccbb54a852c370f5cdc +level 3, file files/g50000 +81368c0b96bf1a2f318940b836b46074 +level 3, file files/g500000 +0c1ef9c6d3d75bfa0dd5d893f65da47c +level 4, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 4, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 4, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 4, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 4, file files/g1000 +6a1214c19ab13d15934244a4655fa327 +level 4, file files/g10000 +09bbd556d9ee9f74f36b36bfa6b17325 +level 4, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 4, file files/g10000-P10 +1adb177b7a441c3585ffd781654758ba +level 4, file files/g10000-P100 +93436482b4da30ce2300d356448c8990 +level 4, file files/g10000-P25 +3a62170477d7f17d64dc49b971388ff7 +level 4, file files/g10000-P50 +de93403eafd68786410fa52a95752514 +level 4, file files/g10000-P75 +f5466b3cfc3ba1e5afecb8d8bb91250f +level 4, file files/g10000-P90 +132869db4091a9b9bdbc5236435a1d98 +level 4, file files/g100000 +dd92f22c593f40e0ccd6b31ad09d9d18 +level 4, file files/g1000000 +cfe7c063909c635f22438f83eb824082 +level 4, file files/g20000 +f8be159b057c6ee827f36cdd2ee5c43f +level 4, file files/g200000 +71362cc7c28dcc730b591e3002fe888c +level 4, file files/g30000 +f0b899995c6ba86066bd7f407fc708ef +level 4, file files/g50000 +2f293e665d5161e68d8e1f86ac6841be +level 4, file files/g500000 +42c5c45c595af60d5cf28f4cdd8ab392 +level 5, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 5, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 5, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 5, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 5, file files/g1000 +d47284586e181d455017d821bd3de1ef +level 5, file files/g10000 +d6cd223f1c215d332654ca241a376549 +level 5, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 5, file files/g10000-P10 +66b935a7666ae668ac990d5c9aaac652 +level 5, file files/g10000-P100 +15fede9faa3d7c484dead66071fb8c5d +level 5, file files/g10000-P25 +b292339cacea797a184554a2de3c1ed3 +level 5, file files/g10000-P50 +10b65af5125bf21a6810b8fb7a30b8b1 +level 5, file files/g10000-P75 +04fc60ea83db4b6101778f91a73d6040 +level 5, file files/g10000-P90 +302c8c7355082a7f40efe4ea40912411 +level 5, file files/g100000 +338f5e822a469774462f144d7ae371a0 +level 5, file files/g1000000 +46b8608a1f833477387e2fc844a817d5 +level 5, file files/g20000 +b7a468d363a7797d3d7a48577cd20213 +level 5, file files/g200000 +5ed09b3fd58ba540128319c02f9259cb +level 5, file files/g30000 +fd4c0e5acb85271c101fd8ae1f411232 +level 5, file files/g50000 +2a14c76d629615bd50a370e587d13eb8 +level 5, file files/g500000 +cb1122167d4a747f3f8e0dd18bce6fa3 +level 6, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 6, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 6, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 6, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 6, file files/g1000 +19187f900e7540efdcab3735f489f718 +level 6, file files/g10000 +70c03e642fb98b896f2d96c0fa0eca74 +level 6, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 6, file files/g10000-P10 +70e2df33337095c818051d86ea68f188 +level 6, file files/g10000-P100 +15fede9faa3d7c484dead66071fb8c5d +level 6, file files/g10000-P25 +dd4ed2ced4ae48672d5c8c0d4a7d58a5 +level 6, file files/g10000-P50 +9182b845f45f4990c8993e1c54e1e2e6 +level 6, file files/g10000-P75 +d3e6bb5a8e9790d23dda0a38b3def532 +level 6, file files/g10000-P90 +21da6c8aefa00b3e16f7674c642aa043 +level 6, file files/g100000 +350a0f07d7ddbcd0c629da0bcf734f02 +level 6, file files/g1000000 +d40c700beee149ab272b94c7ef0f3811 +level 6, file files/g20000 +335bc3f5767a7d4ad479408b0e289459 +level 6, file files/g200000 +032e3313ca247a8f4687059fa708284c +level 6, file files/g30000 +a4b9fed2e1005298617125ee3b00cb06 +level 6, file files/g50000 +d7b3dab8d19fb992795c440d5f953c94 +level 6, file files/g500000 +44e59ccbf7a9794d4ea03f3f59f61ffd +level 7, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 7, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 7, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 7, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 7, file files/g1000 +19187f900e7540efdcab3735f489f718 +level 7, file files/g10000 +495f1e5d30de3b34c5a76301875fa231 +level 7, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 7, file files/g10000-P10 +8a91fa2460ec9bd0387baa31beb81060 +level 7, file files/g10000-P100 +15fede9faa3d7c484dead66071fb8c5d +level 7, file files/g10000-P25 +7dc0563f2e66a2e57c0f119e4d5e636e +level 7, file files/g10000-P50 +e93a6eb179f7b26daa896328b2583b04 +level 7, file files/g10000-P75 +cb1e5facfc34fca7323000c6188ad657 +level 7, file files/g10000-P90 +e9984c6557f5a392f16e5c139dbe4994 +level 7, file files/g100000 +6e493dbe2985fec69860ef34728ac01a +level 7, file files/g1000000 +455023a055f3a4de76c7295408ce3c8f +level 7, file files/g20000 +2359efcd587e36ac9b74a8344bbf0e53 +level 7, file files/g200000 +ca80dbc88183a5aabb4aae955c449dff +level 7, file files/g30000 +7e1be7e841c9fddd776dbe94b50db0ab +level 7, file files/g50000 +09b80b58d70622de6f2354a06c15cb2a +level 7, file files/g500000 +c90609f0558f0979eccb572ce0af4aa3 +level 8, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 8, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 8, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 8, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 8, file files/g1000 +19187f900e7540efdcab3735f489f718 +level 8, file files/g10000 +495f1e5d30de3b34c5a76301875fa231 +level 8, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 8, file files/g10000-P10 +8a91fa2460ec9bd0387baa31beb81060 +level 8, file files/g10000-P100 +15fede9faa3d7c484dead66071fb8c5d +level 8, file files/g10000-P25 +526c95fd77cbcc2079720bb1b5515a54 +level 8, file files/g10000-P50 +50d4e0154067af438e56729716c3eda7 +level 8, file files/g10000-P75 +c94a94cce795566b065f2d3dca554c28 +level 8, file files/g10000-P90 +8f83ce03eb280cba48bafafbd066b752 +level 8, file files/g100000 +dbc4c43d9dc0937e67e92a908688a51e +level 8, file files/g1000000 +5a4e6e44c89c3538fdb09823e649c8f6 +level 8, file files/g20000 +3653750b7ea2e8dc97d1d24ccec72153 +level 8, file files/g200000 +e978eb15e94cf221f1c7c55a059bbc4a +level 8, file files/g30000 +9668f8c1292931955e14b81d67c2c648 +level 8, file files/g50000 +36a864d5bb5d9167d19ac237ce3bef51 +level 8, file files/g500000 +eaaac1f3c4861d4d501d9c92fa67cc08 +level 9, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 9, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 9, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 9, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 9, file files/g1000 +42d1f8aa9ee42135013077f09b77fd1a +level 9, file files/g10000 +ae4166250554922e9ed27e436c13bf6b +level 9, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 9, file files/g10000-P10 +bd9ede6738524ef732c9516146536acd +level 9, file files/g10000-P100 +93436482b4da30ce2300d356448c8990 +level 9, file files/g10000-P25 +526c95fd77cbcc2079720bb1b5515a54 +level 9, file files/g10000-P50 +af6f029bd0d9baee1a78b8f7ffef5df3 +level 9, file files/g10000-P75 +f56895eec07a63269ea3eaeb59e87f40 +level 9, file files/g10000-P90 +c5cef2890886bfaf2d747b37ededc261 +level 9, file files/g100000 +f11c301dcf8c791e4f2db29e1b388eba +level 9, file files/g1000000 +f90563e0d0962955d31af45fc8f2b19d +level 9, file files/g20000 +49820710f3fbc6627b60071e91dba56d +level 9, file files/g200000 +4689b0eb28c34619d8a9087cfa33fc88 +level 9, file files/g30000 +c14b029711fa6abc627ed3a051902b4c +level 9, file files/g50000 +2d1cde6271f46081fbeaaba10f1c48bb +level 9, file files/g500000 +eaaac1f3c4861d4d501d9c92fa67cc08 +level 10, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 10, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 10, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 10, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 10, file files/g1000 +42d1f8aa9ee42135013077f09b77fd1a +level 10, file files/g10000 +ae4166250554922e9ed27e436c13bf6b +level 10, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 10, file files/g10000-P10 +bd9ede6738524ef732c9516146536acd +level 10, file files/g10000-P100 +93436482b4da30ce2300d356448c8990 +level 10, file files/g10000-P25 +526c95fd77cbcc2079720bb1b5515a54 +level 10, file files/g10000-P50 +6f821eef670933208d85daad6a9a2791 +level 10, file files/g10000-P75 +9c944c50c800d72294bdc9a9a452dc90 +level 10, file files/g10000-P90 +838a22c0731a67d185cac135b2bac5c7 +level 10, file files/g100000 +bbb2e91bdee192ae6f23404542a35bfb +level 10, file files/g1000000 +1e52803b3311c2d4428c56d059901721 +level 10, file files/g20000 +939b50f472cf67c6dfbc4d3074e04011 +level 10, file files/g200000 +adc5f0c58c75e79e4bc4800c015d2401 +level 10, file files/g30000 +43e46ec5aae76c55c890a18f49b0163b +level 10, file files/g50000 +65c57573aef37a38bd6c587ef4388800 +level 10, file files/g500000 +d3c45fce79c26bce889c3fa6a5480200 +level 11, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 11, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 11, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 11, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 11, file files/g1000 +4aa08662527d6d7f996705929e0dd8e0 +level 11, file files/g10000 +330f75029558d7cb6fa2756d85a998bd +level 11, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 11, file files/g10000-P10 +990879c5b3d1c99aa5ef39f6049cebc9 +level 11, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 11, file files/g10000-P25 +26a10f96c2008608a33a731ff39cd9c8 +level 11, file files/g10000-P50 +129c6082daea0da5f52358c71b252750 +level 11, file files/g10000-P75 +7ff21b2c10548b9fc8ec5b61f86b9db0 +level 11, file files/g10000-P90 +0def9775620838420b295c07fd50a196 +level 11, file files/g100000 +c115057c51f9bb603a7d0c6bdf76e422 +level 11, file files/g1000000 +d28d3aed914ba7368dd004a9431c0173 +level 11, file files/g20000 +650cf27ffca49ed98f0e5dbb8997d7eb +level 11, file files/g200000 +3210b89239e35e559be0ccd842577bb4 +level 11, file files/g30000 +09fe5a276e3fec09490c85962263fb26 +level 11, file files/g50000 +a9fa2677e4faab0eaa2334f278b3ec7d +level 11, file files/g500000 +86815b1a35a46312a081f1af4946a62e +level 12, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 12, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 12, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 12, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 12, file files/g1000 +6cb98f0115baf96a720638cf92b7803b +level 12, file files/g10000 +b73485abce0df9802dcfeee652c45a8d +level 12, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 12, file files/g10000-P10 +d00ac554fefc8a0f40420f908ff6fe69 +level 12, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 12, file files/g10000-P25 +9e20110ea128e4201c9a09eb48ad16c8 +level 12, file files/g10000-P50 +07287871c8b4ec3b5a925563a97451ce +level 12, file files/g10000-P75 +2a47bb2eb7fb84a157f4525da9f78a77 +level 12, file files/g10000-P90 +d9c87f3f0faf212ec2d60cb611dac8a9 +level 12, file files/g100000 +d5d45068ded1319342ac3b7867d8c8fd +level 12, file files/g1000000 +d28d3aed914ba7368dd004a9431c0173 +level 12, file files/g20000 +650cf27ffca49ed98f0e5dbb8997d7eb +level 12, file files/g200000 +077d0f0ef9e9af86b1a298624fc70062 +level 12, file files/g30000 +09fe5a276e3fec09490c85962263fb26 +level 12, file files/g50000 +a9fa2677e4faab0eaa2334f278b3ec7d +level 12, file files/g500000 +86815b1a35a46312a081f1af4946a62e +level 13, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 13, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 13, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 13, file files/g100 +e6e88e42b891fbc82c87a60928d88e97 +level 13, file files/g1000 +773b6b59d472db0932b5ad1ad75eac64 +level 13, file files/g10000 +dfd1e66b36c80b191c338d0b14813920 +level 13, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 13, file files/g10000-P10 +40b5f47e143e235198f6408a099208e8 +level 13, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 13, file files/g10000-P25 +deaa99c2458ca8ea661b358ef837ef58 +level 13, file files/g10000-P50 +dd575cdc1ac009a7f2407013063d02e3 +level 13, file files/g10000-P75 +0d411eb9beee65c6f5dd7764b639097b +level 13, file files/g10000-P90 +61db327f8fdd9a735e68259f05f71f0d +level 13, file files/g100000 +dece3af6a1b7ef4ab80cad69119a3b61 +level 13, file files/g1000000 +916989f734410afce6b3ae72a3352e68 +level 13, file files/g20000 +7ce4e5c10392cbae28ed79b0707f627f +level 13, file files/g200000 +ab3d3f2a0fb5d4e54f8e799213d7e995 +level 13, file files/g30000 +61f3ce2b87a584169e92791fa54c7361 +level 13, file files/g50000 +aba34c68e1d812fab8ce9863169e050b +level 13, file files/g500000 +9f16a159f5fa88b875e5c1e0574a999c +level 14, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 14, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 14, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 14, file files/g100 +e6e88e42b891fbc82c87a60928d88e97 +level 14, file files/g1000 +773b6b59d472db0932b5ad1ad75eac64 +level 14, file files/g10000 +dfd1e66b36c80b191c338d0b14813920 +level 14, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 14, file files/g10000-P10 +40b5f47e143e235198f6408a099208e8 +level 14, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 14, file files/g10000-P25 +deaa99c2458ca8ea661b358ef837ef58 +level 14, file files/g10000-P50 +246b1782db44f4226d32c8718e39ac8c +level 14, file files/g10000-P75 +023a4c9c041fbcd4f584d5e65f9b4444 +level 14, file files/g10000-P90 +d57d3ce213e81d7ce80930115afc9f71 +level 14, file files/g100000 +29c1d79c3dc1dc51ec4ee3fd19fdbd10 +level 14, file files/g1000000 +7721785c341760a66ac9e2fb39cfeb33 +level 14, file files/g20000 +1055a0a808598d1eedf0442fceff44e0 +level 14, file files/g200000 +87df6235943fd09ba3f6a1f24cbc3a3a +level 14, file files/g30000 +74c32e0cd8bcd62bd4e1cf599c193abf +level 14, file files/g50000 +10d3bbb5e9822fa5c31fc2e79aeae7e9 +level 14, file files/g500000 +f8865d65f1790f723184007b2f940127 +level 15, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 15, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 15, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 15, file files/g100 +e6e88e42b891fbc82c87a60928d88e97 +level 15, file files/g1000 +773b6b59d472db0932b5ad1ad75eac64 +level 15, file files/g10000 +dfd1e66b36c80b191c338d0b14813920 +level 15, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 15, file files/g10000-P10 +40b5f47e143e235198f6408a099208e8 +level 15, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 15, file files/g10000-P25 +deaa99c2458ca8ea661b358ef837ef58 +level 15, file files/g10000-P50 +91cc04148eef18ae4222038ad05f0586 +level 15, file files/g10000-P75 +aa5e9e619fe89644098c9ad17a8b9ad4 +level 15, file files/g10000-P90 +28d6d71a33f507d1e7acd56d586e3981 +level 15, file files/g100000 +29c1d79c3dc1dc51ec4ee3fd19fdbd10 +level 15, file files/g1000000 +de1091b6021db006820019edfcb1384c +level 15, file files/g20000 +1055a0a808598d1eedf0442fceff44e0 +level 15, file files/g200000 +0096718cf88b77da67fc2211bf85e3ca +level 15, file files/g30000 +74c32e0cd8bcd62bd4e1cf599c193abf +level 15, file files/g50000 +10d3bbb5e9822fa5c31fc2e79aeae7e9 +level 15, file files/g500000 +53aa49e42ffac4621397b88d4749c9c0 +level 16, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 16, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 16, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 16, file files/g100 +e6e88e42b891fbc82c87a60928d88e97 +level 16, file files/g1000 +f3eeeae11e293292fe1810d8745d0ae1 +level 16, file files/g10000 +23c5d58cca20ab65ff8a5d780f09e075 +level 16, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 16, file files/g10000-P10 +cced9c0f5709262da932fc8540bb72f4 +level 16, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 16, file files/g10000-P25 +6676c9b599408491f7abc00947782054 +level 16, file files/g10000-P50 +9af82247b7fe18900592ae4fd5f1890a +level 16, file files/g10000-P75 +d44f2305f023fbff3d1a872ab740958a +level 16, file files/g10000-P90 +517f98319c717526b5e211079f073fbc +level 16, file files/g100000 +95ec61667f371a3621b34a042f1f4a0a +level 16, file files/g1000000 +b71641629b58754f1961ac394f177d7c +level 16, file files/g20000 +7bd4e03d703ead21e15fddd4423ef79e +level 16, file files/g200000 +fd1c701e9872f304a71f0e7f7aa9f918 +level 16, file files/g30000 +bc2211b250b5f4ed0a7bd97d447132e0 +level 16, file files/g50000 +a6d98ebd2ed96688482c7d1181dded42 +level 16, file files/g500000 +44e339bb9e57842b77476f6d75ff3fbd +level 17, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 17, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 17, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 17, file files/g100 +e6e88e42b891fbc82c87a60928d88e97 +level 17, file files/g1000 +f3eeeae11e293292fe1810d8745d0ae1 +level 17, file files/g10000 +23c5d58cca20ab65ff8a5d780f09e075 +level 17, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 17, file files/g10000-P10 +cced9c0f5709262da932fc8540bb72f4 +level 17, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 17, file files/g10000-P25 +6676c9b599408491f7abc00947782054 +level 17, file files/g10000-P50 +607968cd37d41631312307f6c8a37ab4 +level 17, file files/g10000-P75 +818c2b0124e0dad26f9d95d753b11140 +level 17, file files/g10000-P90 +2d01bb79185ec88e5d7e684d3983eff8 +level 17, file files/g100000 +95ec61667f371a3621b34a042f1f4a0a +level 17, file files/g1000000 +cbd03f012664a02441271c50ba1330bf +level 17, file files/g20000 +7bd4e03d703ead21e15fddd4423ef79e +level 17, file files/g200000 +fd1c701e9872f304a71f0e7f7aa9f918 +level 17, file files/g30000 +bc2211b250b5f4ed0a7bd97d447132e0 +level 17, file files/g50000 +a6d98ebd2ed96688482c7d1181dded42 +level 17, file files/g500000 +01223076923dc7e3e06eeb3d71c467d2 +level 18, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 18, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 18, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 18, file files/g100 +e6e88e42b891fbc82c87a60928d88e97 +level 18, file files/g1000 +f3eeeae11e293292fe1810d8745d0ae1 +level 18, file files/g10000 +23c5d58cca20ab65ff8a5d780f09e075 +level 18, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 18, file files/g10000-P10 +cced9c0f5709262da932fc8540bb72f4 +level 18, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 18, file files/g10000-P25 +6676c9b599408491f7abc00947782054 +level 18, file files/g10000-P50 +c61ad9309da86f7229498e46daacd6d9 +level 18, file files/g10000-P75 +8bf1c42a6a1f46ff8549e87f7b6daa54 +level 18, file files/g10000-P90 +29077b7a282975006c20701bca0d439d +level 18, file files/g100000 +95ec61667f371a3621b34a042f1f4a0a +level 18, file files/g1000000 +1e598049810de86924756bcda8941085 +level 18, file files/g20000 +7bd4e03d703ead21e15fddd4423ef79e +level 18, file files/g200000 +ab03b5ab84b6ebe79fa325118a895c6b +level 18, file files/g30000 +bc2211b250b5f4ed0a7bd97d447132e0 +level 18, file files/g50000 +a6d98ebd2ed96688482c7d1181dded42 +level 18, file files/g500000 +1b5374095c0bdc676655fe4db94286d1 +level 19, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 19, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 19, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 19, file files/g100 +e6e88e42b891fbc82c87a60928d88e97 +level 19, file files/g1000 +f3eeeae11e293292fe1810d8745d0ae1 +level 19, file files/g10000 +23c5d58cca20ab65ff8a5d780f09e075 +level 19, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 19, file files/g10000-P10 +cced9c0f5709262da932fc8540bb72f4 +level 19, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 19, file files/g10000-P25 +6676c9b599408491f7abc00947782054 +level 19, file files/g10000-P50 +c61ad9309da86f7229498e46daacd6d9 +level 19, file files/g10000-P75 +d3171f297dfd08e444d481b30b1bbefa +level 19, file files/g10000-P90 +87c4a59ec6e15f6da86b26969044a8a4 +level 19, file files/g100000 +7ae11dc1919d94e80979d41d12a0b578 +level 19, file files/g1000000 +d4b9ee8879d7f30bed3ec9e70520ca67 +level 19, file files/g20000 +70028792166e24282f5497592b632192 +level 19, file files/g200000 +ab03b5ab84b6ebe79fa325118a895c6b +level 19, file files/g30000 +d698feea5119e141a08656439c4c1508 +level 19, file files/g50000 +b81384753f0db76004ac97681f6ef757 +level 19, file files/g500000 +0a25ba39483255a2c16899ab80a3ed8f +level 1, long=18, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 19, long=18, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 1, long=18, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 19, long=18, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 1, long=18, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 19, long=18, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 1, long=18, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 19, long=18, file files/g100 +e6e88e42b891fbc82c87a60928d88e97 +level 1, long=18, file files/g1000 +6bf2f4b179864fd8db4676037465feed +level 19, long=18, file files/g1000 +f3eeeae11e293292fe1810d8745d0ae1 +level 1, long=18, file files/g10000 +2ae44c4053b2b47724c8f612dfb60d24 +level 19, long=18, file files/g10000 +23c5d58cca20ab65ff8a5d780f09e075 +level 1, long=18, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 19, long=18, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 1, long=18, file files/g10000-P10 +6a8f6e75ab538eb08a422febc8b68006 +level 19, long=18, file files/g10000-P10 +cced9c0f5709262da932fc8540bb72f4 +level 1, long=18, file files/g10000-P100 +5db6fbe04a2de772ad4e49f5357d0543 +level 19, long=18, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 1, long=18, file files/g10000-P25 +6fd603b31365845346faab9cd64fd647 +level 19, long=18, file files/g10000-P25 +6676c9b599408491f7abc00947782054 +level 1, long=18, file files/g10000-P50 +d1de679e9a8c962ed1cc668a96bf930a +level 19, long=18, file files/g10000-P50 +c61ad9309da86f7229498e46daacd6d9 +level 1, long=18, file files/g10000-P75 +dcf9822423e2ad42a569985707cd5ab4 +level 19, long=18, file files/g10000-P75 +f0ea19930e3866ff7a1932931346e0ac +level 1, long=18, file files/g10000-P90 +87d249fd8c1ad0064d067a1e5ad97647 +level 19, long=18, file files/g10000-P90 +582e2c4c5a06e452d8dae22e7210c070 +level 1, long=18, file files/g100000 +daa38a869130494c077290cf54f2d895 +level 19, long=18, file files/g100000 +7ae11dc1919d94e80979d41d12a0b578 +level 1, long=18, file files/g1000000 +81b9ffd138f3b25254a7078b06950e5f +level 19, long=18, file files/g1000000 +db54f06bf3abdbfd57892ab3aad18233 +level 1, long=18, file files/g20000 +1da5b56511e8693867c0cdd962c521aa +level 19, long=18, file files/g20000 +70028792166e24282f5497592b632192 +level 1, long=18, file files/g200000 +17eb9ff8d912da9c445def85cb748e54 +level 19, long=18, file files/g200000 +ab03b5ab84b6ebe79fa325118a895c6b +level 1, long=18, file files/g30000 +788bc5abca5e33d79bb79a4eca98b9cd +level 19, long=18, file files/g30000 +d698feea5119e141a08656439c4c1508 +level 1, long=18, file files/g50000 +0bf9fafd84a2d56a788a9159f1f23f26 +level 19, long=18, file files/g50000 +b81384753f0db76004ac97681f6ef757 +level 1, long=18, file files/g500000 +f035223dc02f581daf5dd79773c4dc2b +level 19, long=18, file files/g500000 +97093f718faf7b9094e27ea822fd1a29 +level -1, file files/g0 +5d80401e01d33084c65e94f93351e94c +level -1, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level -1, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level -1, file files/g100 +eb805e7fdb95bc42231b20d0e12e2a53 +level -1, file files/g1000 +ac7c900e31b9e4fe37b7846a898c7d48 +level -1, file files/g10000 +55e1e6ed7fcf5581a17f72f3a32e0834 +level -1, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level -1, file files/g10000-P10 +0bf549bdfc20b644c37901918de0d0eb +level -1, file files/g10000-P100 +93436482b4da30ce2300d356448c8990 +level -1, file files/g10000-P25 +b65475ee206e480b3adc9fcc7b79c54b +level -1, file files/g10000-P50 +ae4bf85c8343052ecb1d666bd9766fbc +level -1, file files/g10000-P75 +b0674333f519e71708f226f935ae63d5 +level -1, file files/g10000-P90 +2daa80aa34a8259fed7e04ae41397d6c +level -1, file files/g100000 +586e12a3aa574f35aedf0afadee3040c +level -1, file files/g1000000 +1cc8eb9ee1e4c20373fe3c1b0aa1a982 +level -1, file files/g20000 +b220e6387b1f5036c203f8be5f1a571c +level -1, file files/g200000 +fc42db710c19a4f4a27f004fb4678d9c +level -1, file files/g30000 +5350a7346d815f4ad42216b91ba8749a +level -1, file files/g50000 +4f00a5a94e8f98c6972053057f6ac971 +level -1, file files/g500000 +4abb2e46c936c273955778c00f3eb492 diff --git a/tests/cli-tests/determinism/multithread.sh b/tests/cli-tests/determinism/multithread.sh new file mode 100755 index 000000000..a3481dbaf --- /dev/null +++ b/tests/cli-tests/determinism/multithread.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +. "$COMMON/platform.sh" + +set -e + +# To update checksums on version change run this from the tests/ directory +# make update-cli-tests + +if [ -n "$NON_DETERMINISTIC" ] || [ -z "$hasMT" ]; then + # Skip tests if we have a non-deterministic build + cat "$CLI_TESTS/determinism/multithread.sh.stdout.exact" + exit 0 +fi + +for level in 1 3 7 19; do + for file in $(ls files/); do + file="files/$file" + echo "level $level, file $file" + zstd -T2 -q -$level $file -c | md5hash + done +done + +for file in $(ls files/); do + file="files/$file" + echo "level 1, long=18, file $file" + zstd --long=18 -T2 -q -1 $file -c | md5hash + echo "level 19, long=18, file $file" + zstd --long=18 -T2 -q -19 $file -c | md5hash +done + +for file in $(ls files/); do + file="files/$file" + echo "Vary number of threads on $file" + zstd -qf -1 $file -o $file.zst.good + + zstd -qf -T1 -1 $file + $DIFF $file.zst $file.zst.good + + zstd -qf -T2 -1 $file + $DIFF $file.zst $file.zst.good + + zstd -qf -T4 -1 $file + $DIFF $file.zst $file.zst.good +done diff --git a/tests/cli-tests/determinism/multithread.sh.stderr.exact b/tests/cli-tests/determinism/multithread.sh.stderr.exact new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cli-tests/determinism/multithread.sh.stdout.exact b/tests/cli-tests/determinism/multithread.sh.stdout.exact new file mode 100644 index 000000000..8de7664df --- /dev/null +++ b/tests/cli-tests/determinism/multithread.sh.stdout.exact @@ -0,0 +1,260 @@ +level 1, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 1, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 1, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 1, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 1, file files/g1000 +6bf2f4b179864fd8db4676037465feed +level 1, file files/g10000 +2ae44c4053b2b47724c8f612dfb60d24 +level 1, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 1, file files/g10000-P10 +2d0eeab6a966098583a1dfeafb5090c1 +level 1, file files/g10000-P100 +93436482b4da30ce2300d356448c8990 +level 1, file files/g10000-P25 +c64b5f512c44b6a647da81753791b9a7 +level 1, file files/g10000-P50 +3982325490d90c8307e734c1b25790df +level 1, file files/g10000-P75 +b7504f80fee16b5ba6a0f46571eb563a +level 1, file files/g10000-P90 +350892bec7f7ad6a7d6af01c5d8b07c7 +level 1, file files/g100000 +daa38a869130494c077290cf54f2d895 +level 1, file files/g1000000 +a1d548531221d408b95dc5d9c600b3f0 +level 1, file files/g20000 +1da5b56511e8693867c0cdd962c521aa +level 1, file files/g200000 +41fb3b3d46d4221f2f0b072c65dd6e0a +level 1, file files/g30000 +788bc5abca5e33d79bb79a4eca98b9cd +level 1, file files/g50000 +0bf9fafd84a2d56a788a9159f1f23f26 +level 1, file files/g500000 +73401d6df0657e091de20468f32579a9 +level 3, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 3, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 3, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 3, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 3, file files/g1000 +3ec47dcb2d606b9fdef3f19b1304f8fe +level 3, file files/g10000 +69a9d518b84fe2a66b57dfb4ab8905ae +level 3, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 3, file files/g10000-P10 +ac9866ac355c4ed8939deb9fbeec1aef +level 3, file files/g10000-P100 +93436482b4da30ce2300d356448c8990 +level 3, file files/g10000-P25 +5e1fe7a3831f6632bc8c9873ab8b633d +level 3, file files/g10000-P50 +76295f181396a98565eb9cc69b96dc75 +level 3, file files/g10000-P75 +1f751dc70508e81fef197311e8583e99 +level 3, file files/g10000-P90 +47c7b061c299dc253c6aaaf489e936cb +level 3, file files/g100000 +4b30b2be3394f03f1cf1f37a08dcec12 +level 3, file files/g1000000 +4301dea72cc4dd6162e46caa59788a09 +level 3, file files/g20000 +30456361833d27c0962c2faaa254e615 +level 3, file files/g200000 +0f01c07c57d60298dd54c6b6b197c3d3 +level 3, file files/g30000 +0b3c506a1b1b6ccbb54a852c370f5cdc +level 3, file files/g50000 +81368c0b96bf1a2f318940b836b46074 +level 3, file files/g500000 +0c1ef9c6d3d75bfa0dd5d893f65da47c +level 7, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 7, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 7, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 7, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 7, file files/g1000 +19187f900e7540efdcab3735f489f718 +level 7, file files/g10000 +495f1e5d30de3b34c5a76301875fa231 +level 7, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 7, file files/g10000-P10 +8a91fa2460ec9bd0387baa31beb81060 +level 7, file files/g10000-P100 +15fede9faa3d7c484dead66071fb8c5d +level 7, file files/g10000-P25 +7dc0563f2e66a2e57c0f119e4d5e636e +level 7, file files/g10000-P50 +e93a6eb179f7b26daa896328b2583b04 +level 7, file files/g10000-P75 +cb1e5facfc34fca7323000c6188ad657 +level 7, file files/g10000-P90 +e9984c6557f5a392f16e5c139dbe4994 +level 7, file files/g100000 +6e493dbe2985fec69860ef34728ac01a +level 7, file files/g1000000 +455023a055f3a4de76c7295408ce3c8f +level 7, file files/g20000 +2359efcd587e36ac9b74a8344bbf0e53 +level 7, file files/g200000 +ca80dbc88183a5aabb4aae955c449dff +level 7, file files/g30000 +7e1be7e841c9fddd776dbe94b50db0ab +level 7, file files/g50000 +09b80b58d70622de6f2354a06c15cb2a +level 7, file files/g500000 +c90609f0558f0979eccb572ce0af4aa3 +level 19, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 19, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 19, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 19, file files/g100 +e6e88e42b891fbc82c87a60928d88e97 +level 19, file files/g1000 +f3eeeae11e293292fe1810d8745d0ae1 +level 19, file files/g10000 +23c5d58cca20ab65ff8a5d780f09e075 +level 19, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 19, file files/g10000-P10 +cced9c0f5709262da932fc8540bb72f4 +level 19, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 19, file files/g10000-P25 +6676c9b599408491f7abc00947782054 +level 19, file files/g10000-P50 +c61ad9309da86f7229498e46daacd6d9 +level 19, file files/g10000-P75 +d3171f297dfd08e444d481b30b1bbefa +level 19, file files/g10000-P90 +87c4a59ec6e15f6da86b26969044a8a4 +level 19, file files/g100000 +7ae11dc1919d94e80979d41d12a0b578 +level 19, file files/g1000000 +d4b9ee8879d7f30bed3ec9e70520ca67 +level 19, file files/g20000 +70028792166e24282f5497592b632192 +level 19, file files/g200000 +ab03b5ab84b6ebe79fa325118a895c6b +level 19, file files/g30000 +d698feea5119e141a08656439c4c1508 +level 19, file files/g50000 +b81384753f0db76004ac97681f6ef757 +level 19, file files/g500000 +0a25ba39483255a2c16899ab80a3ed8f +level 1, long=18, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 19, long=18, file files/g0 +5d80401e01d33084c65e94f93351e94c +level 1, long=18, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 19, long=18, file files/g1 +8436b07a7eb916ac9c48af847b7e612f +level 1, long=18, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 19, long=18, file files/g10 +6cf177a3e6494ac3c76c857df6a9b31d +level 1, long=18, file files/g100 +c94d1ef6bbec8b4899486b06207ee829 +level 19, long=18, file files/g100 +e6e88e42b891fbc82c87a60928d88e97 +level 1, long=18, file files/g1000 +6bf2f4b179864fd8db4676037465feed +level 19, long=18, file files/g1000 +f3eeeae11e293292fe1810d8745d0ae1 +level 1, long=18, file files/g10000 +2ae44c4053b2b47724c8f612dfb60d24 +level 19, long=18, file files/g10000 +23c5d58cca20ab65ff8a5d780f09e075 +level 1, long=18, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 19, long=18, file files/g10000-P0 +6c2641d3b83775c50b766793b39967c4 +level 1, long=18, file files/g10000-P10 +6a8f6e75ab538eb08a422febc8b68006 +level 19, long=18, file files/g10000-P10 +cced9c0f5709262da932fc8540bb72f4 +level 1, long=18, file files/g10000-P100 +5db6fbe04a2de772ad4e49f5357d0543 +level 19, long=18, file files/g10000-P100 +049015191cf579b24653c8730fcc10f5 +level 1, long=18, file files/g10000-P25 +6fd603b31365845346faab9cd64fd647 +level 19, long=18, file files/g10000-P25 +6676c9b599408491f7abc00947782054 +level 1, long=18, file files/g10000-P50 +d1de679e9a8c962ed1cc668a96bf930a +level 19, long=18, file files/g10000-P50 +c61ad9309da86f7229498e46daacd6d9 +level 1, long=18, file files/g10000-P75 +dcf9822423e2ad42a569985707cd5ab4 +level 19, long=18, file files/g10000-P75 +f0ea19930e3866ff7a1932931346e0ac +level 1, long=18, file files/g10000-P90 +87d249fd8c1ad0064d067a1e5ad97647 +level 19, long=18, file files/g10000-P90 +582e2c4c5a06e452d8dae22e7210c070 +level 1, long=18, file files/g100000 +daa38a869130494c077290cf54f2d895 +level 19, long=18, file files/g100000 +7ae11dc1919d94e80979d41d12a0b578 +level 1, long=18, file files/g1000000 +2c410773bb02367d20d20569393faf1e +level 19, long=18, file files/g1000000 +e3f5ef0204aedbac03e80d4300b3afc7 +level 1, long=18, file files/g20000 +1da5b56511e8693867c0cdd962c521aa +level 19, long=18, file files/g20000 +70028792166e24282f5497592b632192 +level 1, long=18, file files/g200000 +17eb9ff8d912da9c445def85cb748e54 +level 19, long=18, file files/g200000 +ab03b5ab84b6ebe79fa325118a895c6b +level 1, long=18, file files/g30000 +788bc5abca5e33d79bb79a4eca98b9cd +level 19, long=18, file files/g30000 +d698feea5119e141a08656439c4c1508 +level 1, long=18, file files/g50000 +0bf9fafd84a2d56a788a9159f1f23f26 +level 19, long=18, file files/g50000 +b81384753f0db76004ac97681f6ef757 +level 1, long=18, file files/g500000 +f035223dc02f581daf5dd79773c4dc2b +level 19, long=18, file files/g500000 +97093f718faf7b9094e27ea822fd1a29 +Vary number of threads on files/g0 +Vary number of threads on files/g1 +Vary number of threads on files/g10 +Vary number of threads on files/g100 +Vary number of threads on files/g1000 +Vary number of threads on files/g10000 +Vary number of threads on files/g10000-P0 +Vary number of threads on files/g10000-P10 +Vary number of threads on files/g10000-P100 +Vary number of threads on files/g10000-P25 +Vary number of threads on files/g10000-P50 +Vary number of threads on files/g10000-P75 +Vary number of threads on files/g10000-P90 +Vary number of threads on files/g100000 +Vary number of threads on files/g1000000 +Vary number of threads on files/g20000 +Vary number of threads on files/g200000 +Vary number of threads on files/g30000 +Vary number of threads on files/g50000 +Vary number of threads on files/g500000 diff --git a/tests/cli-tests/determinism/reuse.sh b/tests/cli-tests/determinism/reuse.sh new file mode 100755 index 000000000..83e4088dd --- /dev/null +++ b/tests/cli-tests/determinism/reuse.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +. "$COMMON/platform.sh" + +set -e + +# To update checksums on version change run this from the tests/ directory +# make update-cli-tests + +if [ -n "$NON_DETERMINISTIC" ]; then + # Skip tests if we have a non-deterministic build + cat "$CLI_TESTS/determinism/reuse.sh.stdout.exact" + exit 0 +fi + +datagen -g0 > file0 +datagen -g1 > file1 +datagen -g1000 > file1000 +datagen -g100000 > file100000 + +validate() { + $DIFF file0.zst file0.zst.good + $DIFF file1.zst file1.zst.good + $DIFF file1000.zst file1000.zst.good + $DIFF file100000.zst file100000.zst.good +} + +# Check that context reuse doesn't impact determinism +for level in $(seq 1 19); do + echo $level + zstd -qf --single-thread -$level file0 -o file0.zst.good + zstd -qf --single-thread -$level file1 -o file1.zst.good + zstd -qf --single-thread -$level file1000 -o file1000.zst.good + zstd -qf --single-thread -$level file100000 -o file100000.zst.good + + zstd -qf --single-thread -$level file0 file1 file1000 file100000 + validate + zstd -qf --single-thread -$level file1 file0 file1000 file100000 + validate + zstd -qf --single-thread -$level file1000 file1 file0 file100000 + validate + zstd -qf --single-thread -$level file100000 file1000 file1 file0 + validate +done diff --git a/tests/cli-tests/determinism/reuse.sh.stderr.exact b/tests/cli-tests/determinism/reuse.sh.stderr.exact new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cli-tests/determinism/reuse.sh.stdout.exact b/tests/cli-tests/determinism/reuse.sh.stdout.exact new file mode 100644 index 000000000..ac30dc23a --- /dev/null +++ b/tests/cli-tests/determinism/reuse.sh.stdout.exact @@ -0,0 +1,19 @@ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 diff --git a/tests/cli-tests/determinism/setup b/tests/cli-tests/determinism/setup new file mode 100755 index 000000000..c16029ebf --- /dev/null +++ b/tests/cli-tests/determinism/setup @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e + +cp -r ../files . diff --git a/tests/cli-tests/determinism/setup_once b/tests/cli-tests/determinism/setup_once new file mode 100755 index 000000000..1d7b34c1f --- /dev/null +++ b/tests/cli-tests/determinism/setup_once @@ -0,0 +1,30 @@ +#!/bin/sh + +set -e + +. "$COMMON/platform.sh" + + +mkdir files/ + +datagen -g0 > files/g0 +datagen -g1 > files/g1 +datagen -g10 > files/g10 +datagen -g100 > files/g100 +datagen -g1000 > files/g1000 +datagen -g10000 > files/g10000 +datagen -g20000 > files/g20000 +datagen -g30000 > files/g30000 +datagen -g50000 > files/g50000 +datagen -g100000 > files/g100000 +datagen -g200000 > files/g200000 +datagen -g500000 > files/g500000 +datagen -g1000000 > files/g1000000 + +datagen -g10000 -P0 > files/g10000-P0 +datagen -g10000 -P10 > files/g10000-P10 +datagen -g10000 -P25 > files/g10000-P25 +datagen -g10000 -P50 > files/g10000-P50 +datagen -g10000 -P75 > files/g10000-P75 +datagen -g10000 -P90 > files/g10000-P90 +datagen -g10000 -P100 > files/g10000-P100 diff --git a/tests/cli-tests/run.py b/tests/cli-tests/run.py index 46564d2ff..011c8478e 100755 --- a/tests/cli-tests/run.py +++ b/tests/cli-tests/run.py @@ -705,6 +705,7 @@ if __name__ == "__main__": env["DATAGEN_BIN"] = os.path.abspath(args.datagen) env["ZSTDGREP_BIN"] = os.path.abspath(args.zstdgrep) env["ZSTDLESS_BIN"] = os.path.abspath(args.zstdless) + env["CLI_TESTS"] = os.path.abspath(args.test_dir) env["COMMON"] = os.path.abspath(os.path.join(args.test_dir, "common")) env["PATH"] = bin_dir + ":" + os.getenv("PATH", "") env["LC_ALL"] = "C" From d5986f235f6fbe4f72aabb943cf6d4b9fe51772f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 10 Mar 2025 00:12:34 -0700 Subject: [PATCH 050/245] fix #4332: setting ZSTD_NBTHREADS=0 via environment variables --- programs/zstdcli.c | 55 ++++++++----------- tests/cli-tests/compression/multi-threaded.sh | 4 -- .../multi-threaded.sh.stderr.exact | 5 -- 3 files changed, 24 insertions(+), 40 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 66e9d064b..30a406a7d 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -44,7 +44,7 @@ #endif #ifndef ZSTDCLI_NBTHREADS_DEFAULT -#define ZSTDCLI_NBTHREADS_DEFAULT MAX(1, MIN(4, UTIL_countLogicalCores() / 4)) +#define ZSTDCLI_NBTHREADS_DEFAULT (unsigned)(MAX(1, MIN(4, UTIL_countLogicalCores() / 4))) #endif @@ -94,6 +94,7 @@ static U32 g_ldmBucketSizeLog = LDM_PARAM_DEFAULT; #define DEFAULT_ACCEL 1 +#define NBWORKERS_AUTOCPU 0 typedef enum { cover, fastCover, legacy } dictType; @@ -745,7 +746,7 @@ static void printActualCParams(const char* filename, const char* dictFileName, i /* Environment variables for parameter setting */ #define ENV_CLEVEL "ZSTD_CLEVEL" -#define ENV_NBTHREADS "ZSTD_NBTHREADS" /* takes lower precedence than directly specifying -T# in the CLI */ +#define ENV_NBWORKERS "ZSTD_NBTHREADS" /* takes lower precedence than directly specifying -T# in the CLI */ /* pick up environment variable */ static int init_cLevel(void) { @@ -775,26 +776,28 @@ static int init_cLevel(void) { return ZSTDCLI_CLEVEL_DEFAULT; } +static unsigned init_nbWorkers(void) { #ifdef ZSTD_MULTITHREAD -static int default_nbThreads(void) { - const char* const env = getenv(ENV_NBTHREADS); + const char* const env = getenv(ENV_NBWORKERS); if (env != NULL) { const char* ptr = env; if ((*ptr>='0') && (*ptr<='9')) { unsigned nbThreads; if (readU32FromCharChecked(&ptr, &nbThreads)) { - DISPLAYLEVEL(2, "Ignore environment variable setting %s=%s: numeric value too large \n", ENV_NBTHREADS, env); + DISPLAYLEVEL(2, "Ignore environment variable setting %s=%s: numeric value too large \n", ENV_NBWORKERS, env); return ZSTDCLI_NBTHREADS_DEFAULT; } else if (*ptr == 0) { - return (int)nbThreads; + return nbThreads; } } - DISPLAYLEVEL(2, "Ignore environment variable setting %s=%s: not a valid unsigned value \n", ENV_NBTHREADS, env); + DISPLAYLEVEL(2, "Ignore environment variable setting %s=%s: not a valid unsigned value \n", ENV_NBWORKERS, env); } return ZSTDCLI_NBTHREADS_DEFAULT; -} +#else + return 1; #endif +} #define NEXT_FIELD(ptr) { \ if (*argument == '=') { \ @@ -874,13 +877,15 @@ int main(int argCount, const char* argv[]) singleThread = 0, defaultLogicalCores = 0, showDefaultCParams = 0, - ultra=0, - contentSize=1, - removeSrcFile=0; - ZSTD_ParamSwitch_e mmapDict=ZSTD_ps_auto; + contentSize = 1, + removeSrcFile = 0, + cLevel = init_cLevel(), + ultra = 0, + cLevelLast = MINCLEVEL - 1; /* for benchmark range */ + unsigned nbWorkers = init_nbWorkers(); + ZSTD_ParamSwitch_e mmapDict = ZSTD_ps_auto; ZSTD_ParamSwitch_e useRowMatchFinder = ZSTD_ps_auto; FIO_compressionType_t cType = FIO_zstdCompression; - int nbWorkers = -1; /* -1 means unset */ double compressibility = -1.0; /* lorem ipsum generator */ unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */ size_t chunkSize = 0; @@ -890,8 +895,6 @@ int main(int argCount, const char* argv[]) FIO_progressSetting_e progress = FIO_ps_auto; zstd_operation_mode operation = zom_compress; ZSTD_compressionParameters compressionParams; - int cLevel = init_cLevel(); - int cLevelLast = MINCLEVEL - 1; /* lower than minimum */ unsigned recursive = 0; unsigned memLimit = 0; FileNamesTable* filenames = UTIL_allocateFileNamesTable((size_t)argCount); /* argCount >= 1 */ @@ -930,7 +933,7 @@ int main(int argCount, const char* argv[]) programName = lastNameFromPath(programName); /* preset behaviors */ - if (exeNameMatch(programName, ZSTD_ZSTDMT)) nbWorkers=0, singleThread=0; + if (exeNameMatch(programName, ZSTD_ZSTDMT)) nbWorkers=NBWORKERS_AUTOCPU, singleThread=0; if (exeNameMatch(programName, ZSTD_UNZSTD)) operation=zom_decompress; if (exeNameMatch(programName, ZSTD_CAT)) { operation=zom_decompress; FIO_overwriteMode(prefs); forceStdout=1; followLinks=1; FIO_setPassThroughFlag(prefs, 1); outFileName=stdoutmark; g_displayLevel=1; } /* supports multiple formats */ if (exeNameMatch(programName, ZSTD_ZCAT)) { operation=zom_decompress; FIO_overwriteMode(prefs); forceStdout=1; followLinks=1; FIO_setPassThroughFlag(prefs, 1); outFileName=stdoutmark; g_displayLevel=1; } /* behave like zcat, also supports multiple formats */ @@ -938,7 +941,7 @@ int main(int argCount, const char* argv[]) suffix = GZ_EXTENSION; cType = FIO_gzipCompression; removeSrcFile=1; dictCLevel = cLevel = 6; /* gzip default is -6 */ } - if (exeNameMatch(programName, ZSTD_GUNZIP)) { operation=zom_decompress; removeSrcFile=1; } /* behave like gunzip, also supports multiple formats */ + if (exeNameMatch(programName, ZSTD_GUNZIP)) { operation=zom_decompress; removeSrcFile=1; } /* behave like gunzip, also supports multiple formats */ if (exeNameMatch(programName, ZSTD_GZCAT)) { operation=zom_decompress; FIO_overwriteMode(prefs); forceStdout=1; followLinks=1; FIO_setPassThroughFlag(prefs, 1); outFileName=stdoutmark; g_displayLevel=1; } /* behave like gzcat, also supports multiple formats */ if (exeNameMatch(programName, ZSTD_LZMA)) { suffix = LZMA_EXTENSION; cType = FIO_lzmaCompression; removeSrcFile=1; } /* behave like lzma */ if (exeNameMatch(programName, ZSTD_UNLZMA)) { operation=zom_decompress; cType = FIO_lzmaCompression; removeSrcFile=1; } /* behave like unlzma, also supports multiple formats */ @@ -1081,7 +1084,7 @@ int main(int argCount, const char* argv[]) continue; } #endif - if (longCommandWArg(&argument, "--threads")) { NEXT_INT32(nbWorkers); continue; } + if (longCommandWArg(&argument, "--threads")) { NEXT_UINT32(nbWorkers); continue; } if (longCommandWArg(&argument, "--memlimit")) { NEXT_UINT32(memLimit); continue; } if (longCommandWArg(&argument, "--memory")) { NEXT_UINT32(memLimit); continue; } if (longCommandWArg(&argument, "--memlimit-decompress")) { NEXT_UINT32(memLimit); continue; } @@ -1287,7 +1290,7 @@ int main(int argCount, const char* argv[]) /* nb of threads (hidden option) */ case 'T': argument++; - nbWorkers = (int)readU32FromChar(&argument); + nbWorkers = readU32FromChar(&argument); break; /* Dictionary Selection level */ @@ -1332,10 +1335,7 @@ int main(int argCount, const char* argv[]) DISPLAYLEVEL(3, WELCOME_MESSAGE); #ifdef ZSTD_MULTITHREAD - if ((operation==zom_decompress) && (nbWorkers > 1)) { - DISPLAYLEVEL(2, "Warning : decompression does not support multi-threading\n"); - } - if ((nbWorkers==0) && (!singleThread)) { + if ((nbWorkers==NBWORKERS_AUTOCPU) && (!singleThread)) { /* automatically set # workers based on # of reported cpus */ if (defaultLogicalCores) { nbWorkers = UTIL_countLogicalCores(); @@ -1345,14 +1345,7 @@ int main(int argCount, const char* argv[]) DISPLAYLEVEL(3, "Note: %d physical core(s) detected \n", nbWorkers); } } - /* Resolve to default if nbWorkers is still unset */ - if (nbWorkers == -1) { - if (operation == zom_decompress) { - nbWorkers = 1; - } else { - nbWorkers = default_nbThreads(); - } - } + assert(nbWorkers >= 0); if (operation != zom_bench) DISPLAYLEVEL(4, "Compressing with %u worker threads \n", nbWorkers); #else diff --git a/tests/cli-tests/compression/multi-threaded.sh b/tests/cli-tests/compression/multi-threaded.sh index ac094129e..25d862b45 100755 --- a/tests/cli-tests/compression/multi-threaded.sh +++ b/tests/cli-tests/compression/multi-threaded.sh @@ -10,7 +10,3 @@ zstd -T0 -f file -q ; zstd -t file.zst zstd -T0 --auto-threads=logical -f file -q ; zstd -t file.zst zstd -T0 --auto-threads=physical -f file -q ; zstd -t file.zst zstd -T0 --jobsize=1M -f file -q ; zstd -t file.zst - -# multi-thread decompression warning test -zstd -T0 -f file -q ; zstd -t file.zst; zstd -T0 -d file.zst -o file3 -zstd -T0 -f file -q ; zstd -t file.zst; zstd -T2 -d file.zst -o file4 diff --git a/tests/cli-tests/compression/multi-threaded.sh.stderr.exact b/tests/cli-tests/compression/multi-threaded.sh.stderr.exact index 0dcf52ac4..cb3a24aad 100644 --- a/tests/cli-tests/compression/multi-threaded.sh.stderr.exact +++ b/tests/cli-tests/compression/multi-threaded.sh.stderr.exact @@ -5,8 +5,3 @@ file.zst : 65537 bytes file.zst : 65537 bytes file.zst : 65537 bytes file.zst : 65537 bytes -file.zst : 65537 bytes -file.zst : 65537 bytes -file.zst : 65537 bytes -Warning : decompression does not support multi-threading -file.zst : 65537 bytes From 56e2ebf5c38a22e0264b709a802b1cfa2ce21167 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 10 Mar 2025 09:54:06 -0700 Subject: [PATCH 051/245] removed useless assert() --- programs/zstdcli.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 30a406a7d..637567b95 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1338,14 +1338,13 @@ int main(int argCount, const char* argv[]) if ((nbWorkers==NBWORKERS_AUTOCPU) && (!singleThread)) { /* automatically set # workers based on # of reported cpus */ if (defaultLogicalCores) { - nbWorkers = UTIL_countLogicalCores(); + nbWorkers = (unsigned)UTIL_countLogicalCores(); DISPLAYLEVEL(3, "Note: %d logical core(s) detected \n", nbWorkers); } else { - nbWorkers = UTIL_countPhysicalCores(); + nbWorkers = (unsigned)UTIL_countPhysicalCores(); DISPLAYLEVEL(3, "Note: %d physical core(s) detected \n", nbWorkers); } } - assert(nbWorkers >= 0); if (operation != zom_bench) DISPLAYLEVEL(4, "Compressing with %u worker threads \n", nbWorkers); #else From c18374bb16ecea2a34d003be769bf14b7e97b931 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 10 Mar 2025 13:40:47 -0700 Subject: [PATCH 052/245] add test checks that ZSTD_NBTHREADS triggers the expected verbose message Also: checked that the new test script fails on current `dev` branch, and is fixed by this branch --- tests/playTests.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/playTests.sh b/tests/playTests.sh index 65aa5c0b1..366f9c741 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -1570,7 +1570,11 @@ then ZSTD_NBTHREADS=3a7 zstd -f mt_tmp # malformed env var, warn and revert to default setting ZSTD_NBTHREADS=50000000000 zstd -f mt_tmp # numeric value too large, warn and revert to default setting= ZSTD_NBTHREADS=2 zstd -f mt_tmp # correct usage - ZSTD_NBTHREADS=1 zstd -f mt_tmp # correct usage: single thread + ZSTD_NBTHREADS=1 zstd -f mt_tmp # correct usage: single worker + ZSTD_NBTHREADS=4 zstd -f mt_tmp -vv 2>&1 | grep "4 worker threads" # check message + zstd -tq mt_tmp.zst + ZSTD_NBTHREADS=0 zstd -f mt_tmp -vv 2>&1 | grep "core(s) detected" # check core count autodetection is triggered + zstd -tq mt_tmp.zst # temporary envvar changes in the above tests would actually persist in macos /bin/sh unset ZSTD_NBTHREADS rm -f mt_tmp* From 2ff87aefac1be81601a46a98135b15f57ff3ca56 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 10 Mar 2025 13:55:45 -0700 Subject: [PATCH 053/245] fix FreeBSD use an alias instead of a function also: added more traces and updated version nb to v1.5.8 --- lib/zstd.h | 2 +- programs/zstdcli.c | 10 ++++++++-- tests/playTests.sh | 24 ++++++++---------------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index 4ce2f7742..9fe542edc 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -111,7 +111,7 @@ extern "C" { /*------ Version ------*/ #define ZSTD_VERSION_MAJOR 1 #define ZSTD_VERSION_MINOR 5 -#define ZSTD_VERSION_RELEASE 7 +#define ZSTD_VERSION_RELEASE 8 #define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) /*! ZSTD_versionNumber() : diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 637567b95..04e9218cf 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -686,6 +686,12 @@ static void printVersion(void) DISPLAYOUT("lz4 version %s\n", FIO_lz4Version()); DISPLAYOUT("lzma version %s\n", FIO_lzmaVersion()); + #ifdef ZSTD_MULTITHREAD + DISPLAYOUT("supports Multithreading \n"); + #else + DISPLAYOUT("single-thread operations only \n"); + #endif + /* posix support */ #ifdef _POSIX_C_SOURCE DISPLAYOUT("_POSIX_C_SOURCE defined: %ldL\n", (long) _POSIX_C_SOURCE); @@ -1336,7 +1342,7 @@ int main(int argCount, const char* argv[]) #ifdef ZSTD_MULTITHREAD if ((nbWorkers==NBWORKERS_AUTOCPU) && (!singleThread)) { - /* automatically set # workers based on # of reported cpus */ + /* automatically set # workers based on # of reported cpu cores */ if (defaultLogicalCores) { nbWorkers = (unsigned)UTIL_countLogicalCores(); DISPLAYLEVEL(3, "Note: %d logical core(s) detected \n", nbWorkers); @@ -1345,7 +1351,7 @@ int main(int argCount, const char* argv[]) DISPLAYLEVEL(3, "Note: %d physical core(s) detected \n", nbWorkers); } } - if (operation != zom_bench) + if (operation == zom_compress) DISPLAYLEVEL(4, "Compressing with %u worker threads \n", nbWorkers); #else (void)singleThread; (void)nbWorkers; (void)defaultLogicalCores; diff --git a/tests/playTests.sh b/tests/playTests.sh index 366f9c741..3d6bcdb0b 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -1,7 +1,7 @@ #!/bin/sh set -e # exit immediately on error -# set -x # print commands before execution (debug) +set -x # print commands before execution (debug) unset ZSTD_CLEVEL unset ZSTD_NBTHREADS @@ -16,13 +16,7 @@ datagen() { "$DATAGEN_BIN" "$@" } -zstd() { - if [ -z "$EXE_PREFIX" ]; then - "$ZSTD_BIN" "$@" - else - "$EXE_PREFIX" "$ZSTD_BIN" "$@" - fi -} +alias zstd="$EXE_PREFIX $ZSTD_BIN" sudoZstd() { if [ -z "$EXE_PREFIX" ]; then @@ -1563,18 +1557,16 @@ then println "\n===> zstdmt environment variable tests " echo "multifoo" >> mt_tmp ZSTD_NBTHREADS=-3 zstd -f mt_tmp # negative value, warn and revert to default setting - ZSTD_NBTHREADS='' zstd -f mt_tmp # empty env var, warn and revert to default setting - ZSTD_NBTHREADS=- zstd -f mt_tmp # malformed env var, warn and revert to default setting - ZSTD_NBTHREADS=a zstd -f mt_tmp # malformed env var, warn and revert to default setting - ZSTD_NBTHREADS=+a zstd -f mt_tmp # malformed env var, warn and revert to default setting + ZSTD_NBTHREADS='' zstd -f mt_tmp # empty env var, warn and revert to default setting + ZSTD_NBTHREADS=- zstd -f mt_tmp # malformed env var, warn and revert to default setting + ZSTD_NBTHREADS=a zstd -f mt_tmp # malformed env var, warn and revert to default setting + ZSTD_NBTHREADS=+a zstd -f mt_tmp # malformed env var, warn and revert to default setting ZSTD_NBTHREADS=3a7 zstd -f mt_tmp # malformed env var, warn and revert to default setting ZSTD_NBTHREADS=50000000000 zstd -f mt_tmp # numeric value too large, warn and revert to default setting= ZSTD_NBTHREADS=2 zstd -f mt_tmp # correct usage ZSTD_NBTHREADS=1 zstd -f mt_tmp # correct usage: single worker - ZSTD_NBTHREADS=4 zstd -f mt_tmp -vv 2>&1 | grep "4 worker threads" # check message - zstd -tq mt_tmp.zst - ZSTD_NBTHREADS=0 zstd -f mt_tmp -vv 2>&1 | grep "core(s) detected" # check core count autodetection is triggered - zstd -tq mt_tmp.zst + ZSTD_NBTHREADS=4 zstd -f mt_tmp -vv 2>&1 | $GREP "4 worker threads" # check message + ZSTD_NBTHREADS=0 zstd -f mt_tmp -vv 2>&1 | $GREP "core(s) detected" # check core count autodetection is triggered # temporary envvar changes in the above tests would actually persist in macos /bin/sh unset ZSTD_NBTHREADS rm -f mt_tmp* From 3c4096c83e997adb181a7d2b8f5c02649bb98af5 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 10 Mar 2025 19:11:44 -0700 Subject: [PATCH 054/245] fixed ShellCheck warning --- tests/playTests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/playTests.sh b/tests/playTests.sh index 3d6bcdb0b..72a47d634 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -16,7 +16,7 @@ datagen() { "$DATAGEN_BIN" "$@" } -alias zstd="$EXE_PREFIX $ZSTD_BIN" +alias zstd='$EXE_PREFIX $ZSTD_BIN' sudoZstd() { if [ -z "$EXE_PREFIX" ]; then From c583c2c39ed24c0b155777f600ee2aa74268e37b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 10 Mar 2025 22:46:33 -0700 Subject: [PATCH 055/245] warn when requesting decompression with multiple threads restore #2918 fix --- programs/zstdcli.c | 18 +++++++----------- tests/cli-tests/compression/multi-threaded.sh | 10 ++++++++++ .../compression/multi-threaded.sh.stderr.exact | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 04e9218cf..276910d91 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -822,15 +822,6 @@ static unsigned init_nbWorkers(void) { CLEAN_RETURN(1); \ } } } -#define NEXT_INT32(_vari32) { \ - const char* __nb; \ - NEXT_FIELD(__nb); \ - _vari32 = (int)readU32FromChar(&__nb); \ - if(*__nb != 0) { \ - errorOut("error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed"); \ - } \ -} - #define NEXT_UINT32(_varu32) { \ const char* __nb; \ NEXT_FIELD(__nb); \ @@ -887,7 +878,8 @@ int main(int argCount, const char* argv[]) removeSrcFile = 0, cLevel = init_cLevel(), ultra = 0, - cLevelLast = MINCLEVEL - 1; /* for benchmark range */ + cLevelLast = MINCLEVEL - 1, /* for benchmark range */ + setThreads_non1 = 0; unsigned nbWorkers = init_nbWorkers(); ZSTD_ParamSwitch_e mmapDict = ZSTD_ps_auto; ZSTD_ParamSwitch_e useRowMatchFinder = ZSTD_ps_auto; @@ -1090,7 +1082,7 @@ int main(int argCount, const char* argv[]) continue; } #endif - if (longCommandWArg(&argument, "--threads")) { NEXT_UINT32(nbWorkers); continue; } + if (longCommandWArg(&argument, "--threads")) { NEXT_UINT32(nbWorkers); setThreads_non1 = (nbWorkers != 1); continue; } if (longCommandWArg(&argument, "--memlimit")) { NEXT_UINT32(memLimit); continue; } if (longCommandWArg(&argument, "--memory")) { NEXT_UINT32(memLimit); continue; } if (longCommandWArg(&argument, "--memlimit-decompress")) { NEXT_UINT32(memLimit); continue; } @@ -1297,6 +1289,7 @@ int main(int argCount, const char* argv[]) case 'T': argument++; nbWorkers = readU32FromChar(&argument); + setThreads_non1 = (nbWorkers != 1); break; /* Dictionary Selection level */ @@ -1341,6 +1334,9 @@ int main(int argCount, const char* argv[]) DISPLAYLEVEL(3, WELCOME_MESSAGE); #ifdef ZSTD_MULTITHREAD + if ((operation==zom_decompress) && (setThreads_non1)) { + DISPLAYLEVEL(2, "Warning : decompression does not support multi-threading\n"); + } if ((nbWorkers==NBWORKERS_AUTOCPU) && (!singleThread)) { /* automatically set # workers based on # of reported cpu cores */ if (defaultLogicalCores) { diff --git a/tests/cli-tests/compression/multi-threaded.sh b/tests/cli-tests/compression/multi-threaded.sh index 25d862b45..ba3aa0ce5 100755 --- a/tests/cli-tests/compression/multi-threaded.sh +++ b/tests/cli-tests/compression/multi-threaded.sh @@ -10,3 +10,13 @@ zstd -T0 -f file -q ; zstd -t file.zst zstd -T0 --auto-threads=logical -f file -q ; zstd -t file.zst zstd -T0 --auto-threads=physical -f file -q ; zstd -t file.zst zstd -T0 --jobsize=1M -f file -q ; zstd -t file.zst + +# multi-thread decompression warning test +zstd -T0 -f file -q ; zstd -t file.zst; zstd -T0 -d file.zst -o file3 +zstd -T0 -f file -q ; zstd -t file.zst; zstd -T2 -d file.zst -o file4 +# setting multi-thread via environment variable does not trigger decompression warning +zstd -T0 -f file -q ; zstd -t file.zst; ZSTD_NBTHREADS=0 zstd -df file.zst -o file3 +zstd -T0 -f file -q ; zstd -t file.zst; ZSTD_NBTHREADS=2 zstd -df file.zst -o file4 +# setting nbThreads==1 does not trigger decompression warning +zstd -T0 -f file -q ; zstd -t file.zst; zstd -T1 -df file.zst -o file3 +zstd -T0 -f file -q ; zstd -t file.zst; zstd -T2 -T1 -df file.zst -o file4 diff --git a/tests/cli-tests/compression/multi-threaded.sh.stderr.exact b/tests/cli-tests/compression/multi-threaded.sh.stderr.exact index cb3a24aad..346fe0e0c 100644 --- a/tests/cli-tests/compression/multi-threaded.sh.stderr.exact +++ b/tests/cli-tests/compression/multi-threaded.sh.stderr.exact @@ -5,3 +5,17 @@ file.zst : 65537 bytes file.zst : 65537 bytes file.zst : 65537 bytes file.zst : 65537 bytes +file.zst : 65537 bytes +Warning : decompression does not support multi-threading +file.zst : 65537 bytes +file.zst : 65537 bytes +Warning : decompression does not support multi-threading +file.zst : 65537 bytes +file.zst : 65537 bytes +file.zst : 65537 bytes +file.zst : 65537 bytes +file.zst : 65537 bytes +file.zst : 65537 bytes +file.zst : 65537 bytes +file.zst : 65537 bytes +file.zst : 65537 bytes From 19541b4d1abef6313f317dbe4ff744319f76abaf Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 11 Mar 2025 00:17:45 -0700 Subject: [PATCH 056/245] fix minor unused variable warning --- programs/zstdcli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 276910d91..4fed04e13 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1350,7 +1350,7 @@ int main(int argCount, const char* argv[]) if (operation == zom_compress) DISPLAYLEVEL(4, "Compressing with %u worker threads \n", nbWorkers); #else - (void)singleThread; (void)nbWorkers; (void)defaultLogicalCores; + (void)singleThread; (void)nbWorkers; (void)defaultLogicalCores; (void)setThreads_non1; #endif g_utilDisplayLevel = g_displayLevel; From 68dfd14a8c504bbb27013043e1f3466d5318e019 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 11 Mar 2025 11:53:20 -0700 Subject: [PATCH 057/245] [linux] Opt out of row based match finder for the kernel The row based match finder is slower without SIMD. We used to detect the presence of SIMD to set the lower bound to 17, but that breaks determinism. Instead, specifically opt into it for the kernel, because it is one of the rare cases that doesn't have SIMD support. --- lib/compress/zstd_compress.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index d928b1d3e..c8f6b2865 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -237,10 +237,18 @@ static int ZSTD_rowMatchFinderUsed(const ZSTD_strategy strategy, const ZSTD_Para /* Returns row matchfinder usage given an initial mode and cParams */ static ZSTD_ParamSwitch_e ZSTD_resolveRowMatchFinderMode(ZSTD_ParamSwitch_e mode, const ZSTD_compressionParameters* const cParams) { +#ifdef ZSTD_LINUX_KERNEL + /* The Linux Kernel does not use SIMD, and 128KB is a very common size, e.g. in BtrFS. + * The row match finder is slower for this size without SIMD, so disable it. + */ + const unsigned kWindowLogLowerBound = 17; +#else + const unsigned kWindowLogLowerBound = 14; +#endif if (mode != ZSTD_ps_auto) return mode; /* if requested enabled, but no SIMD, we still will use row matchfinder */ mode = ZSTD_ps_disable; if (!ZSTD_rowMatchFinderSupported(cParams->strategy)) return mode; - if (cParams->windowLog > 14) mode = ZSTD_ps_enable; + if (cParams->windowLog > kWindowLogLowerBound) mode = ZSTD_ps_enable; return mode; } From 9a57bdc0bdac7bdf95ca9401c3d95b84ceae6306 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 11 Mar 2025 01:14:39 -0700 Subject: [PATCH 058/245] attempt to reduce length of long cli tests by invoking -T0 --- tests/playTests.sh | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/playTests.sh b/tests/playTests.sh index 72a47d634..15f6e7761 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -43,7 +43,7 @@ roundTripTest() { rm -f tmp1 tmp2 println "roundTripTest: datagen $1 $proba | zstd -v$cLevel | zstd -d$dLevel" datagen $1 $proba | $MD5SUM > tmp1 - datagen $1 $proba | zstd --ultra -v$cLevel | zstd -d$dLevel | $MD5SUM > tmp2 + datagen $1 $proba | zstd -T0 --ultra -v$cLevel | zstd -d$dLevel | $MD5SUM > tmp2 $DIFF -q tmp1 tmp2 } @@ -65,7 +65,7 @@ fileRoundTripTest() { println "fileRoundTripTest: datagen $1 $local_p > tmp && zstd -v$local_c -c tmp | zstd -d$local_d" datagen $1 $local_p > tmp < tmp $MD5SUM > tmp.md5.1 - zstd --ultra -v$local_c -c tmp | zstd -d$local_d | $MD5SUM > tmp.md5.2 + zstd -T0 --ultra -v$local_c -c tmp | zstd -d$local_d | $MD5SUM > tmp.md5.2 $DIFF -q tmp.md5.1 tmp.md5.2 } @@ -1885,36 +1885,36 @@ println "\n===> cover dictionary builder : advanced options " TESTFILE="$PRGDIR"/zstdcli.c datagen > tmpDict println "- Create first dictionary" -zstd --train-cover=k=46,d=8,split=80 "$TESTDIR"/*.c "$PRGDIR"/*.c -o tmpDict +zstd -T0 --train-cover=k=46,d=8,split=80 "$TESTDIR"/*.c "$PRGDIR"/*.c -o tmpDict cp "$TESTFILE" tmp zstd -f tmp -D tmpDict zstd -f tmp -D tmpDict --patch-from=tmpDict && die "error: can't use -D and --patch-from=#at the same time" zstd -d tmp.zst -D tmpDict -fo result $DIFF "$TESTFILE" result -zstd --train-cover=k=56,d=8 && die "Create dictionary without input file (should error)" +zstd -T0 --train-cover=k=56,d=8 && die "Create dictionary without input file (should error)" println "- Create second (different) dictionary" -zstd --train-cover=k=56,d=8 "$TESTDIR"/*.c "$PRGDIR"/*.c "$PRGDIR"/*.h -o tmpDictC +zstd -T0 --train-cover=k=56,d=8 "$TESTDIR"/*.c "$PRGDIR"/*.c "$PRGDIR"/*.h -o tmpDictC zstd -d tmp.zst -D tmpDictC -fo result && die "wrong dictionary not detected!" println "- Create dictionary using shrink-dict flag" -zstd --train-cover=steps=256,shrink "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict -zstd --train-cover=steps=256,shrink=1 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict1 -zstd --train-cover=steps=256,shrink=5 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict2 -zstd --train-cover=shrink=5,steps=256 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict3 +zstd -T0 --train-cover=steps=256,shrink "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict +zstd -T0 --train-cover=steps=256,shrink=1 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict1 +zstd -T0 --train-cover=steps=256,shrink=5 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict2 +zstd -T0 --train-cover=shrink=5,steps=256 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict3 println "- Create dictionary with short dictID" -zstd --train-cover=k=46,d=8,split=80 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpDict1 +zstd -T0 --train-cover=k=46,d=8,split=80 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpDict1 cmp tmpDict tmpDict1 && die "dictionaries should have different ID !" println "- Create dictionary with size limit" -zstd --train-cover=steps=8 "$TESTDIR"/*.c "$PRGDIR"/*.c -o tmpDict2 --maxdict=4K +zstd -T0 --train-cover=steps=8 "$TESTDIR"/*.c "$PRGDIR"/*.c -o tmpDict2 --maxdict=4K println "- Compare size of dictionary from 90% training samples with 80% training samples" -zstd --train-cover=split=90 -r "$TESTDIR"/*.c "$PRGDIR"/*.c -zstd --train-cover=split=80 -r "$TESTDIR"/*.c "$PRGDIR"/*.c +zstd -T0 --train-cover=split=90 -r "$TESTDIR"/*.c "$PRGDIR"/*.c +zstd -T0 --train-cover=split=80 -r "$TESTDIR"/*.c "$PRGDIR"/*.c println "- Create dictionary using all samples for both training and testing" -zstd --train-cover=split=100 -r "$TESTDIR"/*.c "$PRGDIR"/*.c +zstd -T0 --train-cover=split=100 -r "$TESTDIR"/*.c "$PRGDIR"/*.c println "- Test -o before --train-cover" rm -f tmpDict dictionary zstd -o tmpDict --train-cover "$TESTDIR"/*.c "$PRGDIR"/*.c test -f tmpDict -zstd --train-cover "$TESTDIR"/*.c "$PRGDIR"/*.c +zstd -T0 --train-cover "$TESTDIR"/*.c "$PRGDIR"/*.c test -f dictionary rm -f tmp* dictionary From 51b6e79f659f7ba18bf7c4bd2679ff58711aa34d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 11 Mar 2025 01:57:24 -0700 Subject: [PATCH 059/245] fix #4312 and upgraded the test so that it would fail, both at compile time and at run time, without the fix --- lib/dictBuilder/cover.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index cfb756ff2..ed750e31d 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -284,7 +284,7 @@ static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) { */ #if (defined(_WIN32) && defined(_MSC_VER)) || defined(__APPLE__) static int WIN_CDECL COVER_strict_cmp(void* g_coverCtx, const void* lp, const void* rp) { -#elif defined(_GNU_SOURCE) +#elif defined(_GNU_SOURCE) && !defined(ZSTD_USE_C90_QSORT) static int COVER_strict_cmp(const void *lp, const void *rp, void *g_coverCtx) { #else /* C90 fallback.*/ static int COVER_strict_cmp(const void *lp, const void *rp) { @@ -300,7 +300,7 @@ static int COVER_strict_cmp(const void *lp, const void *rp) { */ #if (defined(_WIN32) && defined(_MSC_VER)) || defined(__APPLE__) static int WIN_CDECL COVER_strict_cmp8(void* g_coverCtx, const void* lp, const void* rp) { -#elif defined(_GNU_SOURCE) +#elif defined(_GNU_SOURCE) && !defined(ZSTD_USE_C90_QSORT) static int COVER_strict_cmp8(const void *lp, const void *rp, void *g_coverCtx) { #else /* C90 fallback.*/ static int COVER_strict_cmp8(const void *lp, const void *rp) { From dcf675886bc138c03c3f157f7464798c4140829f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 11 Mar 2025 11:58:16 -0700 Subject: [PATCH 060/245] re-design qsort() selection in cover centralizes auto detection tests, then distribute the outcome in all the places where it's active. --- .github/workflows/dev-short-tests.yml | 2 +- lib/README.md | 8 +++-- lib/dictBuilder/cover.c | 51 +++++++++++++++++++++------ 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 2a97c32d0..164dc15c7 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -695,7 +695,7 @@ jobs: sudo apt install -y musl-tools - name: Compile the project with musl-gcc run: | - CC=musl-gcc CPPFLAGS=-DZSTD_USE_C90_QSORT make -j V=1 zstd + CC=musl-gcc CFLAGS="-Werror -O3" CPPFLAGS=-DZDICT_QSORT=ZDICT_QSORT_C90 make -j -C tests test-zstd V=1 intel-cet-compatibility: runs-on: ubuntu-latest diff --git a/lib/README.md b/lib/README.md index 9df516c5a..83bf00c19 100644 --- a/lib/README.md +++ b/lib/README.md @@ -193,9 +193,11 @@ The file structure is designed to make this selection manually achievable for an and assembly decoding loops. You may want to use this macro if these loops are slower on your platform. -- The macro `ZSTD_USE_C90_QSORT` forces usage of C90's `qsort()`, - for situations where the code cannot determine that `qsort_r()` is not supported, - such as, for example, older versions of `musl`. +- The macro `ZDICT_QSORT` can enforce selection of a specific sorting variant. + It can be notably set as `ZDICT_QSORT=ZDICT_QSORT_C90`, + for situations where autodetection fails, + for example with older versions of `musl`. + Other selectable suffixes are `_GNU`, `_APPLE` and `_MSVC`. #### Windows : using MinGW+MSYS to create DLL diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index ed750e31d..9ed360033 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -39,6 +39,7 @@ # define ZDICT_STATIC_LINKING_ONLY #endif +#include "../common/debug.h" /* DEBUG_STATIC_ASSERT */ #include "../common/mem.h" /* read */ #include "../common/pool.h" /* POOL_ctx */ #include "../common/threading.h" /* ZSTD_pthread_mutex_t */ @@ -60,6 +61,29 @@ #define COVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB)) #define COVER_DEFAULT_SPLITPOINT 1.0 +/** + * Select the qsort() variant used by cover + */ +#define ZDICT_QSORT_MIN 0 +#define ZDICT_QSORT_C90 ZDICT_QSORT_MIN +#define ZDICT_QSORT_GNU 1 +#define ZDICT_QSORT_APPLE 2 +#define ZDICT_QSORT_MSVC ZDICT_QSORT_MAX +#define ZDICT_QSORT_MAX 3 + +#ifndef ZDICT_QSORT +# if defined(__APPLE__) +# define ZDICT_QSORT ZDICT_QSORT_APPLE /* uses qsort_r() with a different order for parameters */ +# elif defined(_GNU_SOURCE) +# define ZDICT_QSORT ZDICT_QSORT_GNU /* uses qsort_r() */ +# elif defined(_WIN32) && defined(_MSC_VER) +# define ZDICT_QSORT ZDICT_QSORT_MSVC /* uses qsort_s() */ +# else +# define ZDICT_QSORT ZDICT_QSORT_C90 /* uses standard qsort() which is not re-entrant (requires global variable) */ +# endif +#endif + + /*-************************************* * Console display * @@ -234,8 +258,7 @@ typedef struct { int displayLevel; } COVER_ctx_t; -#if defined(ZSTD_USE_C90_QSORT) \ - || (!defined(_GNU_SOURCE) && !defined(__APPLE__) && !defined(_MSC_VER)) +#if ZDICT_QSORT == ZDICT_QSORT_C90 /* Use global context for non-reentrant sort functions */ static COVER_ctx_t *g_coverCtx = NULL; #endif @@ -282,9 +305,9 @@ static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) { /** * Same as COVER_cmp() except ties are broken by pointer value */ -#if (defined(_WIN32) && defined(_MSC_VER)) || defined(__APPLE__) +#if (ZDICT_QSORT == ZDICT_QSORT_MSVC) || (ZDICT_QSORT == ZDICT_QSORT_APPLE) static int WIN_CDECL COVER_strict_cmp(void* g_coverCtx, const void* lp, const void* rp) { -#elif defined(_GNU_SOURCE) && !defined(ZSTD_USE_C90_QSORT) +#elif (ZDICT_QSORT == ZDICT_QSORT_GNU) static int COVER_strict_cmp(const void *lp, const void *rp, void *g_coverCtx) { #else /* C90 fallback.*/ static int COVER_strict_cmp(const void *lp, const void *rp) { @@ -298,9 +321,9 @@ static int COVER_strict_cmp(const void *lp, const void *rp) { /** * Faster version for d <= 8. */ -#if (defined(_WIN32) && defined(_MSC_VER)) || defined(__APPLE__) +#if (ZDICT_QSORT == ZDICT_QSORT_MSVC) || (ZDICT_QSORT == ZDICT_QSORT_APPLE) static int WIN_CDECL COVER_strict_cmp8(void* g_coverCtx, const void* lp, const void* rp) { -#elif defined(_GNU_SOURCE) && !defined(ZSTD_USE_C90_QSORT) +#elif (ZDICT_QSORT == ZDICT_QSORT_GNU) static int COVER_strict_cmp8(const void *lp, const void *rp, void *g_coverCtx) { #else /* C90 fallback.*/ static int COVER_strict_cmp8(const void *lp, const void *rp) { @@ -317,20 +340,26 @@ static int COVER_strict_cmp8(const void *lp, const void *rp) { * Hopefully when C11 become the norm, we will be able * to clean it up. */ -static void stableSort(COVER_ctx_t *ctx) { -#if defined(__APPLE__) +static void stableSort(COVER_ctx_t *ctx) +{ + DEBUG_STATIC_ASSERT(ZDICT_QSORT_MIN <= ZDICT_QSORT && ZDICT_QSORT <= ZDICT_QSORT_MAX); +#if (ZDICT_QSORT == ZDICT_QSORT_APPLE) qsort_r(ctx->suffix, ctx->suffixSize, sizeof(U32), ctx, (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); -#elif defined(_GNU_SOURCE) && !defined(ZSTD_USE_C90_QSORT) +#elif (ZDICT_QSORT == ZDICT_QSORT_GNU) qsort_r(ctx->suffix, ctx->suffixSize, sizeof(U32), (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp), ctx); -#elif defined(_WIN32) && defined(_MSC_VER) +#elif (ZDICT_QSORT == ZDICT_QSORT_MSVC) qsort_s(ctx->suffix, ctx->suffixSize, sizeof(U32), (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp), ctx); #elif defined(__OpenBSD__) + /* On OpenBSD, qsort() is not guaranteed to be stable, their mergesort() is. + * Note(@cyan): qsort() is never guaranteed to be stable, + * so why would this property only matter for OpenBSD ? + */ g_coverCtx = ctx; mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32), (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); @@ -782,7 +811,7 @@ ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_cover( BYTE* const dict = (BYTE*)dictBuffer; COVER_ctx_t ctx; COVER_map_t activeDmers; - const int displayLevel = parameters.zParams.notificationLevel; + const int displayLevel = (int)parameters.zParams.notificationLevel; parameters.splitPoint = 1.0; /* Checks */ if (!COVER_checkParameters(parameters, dictBufferCapacity)) { From a9b8fef2e808c227058da4d0f41768c877cfba4c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 11 Mar 2025 13:30:25 -0700 Subject: [PATCH 061/245] add support for C11 Annex K qsort_s() standard defined re-entrant variant of qsort(). Unfortunately, Annex K is optional. --- .github/workflows/dev-short-tests.yml | 2 +- lib/dictBuilder/cover.c | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 164dc15c7..da35ec675 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -693,7 +693,7 @@ jobs: - name: Install musl-tools run: | sudo apt install -y musl-tools - - name: Compile the project with musl-gcc + - name: Compile with musl-gcc and test-zstd run: | CC=musl-gcc CFLAGS="-Werror -O3" CPPFLAGS=-DZDICT_QSORT=ZDICT_QSORT_C90 make -j -C tests test-zstd V=1 diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 9ed360033..467c1b17f 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -29,6 +29,8 @@ # endif #endif +#define __STDC_WANT_LIB_EXT1__ 1 /* request C11 Annex K, which includes qsort_s() */ + #include /* fprintf */ #include /* malloc, free, qsort_r */ @@ -68,8 +70,9 @@ #define ZDICT_QSORT_C90 ZDICT_QSORT_MIN #define ZDICT_QSORT_GNU 1 #define ZDICT_QSORT_APPLE 2 -#define ZDICT_QSORT_MSVC ZDICT_QSORT_MAX -#define ZDICT_QSORT_MAX 3 +#define ZDICT_QSORT_MSVC 3 +#define ZDICT_QSORT_C11 ZDICT_QSORT_MAX +#define ZDICT_QSORT_MAX 4 #ifndef ZDICT_QSORT # if defined(__APPLE__) @@ -77,7 +80,9 @@ # elif defined(_GNU_SOURCE) # define ZDICT_QSORT ZDICT_QSORT_GNU /* uses qsort_r() */ # elif defined(_WIN32) && defined(_MSC_VER) -# define ZDICT_QSORT ZDICT_QSORT_MSVC /* uses qsort_s() */ +# define ZDICT_QSORT ZDICT_QSORT_MSVC /* uses qsort_s() with a different order for parameters */ +# elif defined(STDC_LIB_EXT1) && (STDC_LIB_EXT1 > 0) /* C11 Annex K */ +# define ZDICT_QSORT ZDICT_QSORT_C11 /* uses qsort_s() */ # else # define ZDICT_QSORT ZDICT_QSORT_C90 /* uses standard qsort() which is not re-entrant (requires global variable) */ # endif @@ -204,7 +209,7 @@ static U32 *COVER_map_at(COVER_map_t *map, U32 key) { */ static void COVER_map_remove(COVER_map_t *map, U32 key) { U32 i = COVER_map_index(map, key); - COVER_map_pair_t *del = &map->data[i]; + COVER_map_pair_t* del = &map->data[i]; U32 shift = 1; if (del->value == MAP_EMPTY_VALUE) { return; @@ -307,7 +312,7 @@ static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) { */ #if (ZDICT_QSORT == ZDICT_QSORT_MSVC) || (ZDICT_QSORT == ZDICT_QSORT_APPLE) static int WIN_CDECL COVER_strict_cmp(void* g_coverCtx, const void* lp, const void* rp) { -#elif (ZDICT_QSORT == ZDICT_QSORT_GNU) +#elif (ZDICT_QSORT == ZDICT_QSORT_GNU) || (ZDICT_QSORT == ZDICT_QSORT_C11) static int COVER_strict_cmp(const void *lp, const void *rp, void *g_coverCtx) { #else /* C90 fallback.*/ static int COVER_strict_cmp(const void *lp, const void *rp) { @@ -323,7 +328,7 @@ static int COVER_strict_cmp(const void *lp, const void *rp) { */ #if (ZDICT_QSORT == ZDICT_QSORT_MSVC) || (ZDICT_QSORT == ZDICT_QSORT_APPLE) static int WIN_CDECL COVER_strict_cmp8(void* g_coverCtx, const void* lp, const void* rp) { -#elif (ZDICT_QSORT == ZDICT_QSORT_GNU) +#elif (ZDICT_QSORT == ZDICT_QSORT_GNU) || (ZDICT_QSORT == ZDICT_QSORT_C11) static int COVER_strict_cmp8(const void *lp, const void *rp, void *g_coverCtx) { #else /* C90 fallback.*/ static int COVER_strict_cmp8(const void *lp, const void *rp) { @@ -355,6 +360,10 @@ static void stableSort(COVER_ctx_t *ctx) qsort_s(ctx->suffix, ctx->suffixSize, sizeof(U32), (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp), ctx); +#elif (ZDICT_QSORT == ZDICT_QSORT_C11) + qsort_s(ctx->suffix, ctx->suffixSize, sizeof(U32), + (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp), + ctx); #elif defined(__OpenBSD__) /* On OpenBSD, qsort() is not guaranteed to be stable, their mergesort() is. * Note(@cyan): qsort() is never guaranteed to be stable, From ddcb41a28204d5e298b052bef5cd839088d3bc6d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 11 Mar 2025 14:10:11 -0700 Subject: [PATCH 062/245] updated documentation --- lib/README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/README.md b/lib/README.md index 83bf00c19..89e53e6c8 100644 --- a/lib/README.md +++ b/lib/README.md @@ -193,11 +193,10 @@ The file structure is designed to make this selection manually achievable for an and assembly decoding loops. You may want to use this macro if these loops are slower on your platform. -- The macro `ZDICT_QSORT` can enforce selection of a specific sorting variant. - It can be notably set as `ZDICT_QSORT=ZDICT_QSORT_C90`, - for situations where autodetection fails, - for example with older versions of `musl`. - Other selectable suffixes are `_GNU`, `_APPLE` and `_MSVC`. +- The macro `ZDICT_QSORT` can enforce selection of a specific sorting variant, + which is useful when autodetection fails, for example with older versions of `musl`. + For this scenario, it can be set as `ZDICT_QSORT=ZDICT_QSORT_C90`. + Other selectable suffixes are `_GNU`, `_APPLE`, `_MSVC` and `_C11`. #### Windows : using MinGW+MSYS to create DLL From 4d53e27144b5ad02c6c37c27a998300986a4adaa Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 12 Mar 2025 09:55:14 -0700 Subject: [PATCH 063/245] removed OpenBSD specificity --- lib/dictBuilder/cover.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 467c1b17f..92c22a96c 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -364,14 +364,6 @@ static void stableSort(COVER_ctx_t *ctx) qsort_s(ctx->suffix, ctx->suffixSize, sizeof(U32), (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp), ctx); -#elif defined(__OpenBSD__) - /* On OpenBSD, qsort() is not guaranteed to be stable, their mergesort() is. - * Note(@cyan): qsort() is never guaranteed to be stable, - * so why would this property only matter for OpenBSD ? - */ - g_coverCtx = ctx; - mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32), - (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); #else /* C90 fallback.*/ g_coverCtx = ctx; /* TODO(cavalcanti): implement a reentrant qsort() when _r is not available. */ From cd8ca9d92e6fb3a4c962f8f6f50c3ee467177e06 Mon Sep 17 00:00:00 2001 From: "Z. Liu" Date: Thu, 20 Mar 2025 03:28:37 +0000 Subject: [PATCH 064/245] lib/zstd.h: move pragma before static otherwise will cause dev-python/zstandard build failed when compiling with clang as reported at https://bugs.gentoo.org/950259 the root cause is pycparser, which is unfixed since reported 2.5 years ago, :( Signed-off-by: Z. Liu --- lib/zstd.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index 9fe542edc..850469490 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1868,15 +1868,14 @@ ZSTDLIB_STATIC_API const ZSTD_DDict* ZSTD_initStaticDDict( typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); typedef void (*ZSTD_freeFunction) (void* opaque, void* address); typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; -static -#ifdef __GNUC__ -__attribute__((__unused__)) -#endif - #if defined(__clang__) && __clang_major__ >= 5 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" #endif +static +#ifdef __GNUC__ +__attribute__((__unused__)) +#endif ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ #if defined(__clang__) && __clang_major__ >= 5 #pragma clang diagnostic pop From 2fec3989c1567e0bd9b52100ad8c821886acf402 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 22 Mar 2025 18:23:31 -0700 Subject: [PATCH 065/245] add an assert to help static analyzers understand there is no overflow risk there. --- lib/compress/huf_compress.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/compress/huf_compress.c b/lib/compress/huf_compress.c index ea0007232..6f2194e79 100644 --- a/lib/compress/huf_compress.c +++ b/lib/compress/huf_compress.c @@ -425,6 +425,7 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 targetNbBits * gain back half the rank. */ U32 nBitsToDecrease = ZSTD_highbit32((U32)totalCost) + 1; + assert(nBitsToDecrease <= HUF_TABLELOG_MAX+1); for ( ; nBitsToDecrease > 1; nBitsToDecrease--) { U32 const highPos = rankLast[nBitsToDecrease]; U32 const lowPos = rankLast[nBitsToDecrease-1]; From bea1e942f7f6e5c6502ad5dec8ce35954d41043e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 22 Mar 2025 23:52:45 -0700 Subject: [PATCH 066/245] [doc] minor clarification for maximum block size closes #4339 --- doc/zstd_compression_format.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/zstd_compression_format.md b/doc/zstd_compression_format.md index a2bf20cbc..7700c472d 100644 --- a/doc/zstd_compression_format.md +++ b/doc/zstd_compression_format.md @@ -16,7 +16,7 @@ Distribution of this document is unlimited. ### Version -0.4.3 (2024-10-07) +0.4.4 (2025-03-22) Introduction @@ -390,7 +390,7 @@ __`Block_Content`__ and __`Block_Maximum_Size`__ The size of `Block_Content` is limited by `Block_Maximum_Size`, which is the smallest of: - `Window_Size` -- 128 KB +- 128 KiB (131.072 bytes) `Block_Maximum_Size` is constant for a given frame. This maximum is applicable to both the decompressed size @@ -1742,6 +1742,7 @@ or at least provide a meaningful error code explaining for which reason it canno Version changes --------------- +- 0.4.4 : minor clarification for block size - 0.4.3 : clarifications for Huffman prefix code assignment example - 0.4.2 : refactor FSE table construction process, inspired by Donald Pian - 0.4.1 : clarifications on a few error scenarios, by Eric Lasota From 33f4d40d1eaa6fadca6960c3b8ec05e522cb6d99 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 23 Mar 2025 11:42:41 -0700 Subject: [PATCH 067/245] fix a risk of overflow on a time counter on Windows closes #4126 --- programs/timefn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/programs/timefn.c b/programs/timefn.c index 4f045226b..d7f330974 100644 --- a/programs/timefn.c +++ b/programs/timefn.c @@ -28,18 +28,20 @@ UTIL_time_t UTIL_getTime(void) { static LARGE_INTEGER ticksPerSecond; + static double nsFactor = 1.0; static int init = 0; if (!init) { if (!QueryPerformanceFrequency(&ticksPerSecond)) { perror("timefn::QueryPerformanceFrequency"); abort(); } + nsFactor = 1000000000.0 / (double)ticksPerSecond.QuadPart; init = 1; } { UTIL_time_t r; LARGE_INTEGER x; QueryPerformanceCounter(&x); - r.t = (PTime)(x.QuadPart * 1000000000ULL / ticksPerSecond.QuadPart); + r.t = (PTime)((double)x.QuadPart * nsFactor); return r; } } From c59f7ac51ec943b5c5ea0746e97a225ee2d56881 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 23 Mar 2025 12:02:51 -0700 Subject: [PATCH 068/245] update benchmark result brotli uses -1 level, like all other compressors --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 22a127dc9..c542bb40e 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ on the [Silesia compression corpus]. | Compressor name | Ratio | Compression| Decompress.| | --------------- | ------| -----------| ---------- | | **zstd 1.5.7 -1** | 2.896 | 510 MB/s | 1550 MB/s | +| brotli 1.1.0 -1 | 2.883 | 290 MB/s | 425 MB/s | | [zlib] 1.3.1 -1 | 2.743 | 105 MB/s | 390 MB/s | -| brotli 1.1.0 -0 | 2.702 | 400 MB/s | 425 MB/s | | **zstd 1.5.7 --fast=1** | 2.439 | 545 MB/s | 1850 MB/s | | **zstd 1.5.7 --fast=3** | 2.241 | 635 MB/s | 1980 MB/s | | quicklz 1.5.0 -1 | 2.238 | 520 MB/s | 750 MB/s | From 334af7228065f93e6d012f7edfa9593f0f1374af Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 23 Mar 2025 12:06:58 -0700 Subject: [PATCH 069/245] update zstd --fast benchmark result use --fast=4, instead of --fast=3, to make it more representative of a lzo equivalent scenario. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c542bb40e..3adacad51 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,8 @@ on the [Silesia compression corpus]. | brotli 1.1.0 -1 | 2.883 | 290 MB/s | 425 MB/s | | [zlib] 1.3.1 -1 | 2.743 | 105 MB/s | 390 MB/s | | **zstd 1.5.7 --fast=1** | 2.439 | 545 MB/s | 1850 MB/s | -| **zstd 1.5.7 --fast=3** | 2.241 | 635 MB/s | 1980 MB/s | | quicklz 1.5.0 -1 | 2.238 | 520 MB/s | 750 MB/s | +| **zstd 1.5.7 --fast=4** | 2.146 | 665 MB/s | 2050 MB/s | | lzo1x 2.10 -1 | 2.106 | 650 MB/s | 780 MB/s | | [lz4] 1.10.0 | 2.101 | 675 MB/s | 3850 MB/s | | snappy 1.2.1 | 2.089 | 520 MB/s | 1500 MB/s | From eb168a0afc062f49b3d2180db69ce380c5085509 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 25 Mar 2025 14:23:14 -0700 Subject: [PATCH 070/245] add --patch-apply command as an equivalent for `-d --patch-from`. Requested by @sergeevabc in #2173. --- programs/zstdcli.c | 4 +++- tests/playTests.sh | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 4fed04e13..b9f961c16 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -230,7 +230,8 @@ static void usageAdvanced(const char* programName) #endif DISPLAYOUT(" --adapt Dynamically adapt compression level to I/O conditions.\n"); DISPLAYOUT(" --long[=#] Enable long distance matching with window log #. [Default: %u]\n", g_defaultMaxWindowLog); - DISPLAYOUT(" --patch-from=REF Use REF as the reference point for Zstandard's diff engine. \n\n"); + DISPLAYOUT(" --patch-from=REF Use REF as the reference point for Zstandard's diff engine. \n"); + DISPLAYOUT(" --patch-apply Equivalent for `-d --patch-from` \n\n"); # ifdef ZSTD_MULTITHREAD DISPLAYOUT(" -T# Spawn # compression threads. [Default: 1; pass 0 for core count.]\n"); DISPLAYOUT(" --single-thread Share a single thread for I/O and compression (slightly different than `-T1`).\n"); @@ -1124,6 +1125,7 @@ int main(int argCount, const char* argv[]) if (longCommandWArg(&argument, "--trace")) { char const* traceFile; NEXT_FIELD(traceFile); TRACE_enable(traceFile); continue; } #endif if (longCommandWArg(&argument, "--patch-from")) { NEXT_FIELD(patchFromDictFileName); ultra = 1; continue; } + if (longCommandWArg(&argument, "--patch-apply")) { operation=zom_decompress; NEXT_FIELD(patchFromDictFileName); memLimit= 1U << ZSTD_WINDOWLOG_MAX; continue; } if (longCommandWArg(&argument, "--long")) { unsigned ldmWindowLog = 0; ldmFlag = 1; diff --git a/tests/playTests.sh b/tests/playTests.sh index 15f6e7761..486b395eb 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -1777,11 +1777,15 @@ datagen -g1000 -P10 > tmp_patch zstd --patch-from=tmp_dict tmp_patch -o tmp_patch_diff zstd -d --patch-from=tmp_dict tmp_patch_diff -o tmp_patch_recon $DIFF -s tmp_patch_recon tmp_patch +zstd -f --patch-apply=tmp_dict tmp_patch_diff -o tmp_patch_recon +$DIFF -s tmp_patch_recon tmp_patch println "\n===> alternate syntax: patch-from origin" zstd -f --patch-from tmp_dict tmp_patch -o tmp_patch_diff zstd -df --patch-from tmp_dict tmp_patch_diff -o tmp_patch_recon $DIFF -s tmp_patch_recon tmp_patch +zstd -f --patch-apply tmp_dict tmp_patch_diff -o tmp_patch_recon +$DIFF -s tmp_patch_recon tmp_patch rm -rf tmp_* println "\n===> patch-from recursive tests" From 165e52ce627169e285c06d1d7879623fb75fcadd Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 24 Mar 2025 20:42:52 -0700 Subject: [PATCH 071/245] first implementation supporting Process Substitution --- programs/fileio.c | 8 +- programs/util.c | 192 ++++++++++++++++++++++++++++------------------ programs/util.h | 1 + 3 files changed, 123 insertions(+), 78 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 3f4460594..644a86ef4 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -537,15 +537,13 @@ static int FIO_removeFile(const char* path) return remove(path); } -/** FIO_openSrcFile() : - * condition : `srcFileName` must be non-NULL. `prefs` may be NULL. - * @result : FILE* to `srcFileName`, or NULL if it fails */ static FILE* FIO_openSrcFile(const FIO_prefs_t* const prefs, const char* srcFileName, stat_t* statbuf) { int allowBlockDevices = prefs != NULL ? prefs->allowBlockDevices : 0; assert(srcFileName != NULL); assert(statbuf != NULL); - if (!strcmp (srcFileName, stdinmark)) { + + if (!strcmp(srcFileName, stdinmark)) { DISPLAYLEVEL(4,"Using stdin for input \n"); SET_BINARY_MODE(stdin); return stdin; @@ -557,8 +555,10 @@ static FILE* FIO_openSrcFile(const FIO_prefs_t* const prefs, const char* srcFile return NULL; } + /* Accept regular files, FIFOs, and process substitution file descriptors */ if (!UTIL_isRegularFileStat(statbuf) && !UTIL_isFIFOStat(statbuf) + && !UTIL_isFileDescriptorPipe(srcFileName) /* Process substitution support */ && !(allowBlockDevices && UTIL_isBlockDevStat(statbuf)) ) { DISPLAYLEVEL(1, "zstd: %s is not a regular file -- ignored \n", diff --git a/programs/util.c b/programs/util.c index 065a35855..506bdd09e 100644 --- a/programs/util.c +++ b/programs/util.c @@ -448,6 +448,26 @@ int UTIL_isFIFOStat(const stat_t* statbuf) return 0; } +/* process substitution */ +int UTIL_isFileDescriptorPipe(const char* filename) +{ + UTIL_TRACE_CALL("UTIL_isFileDescriptorPipe(%s)", filename); + /* Check if the filename is a /dev/fd/ path which indicates a file descriptor */ + if (filename[0] == '/' && strncmp(filename, "/dev/fd/", 8) == 0) { + UTIL_TRACE_RET(1); + return 1; + } + + /* Check for alternative process substitution formats on different systems */ + if (filename[0] == '/' && strncmp(filename, "/proc/self/fd/", 14) == 0) { + UTIL_TRACE_RET(1); + return 1; + } + + UTIL_TRACE_RET(0); + return 0; /* Not recognized as a file descriptor pipe */ +} + /* UTIL_isBlockDevStat : distinguish named pipes */ int UTIL_isBlockDevStat(const stat_t* statbuf) { @@ -614,95 +634,119 @@ U64 UTIL_getTotalFileSize(const char* const * fileNamesTable, unsigned nbFiles) } -/* condition : @file must be valid, and not have reached its end. - * @return : length of line written into @buf, ended with `\0` instead of '\n', - * or 0, if there is no new line */ -static size_t readLineFromFile(char* buf, size_t len, FILE* file) -{ - assert(!feof(file)); - if ( fgets(buf, (int) len, file) == NULL ) return 0; - { size_t linelen = strlen(buf); - if (strlen(buf)==0) return 0; - if (buf[linelen-1] == '\n') linelen--; - buf[linelen] = '\0'; - return linelen+1; - } -} - -/* Conditions : - * size of @inputFileName file must be < @dstCapacity - * @dst must be initialized - * @return : nb of lines - * or -1 if there's an error - */ -static int -readLinesFromFile(void* dst, size_t dstCapacity, - const char* inputFileName) -{ - int nbFiles = 0; - size_t pos = 0; - char* const buf = (char*)dst; - FILE* const inputFile = fopen(inputFileName, "r"); - - assert(dst != NULL); - - if(!inputFile) { - if (g_utilDisplayLevel >= 1) perror("zstd:util:readLinesFromFile"); - return -1; - } - - while ( !feof(inputFile) ) { - size_t const lineLength = readLineFromFile(buf+pos, dstCapacity-pos, inputFile); - if (lineLength == 0) break; - assert(pos + lineLength <= dstCapacity); /* '=' for inputFile not terminated with '\n' */ - pos += lineLength; - ++nbFiles; - } - - CONTROL( fclose(inputFile) == 0 ); - - return nbFiles; -} - /*Note: buf is not freed in case function successfully created table because filesTable->fileNames[0] = buf*/ FileNamesTable* UTIL_createFileNamesTable_fromFileName(const char* inputFileName) { size_t nbFiles = 0; - char* buf; - size_t bufSize; - stat_t statbuf; + char* buf = NULL; + size_t bufSize = 0; + size_t totalRead = 0; + size_t bytesRead = 0; - if (!UTIL_stat(inputFileName, &statbuf) || !UTIL_isRegularFileStat(&statbuf)) - return NULL; - - { U64 const inputFileSize = UTIL_getFileSizeStat(&statbuf); - if(inputFileSize > MAX_FILE_OF_FILE_NAMES_SIZE) + /* Check if the input is a regular file or a file descriptor */ + { stat_t statbuf; + if (!UTIL_stat(inputFileName, &statbuf)) { + return NULL; + } + + if (!UTIL_isRegularFileStat(&statbuf) && + !UTIL_isFIFOStat(&statbuf) && + !UTIL_isFileDescriptorPipe(inputFileName)) { return NULL; - bufSize = (size_t)(inputFileSize + 1); /* (+1) to add '\0' at the end of last filename */ - } - - buf = (char*) malloc(bufSize); - CONTROL( buf != NULL ); - - { int const ret_nbFiles = readLinesFromFile(buf, bufSize, inputFileName); - - if (ret_nbFiles <= 0) { - free(buf); - return NULL; } - nbFiles = (size_t)ret_nbFiles; } - { const char** filenamesTable = (const char**) malloc(nbFiles * sizeof(*filenamesTable)); - CONTROL(filenamesTable != NULL); + /* Open the input file */ + { FILE* const inFile = fopen(inputFileName, "rb"); + if (inFile == NULL) return NULL; - { size_t fnb, pos = 0; + /* Start with a reasonable buffer size */ + bufSize = 64 * 1024; + buf = (char*)malloc(bufSize); + if (buf == NULL) { + fclose(inFile); + return NULL; + } + + /* Read the file incrementally */ + while ((bytesRead = fread(buf + totalRead, 1, bufSize - totalRead - 1, inFile)) > 0) { + totalRead += bytesRead; + + /* If buffer is nearly full, expand it */ + if (bufSize - totalRead < 1024) { + size_t newBufSize; + if (bufSize >= MAX_FILE_OF_FILE_NAMES_SIZE) { + /* Too large, abort */ + free(buf); + fclose(inFile); + return NULL; + } + + newBufSize = bufSize * 2; + if (newBufSize > MAX_FILE_OF_FILE_NAMES_SIZE) + newBufSize = MAX_FILE_OF_FILE_NAMES_SIZE; + + { char* newBuf = (char*)realloc(buf, newBufSize); + if (newBuf == NULL) { + free(buf); + fclose(inFile); + return NULL; + } + + buf = newBuf; + } + bufSize = newBufSize; + } + } + + fclose(inFile); + } + + /* Add null terminator to the end */ + buf[totalRead] = '\0'; + + /* Count and process the lines */ + { + size_t lineCount = 0; + size_t i = 0; + + /* Convert newlines to null terminators and count lines */ + while (i < totalRead) { + if (buf[i] == '\n') { + buf[i] = '\0'; /* Replace newlines with null terminators */ + lineCount++; + } + i++; + } + + /* Count the last line if it doesn't end with a newline */ + if (totalRead > 0 && buf[totalRead-1] != '\0') { + lineCount++; + } + + nbFiles = lineCount; + } + + if (nbFiles == 0) { + free(buf); + return NULL; + } + + /* Create the file names table */ + { const char** filenamesTable = (const char**)malloc(nbFiles * sizeof(*filenamesTable)); + if (filenamesTable == NULL) { + free(buf); + return NULL; + } + + { + size_t fnb, pos = 0; for (fnb = 0; fnb < nbFiles; fnb++) { filenamesTable[fnb] = buf+pos; pos += strlen(buf+pos)+1; /* +1 for the finishing `\0` */ } - assert(pos <= bufSize); + assert(pos <= bufSize); } return UTIL_assembleFileNamesTable(filenamesTable, nbFiles, buf); diff --git a/programs/util.h b/programs/util.h index d768e7660..5fd5de40b 100644 --- a/programs/util.h +++ b/programs/util.h @@ -191,6 +191,7 @@ int UTIL_isSameFileStat(const char* file1, const char* file2, const stat_t* file int UTIL_isCompressedFile(const char* infilename, const char *extensionList[]); int UTIL_isLink(const char* infilename); int UTIL_isFIFO(const char* infilename); +int UTIL_isFileDescriptorPipe(const char* filename); /** * Returns with the given file descriptor is a console. From 7630870b4747bc90cba2aa90fea0df4a89bfabc3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 24 Mar 2025 20:47:56 -0700 Subject: [PATCH 072/245] second implementation, better structured for improved maintenance --- programs/util.c | 192 ++++++++++++++++++++++++++---------------------- 1 file changed, 106 insertions(+), 86 deletions(-) diff --git a/programs/util.c b/programs/util.c index 506bdd09e..b6431b49f 100644 --- a/programs/util.c +++ b/programs/util.c @@ -151,7 +151,8 @@ int UTIL_requireUserConfirmation(const char* prompt, const char* abortMsg, /*-************************************* * Constants ***************************************/ -#define LIST_SIZE_INCREASE (8*1024) +#define KB * (1 << 10) +#define LIST_SIZE_INCREASE (8 KB) #define MAX_FILE_OF_FILE_NAMES_SIZE (1<<20)*50 @@ -634,125 +635,144 @@ U64 UTIL_getTotalFileSize(const char* const * fileNamesTable, unsigned nbFiles) } -/*Note: buf is not freed in case function successfully created table because filesTable->fileNames[0] = buf*/ -FileNamesTable* -UTIL_createFileNamesTable_fromFileName(const char* inputFileName) +/* Read the entire content of a file into a buffer with progressive resizing */ +static char* UTIL_readFileContent(FILE* inFile, size_t* totalReadPtr) { - size_t nbFiles = 0; - char* buf = NULL; - size_t bufSize = 0; + size_t bufSize = 64 KB; /* Start with a reasonable buffer size */ size_t totalRead = 0; size_t bytesRead = 0; + char* buf = (char*)malloc(bufSize); + if (buf == NULL) return NULL; - /* Check if the input is a regular file or a file descriptor */ - { stat_t statbuf; - if (!UTIL_stat(inputFileName, &statbuf)) { - return NULL; - } - if (!UTIL_isRegularFileStat(&statbuf) && - !UTIL_isFIFOStat(&statbuf) && - !UTIL_isFileDescriptorPipe(inputFileName)) { - return NULL; - } - } + /* Read the file incrementally */ + while ((bytesRead = fread(buf + totalRead, 1, bufSize - totalRead - 1, inFile)) > 0) { + totalRead += bytesRead; - /* Open the input file */ - { FILE* const inFile = fopen(inputFileName, "rb"); - if (inFile == NULL) return NULL; + /* If buffer is nearly full, expand it */ + if (bufSize - totalRead < 1 KB) { + if (bufSize >= MAX_FILE_OF_FILE_NAMES_SIZE) { + /* Too large, abort */ + free(buf); + return NULL; + } - /* Start with a reasonable buffer size */ - bufSize = 64 * 1024; - buf = (char*)malloc(bufSize); - if (buf == NULL) { - fclose(inFile); - return NULL; - } - - /* Read the file incrementally */ - while ((bytesRead = fread(buf + totalRead, 1, bufSize - totalRead - 1, inFile)) > 0) { - totalRead += bytesRead; - - /* If buffer is nearly full, expand it */ - if (bufSize - totalRead < 1024) { - size_t newBufSize; - if (bufSize >= MAX_FILE_OF_FILE_NAMES_SIZE) { - /* Too large, abort */ - free(buf); - fclose(inFile); - return NULL; - } - - newBufSize = bufSize * 2; + { size_t newBufSize = bufSize * 2; if (newBufSize > MAX_FILE_OF_FILE_NAMES_SIZE) newBufSize = MAX_FILE_OF_FILE_NAMES_SIZE; { char* newBuf = (char*)realloc(buf, newBufSize); if (newBuf == NULL) { free(buf); - fclose(inFile); return NULL; } buf = newBuf; - } - bufSize = newBufSize; - } - } - - fclose(inFile); + bufSize = newBufSize; + } } } } /* Add null terminator to the end */ buf[totalRead] = '\0'; + *totalReadPtr = totalRead; - /* Count and process the lines */ - { - size_t lineCount = 0; - size_t i = 0; + return buf; +} - /* Convert newlines to null terminators and count lines */ - while (i < totalRead) { - if (buf[i] == '\n') { - buf[i] = '\0'; /* Replace newlines with null terminators */ - lineCount++; - } - i++; - } +/* Process a buffer containing multiple lines and count the number of lines */ +static size_t UTIL_processLines(char* buffer, size_t bufferSize) +{ + size_t lineCount = 0; + size_t i = 0; - /* Count the last line if it doesn't end with a newline */ - if (totalRead > 0 && buf[totalRead-1] != '\0') { + /* Convert newlines to null terminators and count lines */ + while (i < bufferSize) { + if (buffer[i] == '\n') { + buffer[i] = '\0'; /* Replace newlines with null terminators */ lineCount++; } - - nbFiles = lineCount; + i++; } - if (nbFiles == 0) { - free(buf); + /* Count the last line if it doesn't end with a newline */ + if (bufferSize > 0 && (i == 0 || buffer[i-1] != '\0')) { + lineCount++; + } + + return lineCount; +} + +/* Create an array of pointers to the lines in a buffer */ +static const char** +UTIL_createLinePointers(char* buffer, size_t numLines, size_t bufferSize) +{ + size_t lineIndex = 0; + size_t pos = 0; + const char** linePointers = (const char**)malloc(numLines * sizeof(*linePointers)); + if (linePointers == NULL) return NULL; + + while (lineIndex < numLines && pos < bufferSize) { + linePointers[lineIndex++] = buffer + pos; + pos += strlen(buffer + pos) + 1; /* +1 for the finishing `\0` */ + } + + assert(pos <= bufferSize); + assert(lineIndex == numLines); + + return linePointers; +} + +FileNamesTable* +UTIL_createFileNamesTable_fromFileName(const char* inputFileName) +{ + stat_t statbuf; + FILE* inFile = NULL; + char* buffer = NULL; + const char** linePointers = NULL; + size_t numLines = 0; + size_t bufferSize = 0; + + /* Check if the input is a valid file */ + if (!UTIL_stat(inputFileName, &statbuf)) { return NULL; } - /* Create the file names table */ - { const char** filenamesTable = (const char**)malloc(nbFiles * sizeof(*filenamesTable)); - if (filenamesTable == NULL) { - free(buf); - return NULL; - } - - { - size_t fnb, pos = 0; - for (fnb = 0; fnb < nbFiles; fnb++) { - filenamesTable[fnb] = buf+pos; - pos += strlen(buf+pos)+1; /* +1 for the finishing `\0` */ - } - assert(pos <= bufSize); - } - - return UTIL_assembleFileNamesTable(filenamesTable, nbFiles, buf); + /* Check if the input is a supported type */ + if (!UTIL_isRegularFileStat(&statbuf) && + !UTIL_isFIFOStat(&statbuf) && + !UTIL_isFileDescriptorPipe(inputFileName)) { + return NULL; } + + /* Open the input file */ + inFile = fopen(inputFileName, "rb"); + if (inFile == NULL) return NULL; + + /* Read the file content */ + buffer = UTIL_readFileContent(inFile, &bufferSize); + fclose(inFile); + + if (buffer == NULL) return NULL; + + /* Process lines */ + numLines = UTIL_processLines(buffer, bufferSize); + if (numLines == 0) { + free(buffer); + return NULL; + } + + /* Create line pointers */ + linePointers = UTIL_createLinePointers(buffer, numLines, bufferSize); + if (linePointers == NULL) { + free(buffer); + return NULL; + } + + /* Create the final table */ + return UTIL_assembleFileNamesTable(linePointers, numLines, buffer); } + static FileNamesTable* UTIL_assembleFileNamesTable2(const char** filenames, size_t tableSize, size_t tableCapacity, char* buf) { From 76c2fdc7b76e1ab502dd058af9e58a22eeb382ad Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 24 Mar 2025 21:20:21 -0700 Subject: [PATCH 073/245] better naming and more narrow scope of local variables --- programs/util.c | 34 +++++++++++++++++----------------- programs/util.h | 4 ++-- programs/zstdcli.c | 2 +- tests/playTests.sh | 1 + 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/programs/util.c b/programs/util.c index b6431b49f..43f2b9408 100644 --- a/programs/util.c +++ b/programs/util.c @@ -723,34 +723,33 @@ UTIL_createLinePointers(char* buffer, size_t numLines, size_t bufferSize) } FileNamesTable* -UTIL_createFileNamesTable_fromFileName(const char* inputFileName) +UTIL_createFileNamesTable_fromFileList(const char* fileList) { stat_t statbuf; - FILE* inFile = NULL; char* buffer = NULL; - const char** linePointers = NULL; size_t numLines = 0; size_t bufferSize = 0; /* Check if the input is a valid file */ - if (!UTIL_stat(inputFileName, &statbuf)) { + if (!UTIL_stat(fileList, &statbuf)) { return NULL; } /* Check if the input is a supported type */ if (!UTIL_isRegularFileStat(&statbuf) && !UTIL_isFIFOStat(&statbuf) && - !UTIL_isFileDescriptorPipe(inputFileName)) { + !UTIL_isFileDescriptorPipe(fileList)) { return NULL; } /* Open the input file */ - inFile = fopen(inputFileName, "rb"); - if (inFile == NULL) return NULL; + { FILE* const inFile = fopen(fileList, "rb"); + if (inFile == NULL) return NULL; - /* Read the file content */ - buffer = UTIL_readFileContent(inFile, &bufferSize); - fclose(inFile); + /* Read the file content */ + buffer = UTIL_readFileContent(inFile, &bufferSize); + fclose(inFile); + } if (buffer == NULL) return NULL; @@ -762,14 +761,15 @@ UTIL_createFileNamesTable_fromFileName(const char* inputFileName) } /* Create line pointers */ - linePointers = UTIL_createLinePointers(buffer, numLines, bufferSize); - if (linePointers == NULL) { - free(buffer); - return NULL; - } + { const char** linePointers = UTIL_createLinePointers(buffer, numLines, bufferSize); + if (linePointers == NULL) { + free(buffer); + return NULL; + } - /* Create the final table */ - return UTIL_assembleFileNamesTable(linePointers, numLines, buffer); + /* Create the final table */ + return UTIL_assembleFileNamesTable(linePointers, numLines, buffer); + } } diff --git a/programs/util.h b/programs/util.h index 5fd5de40b..427bcf441 100644 --- a/programs/util.h +++ b/programs/util.h @@ -251,13 +251,13 @@ typedef struct size_t tableCapacity; } FileNamesTable; -/*! UTIL_createFileNamesTable_fromFileName() : +/*! UTIL_createFileNamesTable_fromFileList() : * read filenames from @inputFileName, and store them into returned object. * @return : a FileNamesTable*, or NULL in case of error (ex: @inputFileName doesn't exist). * Note: inputFileSize must be less than 50MB */ FileNamesTable* -UTIL_createFileNamesTable_fromFileName(const char* inputFileName); +UTIL_createFileNamesTable_fromFileList(const char* inputFileName); /*! UTIL_assembleFileNamesTable() : * This function takes ownership of its arguments, @filenames and @buf, diff --git a/programs/zstdcli.c b/programs/zstdcli.c index b9f961c16..fa7ea37b3 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1379,7 +1379,7 @@ int main(int argCount, const char* argv[]) size_t const nbFileLists = file_of_names->tableSize; size_t flNb; for (flNb=0; flNb < nbFileLists; flNb++) { - FileNamesTable* const fnt = UTIL_createFileNamesTable_fromFileName(file_of_names->fileNames[flNb]); + FileNamesTable* const fnt = UTIL_createFileNamesTable_fromFileList(file_of_names->fileNames[flNb]); if (fnt==NULL) { DISPLAYLEVEL(1, "zstd: error reading %s \n", file_of_names->fileNames[flNb]); CLEAN_RETURN(1); diff --git a/tests/playTests.sh b/tests/playTests.sh index 486b395eb..d3ce39846 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -848,6 +848,7 @@ ls tmp* > tmpList zstd -f tmp1 --filelist=tmpList --filelist=tmpList tmp2 tmp3 # can trigger an overflow of internal file list rm -rf tmp* + println "\n===> --[no-]content-size tests" datagen > tmp_contentsize From 94cfa0b5a064b91a61f8b49148ea857e042b51a1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 24 Mar 2025 21:31:51 -0700 Subject: [PATCH 074/245] minor: restore some code comment --- programs/fileio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/programs/fileio.c b/programs/fileio.c index 644a86ef4..6514bf32c 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -537,6 +537,10 @@ static int FIO_removeFile(const char* path) return remove(path); } +/** FIO_openSrcFile() : + * condition : `srcFileName` must be non-NULL. + * optional: `prefs` may be NULL. + * @result : FILE* to `srcFileName`, or NULL if it fails */ static FILE* FIO_openSrcFile(const FIO_prefs_t* const prefs, const char* srcFileName, stat_t* statbuf) { int allowBlockDevices = prefs != NULL ? prefs->allowBlockDevices : 0; From 0bde39a9b32af17a9c21313b7f8cadaf9ae224cd Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 25 Mar 2025 15:22:55 -0700 Subject: [PATCH 075/245] visual studio fix --- programs/util.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/programs/util.c b/programs/util.c index 43f2b9408..94c40cc95 100644 --- a/programs/util.c +++ b/programs/util.c @@ -703,21 +703,34 @@ static size_t UTIL_processLines(char* buffer, size_t bufferSize) } /* Create an array of pointers to the lines in a buffer */ -static const char** -UTIL_createLinePointers(char* buffer, size_t numLines, size_t bufferSize) +static const char** UTIL_createLinePointers(char* buffer, size_t numLines, size_t bufferSize) { size_t lineIndex = 0; size_t pos = 0; - const char** linePointers = (const char**)malloc(numLines * sizeof(*linePointers)); - if (linePointers == NULL) return NULL; + void* const bufferPtrs = malloc(numLines * sizeof(const char**)); + const char** const linePointers = (const char**)bufferPtrs; + if (bufferPtrs == NULL) return NULL; while (lineIndex < numLines && pos < bufferSize) { - linePointers[lineIndex++] = buffer + pos; - pos += strlen(buffer + pos) + 1; /* +1 for the finishing `\0` */ + size_t len = 0; + linePointers[lineIndex++] = buffer+pos; + + /* Find the next null terminator, being careful not to go past the buffer */ + while ((pos + len < bufferSize) && buffer[pos + len] != '\0') { + len++; + } + + /* Move past this string and its null terminator */ + pos += len; + if (pos < bufferSize) pos++; /* Skip the null terminator if we're not at buffer end */ } - assert(pos <= bufferSize); - assert(lineIndex == numLines); + /* Verify we processed the expected number of lines */ + if (lineIndex != numLines) { + /* Something went wrong - we didn't find as many lines as expected */ + free(bufferPtrs); + return NULL; + } return linePointers; } From a293cdcb8581b3ff7c460c48fe7fe1b061bdd2e2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 25 Mar 2025 16:39:42 -0700 Subject: [PATCH 076/245] added CI test --- .github/workflows/dev-long-tests.yml | 5 +- tests/test_process_substitution.bash | 92 ++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100755 tests/test_process_substitution.bash diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 275b22297..bf287857f 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -28,7 +28,10 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: make test - run: make test + run: | + make test + make -j zstd + ./tests/test_process_substitution.bash ./zstd # lasts ~26mn make-test-macos: diff --git a/tests/test_process_substitution.bash b/tests/test_process_substitution.bash new file mode 100755 index 000000000..586c42838 --- /dev/null +++ b/tests/test_process_substitution.bash @@ -0,0 +1,92 @@ +#!/usr/bin/env bash +# test_process_substitution.bash +# Test zstd's support for process substitution with --filelist + +# Process arguments +ZSTD_PATH="zstd" # Default to using zstd from PATH +if [ $# -ge 1 ]; then + ZSTD_PATH="$1" +fi + +echo "Using zstd executable: $ZSTD_PATH" + +set -e # Exit on error + +# Set up test directory and files +echo "Setting up test environment..." +TEST_DIR="tmp_process_substit" +rm -rf "$TEST_DIR" +mkdir -p "$TEST_DIR" +echo "Content of file 1" > "$TEST_DIR/file1.txt" +echo "Content of file 2" > "$TEST_DIR/file2.txt" +echo "Content of file 3" > "$TEST_DIR/file3.txt" + +# Clean up any previous test artifacts +rm -f "$TEST_DIR/output.zst" "$TEST_DIR/output_echo.zst" "$TEST_DIR/output_cat.zst" +rm -rf "$TEST_DIR/extracted" +mkdir -p "$TEST_DIR/extracted" + +echo "=== Testing process substitution with --filelist ===" + +# Test 1: Basic process substitution with find +echo "Test 1: Basic process substitution (find command)" +"$ZSTD_PATH" --filelist=<(find "$TEST_DIR" -name "*.txt" | sort) -c > "$TEST_DIR/output.zst" + +if [ -f "$TEST_DIR/output.zst" ]; then + echo "✓ Test 1 PASSED: Output file was created" +else + echo "✗ Test 1 FAILED: Output file was not created" + exit 1 +fi + +# Test 2: Process substitution with echo +echo "Test 2: Process substitution (echo command)" +"$ZSTD_PATH" --filelist=<(echo -e "$TEST_DIR/file1.txt\n$TEST_DIR/file2.txt") -c > "$TEST_DIR/output_echo.zst" + +if [ -f "$TEST_DIR/output_echo.zst" ]; then + echo "✓ Test 2 PASSED: Output file was created" +else + echo "✗ Test 2 FAILED: Output file was not created" + exit 1 +fi + +# Test 3: Process substitution with cat +echo "Test 3: Process substitution (cat command)" +echo -e "$TEST_DIR/file1.txt\n$TEST_DIR/file3.txt" > "$TEST_DIR/filelist.txt" +"$ZSTD_PATH" --filelist=<(cat "$TEST_DIR/filelist.txt") -c > "$TEST_DIR/output_cat.zst" + +if [ -f "$TEST_DIR/output_cat.zst" ]; then + echo "✓ Test 3 PASSED: Output file was created" +else + echo "✗ Test 3 FAILED: Output file was not created" + exit 1 +fi + +# Test 4: Verify contents of archives +echo "Test 4: Verifying archive contents" +"$ZSTD_PATH" -d "$TEST_DIR/output.zst" -o "$TEST_DIR/extracted/combined.out" + +if grep -q "Content of file 1" "$TEST_DIR/extracted/combined.out" && + grep -q "Content of file 2" "$TEST_DIR/extracted/combined.out" && + grep -q "Content of file 3" "$TEST_DIR/extracted/combined.out"; then + echo "✓ Test 4 PASSED: All files were correctly archived and extracted" +else + echo "✗ Test 4 FAILED: Not all expected content was found in the extracted file" + exit 1 +fi + +# Test 5: Edge case with empty list +echo "Test 5: Process substitution with empty input" +"$ZSTD_PATH" --filelist=<(echo "") -c > "$TEST_DIR/output_empty.zst" 2>/dev/null || true + +if [ -f "$TEST_DIR/output_empty.zst" ]; then + echo "✓ Test 5 PASSED: Handled empty input gracefully" +else + echo "✓ Test 5 PASSED: Properly rejected empty input" +fi + +# cleanup +rm -rf "$TEST_DIR" + +echo "All tests completed successfully!" + From 8626da73b6596bdd30c1289525db59f09737226d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 26 Mar 2025 19:21:48 -0700 Subject: [PATCH 077/245] add error message clarification for inputs as process substitution --- programs/fileio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/programs/fileio.c b/programs/fileio.c index 6514bf32c..6c6faa485 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -660,6 +660,9 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, #endif if (f == NULL) { DISPLAYLEVEL(1, "zstd: %s: %s\n", dstFileName, strerror(errno)); + if (UTIL_isFileDescriptorPipe(dstFileName)) { + DISPLAYLEVEL(1, "When using process substitution (<(...)), specify an output destination with -o or -c. \n"); + } } else { /* An increased buffer size can provide a significant performance * boost on some platforms. Note that providing a NULL buf with a From 0bdeb1d20451ae8dddffa19d9ff67917cf962a59 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 26 Mar 2025 21:33:26 -0700 Subject: [PATCH 078/245] fix test --- .../compress-file-to-dir-without-write-perm.sh.stderr.exact | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact b/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact index 95deaf2b1..515b63c60 100644 --- a/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact +++ b/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact @@ -23,4 +23,6 @@ Trace:FileStat: > UTIL_stat(-1, out/file.zst) Trace:FileStat: < 0 Trace:FileStat: < 0 zstd: out/file.zst: Permission denied +Trace:FileStat: > UTIL_isFileDescriptorPipe(out/file.zst) +Trace:FileStat: < 0 zstd: can't stat out/file.zst : Permission denied -- ignored From 2f9627863fb7ecd93b5f7f62b24ba9c7d7af1f77 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 28 Mar 2025 10:02:37 -0700 Subject: [PATCH 079/245] update error message --- programs/fileio.c | 5 +++-- .../compress-file-to-dir-without-write-perm.sh.stderr.exact | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 6c6faa485..dc7636949 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -659,9 +659,10 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, } #endif if (f == NULL) { - DISPLAYLEVEL(1, "zstd: %s: %s\n", dstFileName, strerror(errno)); if (UTIL_isFileDescriptorPipe(dstFileName)) { - DISPLAYLEVEL(1, "When using process substitution (<(...)), specify an output destination with -o or -c. \n"); + DISPLAYLEVEL(1, "zstd: error: no output specified (use -o or -c). \n"); + } else { + DISPLAYLEVEL(1, "zstd: %s: %s\n", dstFileName, strerror(errno)); } } else { /* An increased buffer size can provide a significant performance diff --git a/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact b/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact index 515b63c60..9f254f8c2 100644 --- a/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact +++ b/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact @@ -22,7 +22,7 @@ Trace:FileStat: > UTIL_isRegularFile(out/file.zst) Trace:FileStat: > UTIL_stat(-1, out/file.zst) Trace:FileStat: < 0 Trace:FileStat: < 0 -zstd: out/file.zst: Permission denied Trace:FileStat: > UTIL_isFileDescriptorPipe(out/file.zst) Trace:FileStat: < 0 +zstd: out/file.zst: Permission denied zstd: can't stat out/file.zst : Permission denied -- ignored From 3bd5aa34046ef02ed0e8e04aa5e464a5a10bb042 Mon Sep 17 00:00:00 2001 From: Li-Yu Yu Date: Fri, 28 Mar 2025 21:16:29 +0000 Subject: [PATCH 080/245] Check regular file for sparse support after opening A regular file may be created by the open call. Checking after opening allows sparseFileSupport even if dstFileName does not already exist. --- programs/fileio.c | 23 +++++++++++------------ programs/util.c | 10 ++++++++++ programs/util.h | 1 + 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index dc7636949..b1303a2ad 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -585,8 +585,6 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, const char* srcFileName, const char* dstFileName, const int mode) { - int isDstRegFile; - if (prefs->testMode) return NULL; /* do not open file in test mode */ assert(dstFileName != NULL); @@ -606,16 +604,7 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, return NULL; } - isDstRegFile = UTIL_isRegularFile(dstFileName); /* invoke once */ - if (prefs->sparseFileSupport == 1) { - prefs->sparseFileSupport = ZSTD_SPARSE_DEFAULT; - if (!isDstRegFile) { - prefs->sparseFileSupport = 0; - DISPLAYLEVEL(4, "Sparse File Support is disabled when output is not a file \n"); - } - } - - if (isDstRegFile) { + if (UTIL_isRegularFile(dstFileName)) { /* Check if destination file already exists */ #if !defined(_WIN32) /* this test does not work on Windows : @@ -658,6 +647,16 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, f = fdopen(fd, "wb"); } #endif + + if (prefs->sparseFileSupport == 1) { + prefs->sparseFileSupport = ZSTD_SPARSE_DEFAULT; + /* Check regular file after opening with O_CREAT */ + if (!UTIL_isFdRegularFile(fd)) { + prefs->sparseFileSupport = 0; + DISPLAYLEVEL(4, "Sparse File Support is disabled when output is not a file \n"); + } + } + if (f == NULL) { if (UTIL_isFileDescriptorPipe(dstFileName)) { DISPLAYLEVEL(1, "zstd: error: no output specified (use -o or -c). \n"); diff --git a/programs/util.c b/programs/util.c index 94c40cc95..850bcacd2 100644 --- a/programs/util.c +++ b/programs/util.c @@ -197,6 +197,16 @@ int UTIL_stat(const char* filename, stat_t* statbuf) return UTIL_fstat(-1, filename, statbuf); } +int UTIL_isFdRegularFile(int fd) +{ + stat_t statbuf; + int ret; + UTIL_TRACE_CALL("UTIL_isFdRegularFile(%d)", fd); + ret = UTIL_fstat(fd, "", &statbuf) && UTIL_isRegularFileStat(&statbuf); + UTIL_TRACE_RET(ret); + return ret; +} + int UTIL_isRegularFile(const char* infilename) { stat_t statbuf; diff --git a/programs/util.h b/programs/util.h index 427bcf441..65e12633a 100644 --- a/programs/util.h +++ b/programs/util.h @@ -184,6 +184,7 @@ int UTIL_fchmod(const int fd, char const* filename, const stat_t* statbuf, mode_ * compute the needed information. */ +int UTIL_isFdRegularFile(int fd); int UTIL_isRegularFile(const char* infilename); int UTIL_isDirectory(const char* infilename); int UTIL_isSameFile(const char* file1, const char* file2); From 2a12bbaf909136ea28f2206441a10b0837c60325 Mon Sep 17 00:00:00 2001 From: Li-Yu Yu Date: Fri, 28 Mar 2025 21:45:47 +0000 Subject: [PATCH 081/245] Update cli-tests/file-stat tests --- programs/fileio.c | 6 ++++-- programs/util.c | 2 +- .../compress-file-to-dir-without-write-perm.sh.stderr.exact | 2 ++ ...sh.stderr.exact => compress-file-to-file.sh.stderr.glob} | 4 ++++ ...h.stderr.exact => compress-stdin-to-file.sh.stderr.glob} | 4 ++++ ....stderr.exact => decompress-file-to-file.sh.stderr.glob} | 4 ++++ ...stderr.exact => decompress-stdin-to-file.sh.stderr.glob} | 4 ++++ 7 files changed, 23 insertions(+), 3 deletions(-) rename tests/cli-tests/file-stat/{compress-file-to-file.sh.stderr.exact => compress-file-to-file.sh.stderr.glob} (91%) rename tests/cli-tests/file-stat/{compress-stdin-to-file.sh.stderr.exact => compress-stdin-to-file.sh.stderr.glob} (86%) rename tests/cli-tests/file-stat/{decompress-file-to-file.sh.stderr.exact => decompress-file-to-file.sh.stderr.glob} (90%) rename tests/cli-tests/file-stat/{decompress-stdin-to-file.sh.stderr.exact => decompress-stdin-to-file.sh.stderr.glob} (84%) diff --git a/programs/fileio.c b/programs/fileio.c index b1303a2ad..77f3d35f9 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -630,6 +630,7 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, } { + int isDstRegFile; #if defined(_WIN32) /* Windows requires opening the file as a "binary" file to avoid * mangling. This macro doesn't exist on unix. */ @@ -648,10 +649,11 @@ FIO_openDstFile(FIO_ctx_t* fCtx, FIO_prefs_t* const prefs, } #endif + /* Check regular file after opening with O_CREAT */ + isDstRegFile = UTIL_isFdRegularFile(fd); if (prefs->sparseFileSupport == 1) { prefs->sparseFileSupport = ZSTD_SPARSE_DEFAULT; - /* Check regular file after opening with O_CREAT */ - if (!UTIL_isFdRegularFile(fd)) { + if (!isDstRegFile) { prefs->sparseFileSupport = 0; DISPLAYLEVEL(4, "Sparse File Support is disabled when output is not a file \n"); } diff --git a/programs/util.c b/programs/util.c index 850bcacd2..d11f13cfd 100644 --- a/programs/util.c +++ b/programs/util.c @@ -202,7 +202,7 @@ int UTIL_isFdRegularFile(int fd) stat_t statbuf; int ret; UTIL_TRACE_CALL("UTIL_isFdRegularFile(%d)", fd); - ret = UTIL_fstat(fd, "", &statbuf) && UTIL_isRegularFileStat(&statbuf); + ret = fd >= 0 && UTIL_fstat(fd, "", &statbuf) && UTIL_isRegularFileStat(&statbuf); UTIL_TRACE_RET(ret); return ret; } diff --git a/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact b/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact index 9f254f8c2..05d91ffc9 100644 --- a/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact +++ b/tests/cli-tests/file-stat/compress-file-to-dir-without-write-perm.sh.stderr.exact @@ -22,6 +22,8 @@ Trace:FileStat: > UTIL_isRegularFile(out/file.zst) Trace:FileStat: > UTIL_stat(-1, out/file.zst) Trace:FileStat: < 0 Trace:FileStat: < 0 +Trace:FileStat: > UTIL_isFdRegularFile(-1) +Trace:FileStat: < 0 Trace:FileStat: > UTIL_isFileDescriptorPipe(out/file.zst) Trace:FileStat: < 0 zstd: out/file.zst: Permission denied diff --git a/tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.exact b/tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.glob similarity index 91% rename from tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.exact rename to tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.glob index 32d248ee5..17a677deb 100644 --- a/tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.exact +++ b/tests/cli-tests/file-stat/compress-file-to-file.sh.stderr.glob @@ -22,6 +22,10 @@ Trace:FileStat: > UTIL_isRegularFile(file.zst) Trace:FileStat: > UTIL_stat(-1, file.zst) Trace:FileStat: < 0 Trace:FileStat: < 0 +Trace:FileStat: > UTIL_isFdRegularFile(*) +Trace:FileStat: > UTIL_stat(*, ) +Trace:FileStat: < 1 +Trace:FileStat: < 1 Trace:FileStat: > UTIL_isRegularFile(file.zst) Trace:FileStat: > UTIL_stat(-1, file.zst) Trace:FileStat: < 1 diff --git a/tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.exact b/tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.glob similarity index 86% rename from tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.exact rename to tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.glob index 9183c4674..38732cbe9 100644 --- a/tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.exact +++ b/tests/cli-tests/file-stat/compress-stdin-to-file.sh.stderr.glob @@ -14,6 +14,10 @@ Trace:FileStat: > UTIL_isRegularFile(file.zst) Trace:FileStat: > UTIL_stat(-1, file.zst) Trace:FileStat: < 0 Trace:FileStat: < 0 +Trace:FileStat: > UTIL_isFdRegularFile(*) +Trace:FileStat: > UTIL_stat(*, ) +Trace:FileStat: < 1 +Trace:FileStat: < 1 Trace:FileStat: > UTIL_isRegularFile(file.zst) Trace:FileStat: > UTIL_stat(-1, file.zst) Trace:FileStat: < 1 diff --git a/tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.exact b/tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.glob similarity index 90% rename from tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.exact rename to tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.glob index ad3a0deb8..ce194dfb3 100644 --- a/tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.exact +++ b/tests/cli-tests/file-stat/decompress-file-to-file.sh.stderr.glob @@ -22,6 +22,10 @@ Trace:FileStat: > UTIL_isRegularFile(file) Trace:FileStat: > UTIL_stat(-1, file) Trace:FileStat: < 0 Trace:FileStat: < 0 +Trace:FileStat: > UTIL_isFdRegularFile(*) +Trace:FileStat: > UTIL_stat(*, ) +Trace:FileStat: < 1 +Trace:FileStat: < 1 Trace:FileStat: > UTIL_isRegularFile(file) Trace:FileStat: > UTIL_stat(-1, file) Trace:FileStat: < 1 diff --git a/tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.exact b/tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.glob similarity index 84% rename from tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.exact rename to tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.glob index 716a7ac7b..9eb920883 100644 --- a/tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.exact +++ b/tests/cli-tests/file-stat/decompress-stdin-to-file.sh.stderr.glob @@ -14,6 +14,10 @@ Trace:FileStat: > UTIL_isRegularFile(file) Trace:FileStat: > UTIL_stat(-1, file) Trace:FileStat: < 0 Trace:FileStat: < 0 +Trace:FileStat: > UTIL_isFdRegularFile(*) +Trace:FileStat: > UTIL_stat(*, ) +Trace:FileStat: < 1 +Trace:FileStat: < 1 Trace:FileStat: > UTIL_isRegularFile(file) Trace:FileStat: > UTIL_stat(-1, file) Trace:FileStat: < 1 From 28ffb100aba333e2535021c5c0a672e68ea025bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 05:21:33 +0000 Subject: [PATCH 082/245] Bump actions/setup-java from 4.7.0 to 4.7.1 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4.7.0 to 4.7.1. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/3a4f6e1af504cf6a31855fa899c6aa5355ba6c12...c5195efecf7bdfc987ee8bae7a71cb8b11521c00) --- updated-dependencies: - dependency-name: actions/setup-java dependency-version: 4.7.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/android-ndk-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index 5746d86f7..7ba3958b8 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: Set up JDK 17 - uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 + uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: java-version: '17' distribution: 'temurin' From 8929d3b09f7391b4756dd5056fded3a6a90bc9a4 Mon Sep 17 00:00:00 2001 From: Etienne Cordonnier Date: Fri, 18 Apr 2025 14:37:50 +0200 Subject: [PATCH 083/245] Fix duplicate LC_RPATH error on MacOS After the update to MacOS 15.4, the dynamic loader dyld treats duplicated LC_RPATH as an error. The `FLAGS` variable already contains `LDFLAGS`, thus using both `FLAGS` and `LDFLAGS` duplicates all `LDFLAGS`, including `-Wl,rpath` parameters. The duplicate LC_RPATH causes this kind of errors: ``` dyld[29361]: Library not loaded: @loader_path/../lib/libzstd.1.dylib Referenced from: <7131C877-3CF0-33AC-AA05-257BA4FDD770> /Users/foobar/... Reason: tried: '/Users/foobar/..../lib/libzstd.1.dylib' (duplicate LC_RPATH '/usr/mypath.../lib') ``` Closes https://github.com/facebook/zstd/issues/4369 Signed-off-by: Etienne Cordonnier --- lib/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index a6a0eb09d..e9a50a8f7 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -166,7 +166,7 @@ $(ZSTD_DYNLIB): $(ZSTD_DYNLIB_OBJ) $(if $(filter -DZSTD_MULTITHREAD,$(CPPFLAGS)),\ @echo compiling multi-threaded dynamic library $(LIBVER),\ @echo compiling single-threaded dynamic library $(LIBVER)) - $(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@ + $(CC) $(FLAGS) $^ $(SONAME_FLAGS) -o $@ @echo creating versioned links ln -sf $@ libzstd.$(SHARED_EXT_MAJOR) ln -sf $@ libzstd.$(SHARED_EXT) @@ -255,7 +255,7 @@ libzstd-nomt: $(ZSTD_NOMT_FILES) echo "Error: Found zstdmt in list."; \ exit 1; \ fi - $(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@ + $(CC) $(FLAGS) $^ $(SONAME_FLAGS) -o $@ .PHONY: clean clean: From 7f907d5c232fe89c206af0a146794b755df8f1ae Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 29 Apr 2025 08:55:19 -0700 Subject: [PATCH 084/245] fix minor warning in zstreamtest --- tests/zstreamtest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 760d9f26c..88a20a3e2 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -1896,7 +1896,7 @@ static int basicUnitTests(U32 seed, double compressibility, int bigTests) CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, 1)); /* Write a bunch of 6 byte blocks */ while (remainingInput > 0) { - char testBuffer[6] = "\xAA\xAA\xAA\xAA\xAA\xAA"; + char testBuffer[6] = { 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 }; const size_t kSmallBlockSize = sizeof(testBuffer); ZSTD_inBuffer in = {testBuffer, kSmallBlockSize, 0}; From 2d224dc7457fb6a6267f801c59546b981d6552fb Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 28 Apr 2025 18:03:33 +0900 Subject: [PATCH 085/245] Add License variable to pkg-config file The pkg-config file has License variable that allows you to set the license for the software. This sets 'BSD-3-Clause OR GPL-2.0-only' to License. Ref: https://github.com/pkgconf/pkgconf/blob/master/man/pc.5#L116 Signed-off-by: Nobuhiro Iwamatsu --- lib/libzstd.pc.in | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libzstd.pc.in b/lib/libzstd.pc.in index d7b6c8582..2220a5797 100644 --- a/lib/libzstd.pc.in +++ b/lib/libzstd.pc.in @@ -14,3 +14,4 @@ Version: @VERSION@ Libs: -L${libdir} -lzstd @LIBS_MT@ Libs.private: @LIBS_PRIVATE@ Cflags: -I${includedir} @LIBS_MT@ +License: BSD-3-Clause OR GPL-2.0-only From 769723aee2540aaff8951ac432a1babed358aa71 Mon Sep 17 00:00:00 2001 From: Thomas Devoogdt Date: Tue, 1 Apr 2025 22:47:45 +0200 Subject: [PATCH 086/245] [cmake] only require a CXX compiler when tests are build Signed-off-by: Thomas Devoogdt --- build/cmake/CMakeLists.txt | 20 +++++++---- .../AddZstdCompilationFlags.cmake | 34 +++++++++---------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/build/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt index 347d41c0f..f08905345 100644 --- a/build/cmake/CMakeLists.txt +++ b/build/cmake/CMakeLists.txt @@ -37,7 +37,6 @@ project(zstd VERSION "${ZSTD_FULL_VERSION}" LANGUAGES C # Main library is in C ASM # And ASM - CXX # Testing contributed code also utilizes CXX ) message(STATUS "ZSTD VERSION: ${zstd_VERSION}") @@ -54,12 +53,6 @@ endif() include(GNUInstallDirs) -#----------------------------------------------------------------------------- -# Add extra compilation flags -#----------------------------------------------------------------------------- -include(AddZstdCompilationFlags) -ADD_ZSTD_COMPILATION_FLAGS() - # Always hide XXHash symbols add_definitions(-DXXH_NAMESPACE=ZSTD_) @@ -123,6 +116,19 @@ if (MSVC) option(ZSTD_USE_STATIC_RUNTIME "LINK TO STATIC RUN-TIME LIBRARIES" OFF) endif () +# Enable C++ support for testing. +set(ZSTD_ENABLE_CXX ${ZSTD_BUILD_TESTS}) + +if(ZSTD_ENABLE_CXX) + enable_language(CXX) +endif() + +#----------------------------------------------------------------------------- +# Add extra compilation flags +#----------------------------------------------------------------------------- +include(AddZstdCompilationFlags) +ADD_ZSTD_COMPILATION_FLAGS(ON ZSTD_ENABLE_CXX ON) # C CXX LD + #----------------------------------------------------------------------------- # External dependencies #----------------------------------------------------------------------------- diff --git a/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake b/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake index 5f381c656..25231b5ec 100644 --- a/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake +++ b/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake @@ -49,7 +49,7 @@ function(EnableCompilerFlag _flag _C _CXX _LD) endif () endfunction() -macro(ADD_ZSTD_COMPILATION_FLAGS) +macro(ADD_ZSTD_COMPILATION_FLAGS _C _CXX _LD) # We set ZSTD_HAS_NOEXECSTACK if we are certain we've set all the required # compiler flags to mark the stack as non-executable. set(ZSTD_HAS_NOEXECSTACK false) @@ -63,26 +63,26 @@ macro(ADD_ZSTD_COMPILATION_FLAGS) # EnableCompilerFlag("-std=c99" true false) # Set C compilation to c99 standard if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC) # clang-cl normally maps -Wall to -Weverything. - EnableCompilerFlag("/clang:-Wall" true true false) + EnableCompilerFlag("/clang:-Wall" _C _CXX false) else () - EnableCompilerFlag("-Wall" true true false) + EnableCompilerFlag("-Wall" _C _CXX false) endif () - EnableCompilerFlag("-Wextra" true true false) - EnableCompilerFlag("-Wundef" true true false) - EnableCompilerFlag("-Wshadow" true true false) - EnableCompilerFlag("-Wcast-align" true true false) - EnableCompilerFlag("-Wcast-qual" true true false) - EnableCompilerFlag("-Wstrict-prototypes" true false false) + EnableCompilerFlag("-Wextra" _C _CXX false) + EnableCompilerFlag("-Wundef" _C _CXX false) + EnableCompilerFlag("-Wshadow" _C _CXX false) + EnableCompilerFlag("-Wcast-align" _C _CXX false) + EnableCompilerFlag("-Wcast-qual" _C _CXX false) + EnableCompilerFlag("-Wstrict-prototypes" _C false false) # Enable asserts in Debug mode if (CMAKE_BUILD_TYPE MATCHES "Debug") - EnableCompilerFlag("-DDEBUGLEVEL=1" true true false) + EnableCompilerFlag("-DDEBUGLEVEL=1" _C _CXX false) endif () # Add noexecstack flags # LDFLAGS - EnableCompilerFlag("-Wl,-z,noexecstack" false false true) + EnableCompilerFlag("-Wl,-z,noexecstack" false false _LD) # CFLAGS & CXXFLAGS - EnableCompilerFlag("-Qunused-arguments" true true false) - EnableCompilerFlag("-Wa,--noexecstack" true true false) + EnableCompilerFlag("-Qunused-arguments" _C _CXX false) + EnableCompilerFlag("-Wa,--noexecstack" _C _CXX false) # NOTE: Using 3 nested ifs because the variables are sometimes # empty if the condition is false, and sometimes equal to false. # This implicitly converts them to truthy values. There may be @@ -99,15 +99,15 @@ macro(ADD_ZSTD_COMPILATION_FLAGS) set(ACTIVATE_MULTITHREADED_COMPILATION "ON" CACHE BOOL "activate multi-threaded compilation (/MP flag)") if (CMAKE_GENERATOR MATCHES "Visual Studio" AND ACTIVATE_MULTITHREADED_COMPILATION) - EnableCompilerFlag("/MP" true true false) + EnableCompilerFlag("/MP" _C _CXX false) endif () # UNICODE SUPPORT - EnableCompilerFlag("/D_UNICODE" true true false) - EnableCompilerFlag("/DUNICODE" true true false) + EnableCompilerFlag("/D_UNICODE" _C _CXX false) + EnableCompilerFlag("/DUNICODE" _C _CXX false) # Enable asserts in Debug mode if (CMAKE_BUILD_TYPE MATCHES "Debug") - EnableCompilerFlag("/DDEBUGLEVEL=1" true true false) + EnableCompilerFlag("/DDEBUGLEVEL=1" _C _CXX false) endif () endif () From 6b0039abcf5fb9ef1f942ded9cc86ec10e062c1e Mon Sep 17 00:00:00 2001 From: Dave Vasilevsky Date: Tue, 6 May 2025 21:55:22 -0400 Subject: [PATCH 087/245] seekable_format: Build with $(MAKE) This passes make flags, such as `-jN` for building in parallel, to the underlying make. --- contrib/seekable_format/examples/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/seekable_format/examples/Makefile b/contrib/seekable_format/examples/Makefile index fcc04587c..336d8c722 100644 --- a/contrib/seekable_format/examples/Makefile +++ b/contrib/seekable_format/examples/Makefile @@ -28,7 +28,7 @@ all: seekable_compression seekable_decompression seekable_decompression_mem \ parallel_processing $(ZSTDLIB): - make -C $(ZSTDLIB_PATH) $(ZSTDLIB_NAME) + $(MAKE) -C $(ZSTDLIB_PATH) $(ZSTDLIB_NAME) seekable_compression : seekable_compression.c $(SEEKABLE_OBJS) $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ From f5b6531902a8e12b679b10ea748aa55ac0d40d66 Mon Sep 17 00:00:00 2001 From: Dave Vasilevsky Date: Tue, 6 May 2025 21:57:29 -0400 Subject: [PATCH 088/245] seekable_format: Link against multi-threaded libzstd.a Some of these examples are intended to be parallel, and don't make sense to link against single-threaded libzstd. The filename of mt and nomt libzstd are identical, so it's still possible to link against the single-threaded one, just harder. --- contrib/seekable_format/examples/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/seekable_format/examples/Makefile b/contrib/seekable_format/examples/Makefile index 336d8c722..f15a4a15a 100644 --- a/contrib/seekable_format/examples/Makefile +++ b/contrib/seekable_format/examples/Makefile @@ -11,6 +11,8 @@ ZSTDLIB_PATH = ../../../lib ZSTDLIB_NAME = libzstd.a +# Parallel tools only make sense against multi-threaded libzstd +ZSTDLIB_TARGET = $(ZSTDLIB_NAME)-mt ZSTDLIB = $(ZSTDLIB_PATH)/$(ZSTDLIB_NAME) CPPFLAGS += -DXXH_NAMESPACE=ZSTD_ -I../ -I../../../lib -I../../../lib/common @@ -28,7 +30,7 @@ all: seekable_compression seekable_decompression seekable_decompression_mem \ parallel_processing $(ZSTDLIB): - $(MAKE) -C $(ZSTDLIB_PATH) $(ZSTDLIB_NAME) + $(MAKE) -C $(ZSTDLIB_PATH) $(ZSTDLIB_TARGET) seekable_compression : seekable_compression.c $(SEEKABLE_OBJS) $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ From 2d4cff69c439d40b2bb39300f003522da8f2c6ab Mon Sep 17 00:00:00 2001 From: Dave Vasilevsky Date: Tue, 6 May 2025 23:26:32 -0400 Subject: [PATCH 089/245] seekable_format: Make parallel_compression use memory properly Previously, parallel_compression would only handle each job's results after ALL jobs were successfully queued. This caused all src/dst buffers to remain in memory until then! It also polled to check whether a job completed, which is racy without any memory barrier. Now, we flush results as a side effect of completing a job. Completed frames are placed in an ordered linked-list, and any eligible frames are flushed. This may be zero or multiple frames, depending on the order in which jobs finish. This design also makes it simple to support streaming input, so that is now available. Just pass `-` as the filename, and stdin/stdout will be used for I/O. --- .../examples/parallel_compression.c | 215 +++++++++++------- 1 file changed, 127 insertions(+), 88 deletions(-) diff --git a/contrib/seekable_format/examples/parallel_compression.c b/contrib/seekable_format/examples/parallel_compression.c index 4e06fae32..d54704c11 100644 --- a/contrib/seekable_format/examples/parallel_compression.c +++ b/contrib/seekable_format/examples/parallel_compression.c @@ -23,6 +23,8 @@ #include "xxhash.h" +#define ZSTD_MULTITHREAD 1 +#include "threading.h" #include "pool.h" // use zstd thread pool for demo #include "../zstd_seekable.h" @@ -72,114 +74,87 @@ static size_t fclose_orDie(FILE* file) exit(6); } -static void fseek_orDie(FILE* file, long int offset, int origin) -{ - if (!fseek(file, offset, origin)) { - if (!fflush(file)) return; - } - /* error */ - perror("fseek"); - exit(7); -} - -static long int ftell_orDie(FILE* file) -{ - long int off = ftell(file); - if (off != -1) return off; - /* error */ - perror("ftell"); - exit(8); -} +struct state { + FILE* fout; + ZSTD_pthread_mutex_t mutex; + size_t nextID; + struct job* pending; + ZSTD_frameLog* frameLog; + const int compressionLevel; +}; struct job { - const void* src; + size_t id; + struct job* next; + struct state* state; + + void* src; size_t srcSize; void* dst; size_t dstSize; unsigned checksum; - - int compressionLevel; - int done; }; +static void addPending_inmutex(struct state* state, struct job* job) +{ + struct job** p = &state->pending; + while (*p && (*p)->id < job->id) + p = &(*p)->next; + job->next = *p; + *p = job; +} + +static void flushFrame(struct state* state, struct job* job) +{ + fwrite_orDie(job->dst, job->dstSize, state->fout); + free(job->dst); + + size_t ret = ZSTD_seekable_logFrame(state->frameLog, job->dstSize, job->srcSize, job->checksum); + if (ZSTD_isError(ret)) { + fprintf(stderr, "ZSTD_seekable_logFrame() error : %s \n", ZSTD_getErrorName(ret)); + exit(12); + } +} + +static void flushPending_inmutex(struct state* state) +{ + while (state->pending && state->pending->id == state->nextID) { + struct job* p = state->pending; + state->pending = p->next; + flushFrame(state, p); + free(p); + state->nextID++; + } +} + +static void finishFrame(struct job* job) +{ + struct state *state = job->state; + ZSTD_pthread_mutex_lock(&state->mutex); + addPending_inmutex(state, job); + flushPending_inmutex(state); + ZSTD_pthread_mutex_unlock(&state->mutex); +} + static void compressFrame(void* opaque) { struct job* job = opaque; job->checksum = XXH64(job->src, job->srcSize, 0); - size_t ret = ZSTD_compress(job->dst, job->dstSize, job->src, job->srcSize, job->compressionLevel); + size_t ret = ZSTD_compress(job->dst, job->dstSize, job->src, job->srcSize, job->state->compressionLevel); if (ZSTD_isError(ret)) { fprintf(stderr, "ZSTD_compress() error : %s \n", ZSTD_getErrorName(ret)); exit(20); } - job->dstSize = ret; - job->done = 1; -} -static void compressFile_orDie(const char* fname, const char* outName, int cLevel, unsigned frameSize, int nbThreads) -{ - POOL_ctx* pool = POOL_create(nbThreads, nbThreads); - if (pool == NULL) { fprintf(stderr, "POOL_create() error \n"); exit(9); } + // No longer need + free(job->src); + job->src = NULL; - FILE* const fin = fopen_orDie(fname, "rb"); - FILE* const fout = fopen_orDie(outName, "wb"); - - if (ZSTD_compressBound(frameSize) > 0xFFFFFFFFU) { fprintf(stderr, "Frame size too large \n"); exit(10); } - unsigned dstSize = ZSTD_compressBound(frameSize); - - - fseek_orDie(fin, 0, SEEK_END); - long int length = ftell_orDie(fin); - fseek_orDie(fin, 0, SEEK_SET); - - size_t numFrames = (length + frameSize - 1) / frameSize; - - struct job* jobs = malloc_orDie(sizeof(struct job) * numFrames); - - size_t i; - for(i = 0; i < numFrames; i++) { - void* in = malloc_orDie(frameSize); - void* out = malloc_orDie(dstSize); - - size_t inSize = fread_orDie(in, frameSize, fin); - - jobs[i].src = in; - jobs[i].srcSize = inSize; - jobs[i].dst = out; - jobs[i].dstSize = dstSize; - jobs[i].compressionLevel = cLevel; - jobs[i].done = 0; - POOL_add(pool, compressFrame, &jobs[i]); - } - - ZSTD_frameLog* fl = ZSTD_seekable_createFrameLog(1); - if (fl == NULL) { fprintf(stderr, "ZSTD_seekable_createFrameLog() failed \n"); exit(11); } - for (i = 0; i < numFrames; i++) { - while (!jobs[i].done) SLEEP(5); /* wake up every 5 milliseconds to check */ - fwrite_orDie(jobs[i].dst, jobs[i].dstSize, fout); - free((void*)jobs[i].src); - free(jobs[i].dst); - - size_t ret = ZSTD_seekable_logFrame(fl, jobs[i].dstSize, jobs[i].srcSize, jobs[i].checksum); - if (ZSTD_isError(ret)) { fprintf(stderr, "ZSTD_seekable_logFrame() error : %s \n", ZSTD_getErrorName(ret)); } - } - - { unsigned char seekTableBuff[1024]; - ZSTD_outBuffer out = {seekTableBuff, 1024, 0}; - while (ZSTD_seekable_writeSeekTable(fl, &out) != 0) { - fwrite_orDie(seekTableBuff, out.pos, fout); - out.pos = 0; - } - fwrite_orDie(seekTableBuff, out.pos, fout); - } - - ZSTD_seekable_freeFrameLog(fl); - free(jobs); - fclose_orDie(fout); - fclose_orDie(fin); + finishFrame(job); } static const char* createOutFilename_orDie(const char* filename) @@ -193,6 +168,71 @@ static const char* createOutFilename_orDie(const char* filename) return (const char*)outSpace; } +static void openInOut_orDie(const char* fname, FILE** fin, FILE** fout) { + if (strcmp(fname, "-") == 0) { + *fin = stdin; + *fout = stdout; + } else { + *fin = fopen_orDie(fname, "rb"); + const char* outName = createOutFilename_orDie(fname); + *fout = fopen_orDie(outName, "wb"); + } +} + +static void compressFile_orDie(const char* fname, int cLevel, unsigned frameSize, int nbThreads) +{ + struct state state = { + .nextID = 0, + .pending = NULL, + .compressionLevel = cLevel, + }; + ZSTD_pthread_mutex_init(&state.mutex, NULL); + state.frameLog = ZSTD_seekable_createFrameLog(1); + if (state.frameLog == NULL) { fprintf(stderr, "ZSTD_seekable_createFrameLog() failed \n"); exit(11); } + + POOL_ctx* pool = POOL_create(nbThreads, nbThreads); + if (pool == NULL) { fprintf(stderr, "POOL_create() error \n"); exit(9); } + + FILE* fin; + openInOut_orDie(fname, &fin, &state.fout); + + if (ZSTD_compressBound(frameSize) > 0xFFFFFFFFU) { fprintf(stderr, "Frame size too large \n"); exit(10); } + unsigned dstSize = ZSTD_compressBound(frameSize); + + for (size_t id = 0; 1; id++) { + struct job* job = malloc_orDie(sizeof(struct job)); + job->id = id; + job->next = NULL; + job->state = &state; + job->src = malloc_orDie(frameSize); + job->dst = malloc_orDie(dstSize); + job->srcSize = fread_orDie(job->src, frameSize, fin); + job->dstSize = dstSize; + POOL_add(pool, compressFrame, job); + if (feof(fin)) + break; + } + + POOL_joinJobs(pool); + if (state.pending) { + fprintf(stderr, "Unexpected leftover output blocks!\n"); + exit(13); + } + + { unsigned char seekTableBuff[1024]; + ZSTD_outBuffer out = {seekTableBuff, 1024, 0}; + while (ZSTD_seekable_writeSeekTable(state.frameLog, &out) != 0) { + fwrite_orDie(seekTableBuff, out.pos, state.fout); + out.pos = 0; + } + fwrite_orDie(seekTableBuff, out.pos, state.fout); + } + + ZSTD_seekable_freeFrameLog(state.frameLog); + fclose_orDie(state.fout); + fclose_orDie(fin); +} + int main(int argc, const char** argv) { const char* const exeName = argv[0]; if (argc!=4) { @@ -206,8 +246,7 @@ int main(int argc, const char** argv) { unsigned const frameSize = (unsigned)atoi(argv[2]); int const nbThreads = atoi(argv[3]); - const char* const outFileName = createOutFilename_orDie(inFileName); - compressFile_orDie(inFileName, outFileName, 5, frameSize, nbThreads); + compressFile_orDie(inFileName, 5, frameSize, nbThreads); } return 0; From 6fc8455a727f5e21c1ccd5402731b390e2a9076d Mon Sep 17 00:00:00 2001 From: Dave Vasilevsky Date: Tue, 6 May 2025 23:45:04 -0400 Subject: [PATCH 090/245] seekable_format: Cleanup POOL in parallel_compression --- contrib/seekable_format/examples/parallel_compression.c | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/seekable_format/examples/parallel_compression.c b/contrib/seekable_format/examples/parallel_compression.c index d54704c11..a9f51bdbe 100644 --- a/contrib/seekable_format/examples/parallel_compression.c +++ b/contrib/seekable_format/examples/parallel_compression.c @@ -214,6 +214,7 @@ static void compressFile_orDie(const char* fname, int cLevel, unsigned frameSize } POOL_joinJobs(pool); + POOL_free(pool); if (state.pending) { fprintf(stderr, "Unexpected leftover output blocks!\n"); exit(13); From 01c973de8d85392156f4fa1400e0b3c52b50b23e Mon Sep 17 00:00:00 2001 From: Dave Vasilevsky Date: Wed, 7 May 2025 00:10:10 -0400 Subject: [PATCH 091/245] seekable_format: Fix race in parallel_processing There was no memory barrier between writing and reading `done`, which would allow reordering to cause races. With so little data to handle after each job completes, we might as well just join. --- contrib/seekable_format/examples/parallel_processing.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/contrib/seekable_format/examples/parallel_processing.c b/contrib/seekable_format/examples/parallel_processing.c index 928371025..2757a9aba 100644 --- a/contrib/seekable_format/examples/parallel_processing.c +++ b/contrib/seekable_format/examples/parallel_processing.c @@ -100,13 +100,11 @@ struct sum_job { const char* fname; unsigned long long sum; unsigned frameNb; - int done; }; static void sumFrame(void* opaque) { struct sum_job* job = (struct sum_job*)opaque; - job->done = 0; FILE* const fin = fopen_orDie(job->fname, "rb"); @@ -128,7 +126,6 @@ static void sumFrame(void* opaque) sum += data[i]; } job->sum = sum; - job->done = 1; fclose(fin); ZSTD_seekable_free(seekable); @@ -153,14 +150,14 @@ static void sumFile_orDie(const char* fname, int nbThreads) unsigned fnb; for (fnb = 0; fnb < numFrames; fnb++) { - jobs[fnb] = (struct sum_job){ fname, 0, fnb, 0 }; + jobs[fnb] = (struct sum_job){ fname, 0, fnb }; POOL_add(pool, sumFrame, &jobs[fnb]); } + POOL_joinJobs(pool); unsigned long long total = 0; for (fnb = 0; fnb < numFrames; fnb++) { - while (!jobs[fnb].done) SLEEP(5); /* wake up every 5 milliseconds to check */ total += jobs[fnb].sum; } From 13cb7a10ae556c24896ee2f305624d084234042a Mon Sep 17 00:00:00 2001 From: Dave Vasilevsky Date: Wed, 7 May 2025 01:43:36 -0400 Subject: [PATCH 092/245] seekable_format: Add test for parallel_compression memory usage Use ulimit to fail the test if we use O(filesize) memory, rather than O(threads). --- contrib/seekable_format/tests/.gitignore | 1 + contrib/seekable_format/tests/Makefile | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/contrib/seekable_format/tests/.gitignore b/contrib/seekable_format/tests/.gitignore index f831eaf37..b59d08b34 100644 --- a/contrib/seekable_format/tests/.gitignore +++ b/contrib/seekable_format/tests/.gitignore @@ -1 +1,2 @@ seekable_tests +data.txt diff --git a/contrib/seekable_format/tests/Makefile b/contrib/seekable_format/tests/Makefile index a81f2229f..a23c0f43c 100644 --- a/contrib/seekable_format/tests/Makefile +++ b/contrib/seekable_format/tests/Makefile @@ -24,7 +24,7 @@ SEEKABLE_OBJS = ../zstdseek_compress.c ../zstdseek_decompress.c $(ZSTDLIB) .PHONY: default clean test default: test -test: seekable_tests +test: seekable_tests parallel_compression_test ./seekable_tests $(ZSTDLIB): @@ -32,7 +32,27 @@ $(ZSTDLIB): seekable_tests : $(SEEKABLE_OBJS) +EXAMPLES_PATH = ../examples +PARALLEL_COMPRESSION = $(EXAMPLES_PATH)/parallel_compression + +DATAGEN_PATH = ../../../tests +DATAGEN = $(DATAGEN_PATH)/datagen + +$(PARALLEL_COMPRESSION): + $(MAKE) -C $(EXAMPLES_PATH) parallel_compression + +$(DATAGEN): + $(MAKE) -C $(DATAGEN_PATH) datagen + +data.txt: $(DATAGEN) + $(DATAGEN) -g100M > $@ + +parallel_compression_test: $(PARALLEL_COMPRESSION) data.txt + ulimit -Sv 102400; $(PARALLEL_COMPRESSION) data.txt 1048576 2 + +.PHONY: parallel_compression_test parallel_comp + clean: @$(RM) core *.o tmp* result* *.zst \ - seekable_tests + seekable_tests data.txt @echo Cleaning completed From 448a09ff78c2a28ad666539357d6687c759f2bb6 Mon Sep 17 00:00:00 2001 From: Dave Vasilevsky Date: Wed, 7 May 2025 02:12:29 -0400 Subject: [PATCH 093/245] seekable_format: Fix conversion warnings in parallel_compression --- .../seekable_format/examples/parallel_compression.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/seekable_format/examples/parallel_compression.c b/contrib/seekable_format/examples/parallel_compression.c index a9f51bdbe..f8a73a36b 100644 --- a/contrib/seekable_format/examples/parallel_compression.c +++ b/contrib/seekable_format/examples/parallel_compression.c @@ -110,7 +110,7 @@ static void flushFrame(struct state* state, struct job* job) fwrite_orDie(job->dst, job->dstSize, state->fout); free(job->dst); - size_t ret = ZSTD_seekable_logFrame(state->frameLog, job->dstSize, job->srcSize, job->checksum); + size_t ret = ZSTD_seekable_logFrame(state->frameLog, (unsigned)job->dstSize, (unsigned)job->srcSize, job->checksum); if (ZSTD_isError(ret)) { fprintf(stderr, "ZSTD_seekable_logFrame() error : %s \n", ZSTD_getErrorName(ret)); exit(12); @@ -141,7 +141,7 @@ static void compressFrame(void* opaque) { struct job* job = opaque; - job->checksum = XXH64(job->src, job->srcSize, 0); + job->checksum = (unsigned)XXH64(job->src, job->srcSize, 0); size_t ret = ZSTD_compress(job->dst, job->dstSize, job->src, job->srcSize, job->state->compressionLevel); if (ZSTD_isError(ret)) { @@ -179,7 +179,7 @@ static void openInOut_orDie(const char* fname, FILE** fin, FILE** fout) { } } -static void compressFile_orDie(const char* fname, int cLevel, unsigned frameSize, int nbThreads) +static void compressFile_orDie(const char* fname, int cLevel, unsigned frameSize, size_t nbThreads) { struct state state = { .nextID = 0, @@ -197,7 +197,7 @@ static void compressFile_orDie(const char* fname, int cLevel, unsigned frameSize openInOut_orDie(fname, &fin, &state.fout); if (ZSTD_compressBound(frameSize) > 0xFFFFFFFFU) { fprintf(stderr, "Frame size too large \n"); exit(10); } - unsigned dstSize = ZSTD_compressBound(frameSize); + size_t dstSize = ZSTD_compressBound(frameSize); for (size_t id = 0; 1; id++) { struct job* job = malloc_orDie(sizeof(struct job)); @@ -245,7 +245,7 @@ int main(int argc, const char** argv) { { const char* const inFileName = argv[1]; unsigned const frameSize = (unsigned)atoi(argv[2]); - int const nbThreads = atoi(argv[3]); + size_t const nbThreads = (size_t)atoi(argv[3]); compressFile_orDie(inFileName, 5, frameSize, nbThreads); } From f9938c217da17ec3e9dcd2a2d99c5cf39536aeb9 Mon Sep 17 00:00:00 2001 From: Dave Vasilevsky Date: Wed, 7 May 2025 03:03:29 -0400 Subject: [PATCH 094/245] lz4: Remove ancient test helpers Building lz4 as root was causing `make clean` to fail with permission errors. We used to have to install lz4 from source back in Ubuntu 14.04, but nowadays the installed lz4 is fine. Get rid of ancient helpers and cruft! --- .github/workflows/dev-short-tests.yml | 1 - Makefile | 6 +----- tests/Makefile | 6 +++--- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index da35ec675..227b01a0c 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -170,7 +170,6 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: LZ4, thread pool, and libs build testslib wrapper test run: | - make lz4install make -C tests test-lz4 make check < /dev/null | tee # mess with lz4 console detection make clean diff --git a/Makefile b/Makefile index e8e6bcffe..c9a640cba 100644 --- a/Makefile +++ b/Makefile @@ -351,7 +351,7 @@ apt-add-repo: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update -y -qq -.PHONY: ppcinstall arminstall valgrindinstall libc6install gcc6install gcc7install gcc8install gpp6install clang38install lz4install +.PHONY: ppcinstall arminstall valgrindinstall libc6install gcc6install gcc7install gcc8install gpp6install clang38install ppcinstall: APT_PACKAGES="qemu-system-ppc qemu-user-static gcc-powerpc-linux-gnu" $(MAKE) apt-install @@ -379,10 +379,6 @@ gpp6install: apt-add-repo clang38install: APT_PACKAGES="clang-3.8" $(MAKE) apt-install -# Ubuntu 14.04 ships a too-old lz4 -lz4install: - [ -e lz4 ] || git clone https://github.com/lz4/lz4 && sudo $(MAKE) -C lz4 install - endif diff --git a/tests/Makefile b/tests/Makefile index b96986cae..643f8cd61 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -447,9 +447,9 @@ test-decodecorpus-cli: decodecorpus test-pool: poolTests $(QEMU_SYS) ./poolTests -test-lz4: ZSTD = LD_LIBRARY_PATH=/usr/local/lib $(PRGDIR)/zstd -test-lz4: ZSTD_LZ4 = LD_LIBRARY_PATH=/usr/local/lib ./lz4 -test-lz4: ZSTD_UNLZ4 = LD_LIBRARY_PATH=/usr/local/lib ./unlz4 +test-lz4: ZSTD = $(PRGDIR)/zstd +test-lz4: ZSTD_LZ4 = ./lz4 +test-lz4: ZSTD_UNLZ4 = ./unlz4 test-lz4: zstd decodecorpus datagen [ -f lz4 ] || ln -s $(PRGDIR)/zstd lz4 [ -f unlz4 ] || ln -s $(PRGDIR)/zstd unlz4 From 4618b255eae0a2a7e36cbdb50276d734f039bd52 Mon Sep 17 00:00:00 2001 From: jinyaoguo Date: Sun, 25 May 2025 15:21:23 -0400 Subject: [PATCH 095/245] Fix memory leak in function benchMem `speedPerRound` is allocated at the start of benchMem to collect per-round speeds, but is never freed, causing a leak on each invocation. --- contrib/largeNbDicts/largeNbDicts.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/largeNbDicts/largeNbDicts.c b/contrib/largeNbDicts/largeNbDicts.c index 6502f1227..6b6cc34ca 100644 --- a/contrib/largeNbDicts/largeNbDicts.c +++ b/contrib/largeNbDicts/largeNbDicts.c @@ -739,6 +739,8 @@ static int benchMem(slice_collection_t dstBlocks, slice_collection_t srcBlocks, /* BMK_benchTimedFn may not run exactly nbRounds iterations */ double speedAggregated = aggregateData(speedPerRound, roundNb + 1, metricAggregatePref); + free(speedPerRound); + if (metricAggregatePref == fastest) DISPLAY("Fastest Speed : %.1f MB/s \n", speedAggregated); else From 4bd5654e72e8b0f03218d7d56f8b5329ba6445b3 Mon Sep 17 00:00:00 2001 From: shixuantong Date: Fri, 9 May 2025 22:47:08 +0800 Subject: [PATCH 096/245] update `--rm` cmd help info Starting from cee6bec9fa6aa249f2df9f84165b682eb793eab, --rm is ignored when the output is `stdout`. --- programs/README.md | 2 +- programs/zstdcli.c | 2 +- tests/cli-tests/basic/help.sh.stdout.glob | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/README.md b/programs/README.md index 43ef07a45..2c2e94dc6 100644 --- a/programs/README.md +++ b/programs/README.md @@ -153,7 +153,7 @@ Usage: zstd [OPTIONS...] [INPUT... | -] [-o OUTPUT] Options: -o OUTPUT Write output to a single file, OUTPUT. -k, --keep Preserve INPUT file(s). [Default] - --rm Remove INPUT file(s) after successful (de)compression. + --rm Remove INPUT file(s) after successful (de)compression to file. -# Desired compression level, where `#` is a number between 1 and 19; lower numbers provide faster compression, higher numbers yield diff --git a/programs/zstdcli.c b/programs/zstdcli.c index fa7ea37b3..124ea47aa 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -147,7 +147,7 @@ static void usage(FILE* f, const char* programName) DISPLAY_F(f, "Options:\n"); DISPLAY_F(f, " -o OUTPUT Write output to a single file, OUTPUT.\n"); DISPLAY_F(f, " -k, --keep Preserve INPUT file(s). [Default] \n"); - DISPLAY_F(f, " --rm Remove INPUT file(s) after successful (de)compression.\n"); + DISPLAY_F(f, " --rm Remove INPUT file(s) after successful (de)compression to file.\n"); #ifdef ZSTD_GZCOMPRESS if (exeNameMatch(programName, ZSTD_GZ)) { /* behave like gzip */ DISPLAY_F(f, " -n, --no-name Do not store original filename when compressing.\n\n"); diff --git a/tests/cli-tests/basic/help.sh.stdout.glob b/tests/cli-tests/basic/help.sh.stdout.glob index 21bc28c3f..66c6906cf 100644 --- a/tests/cli-tests/basic/help.sh.stdout.glob +++ b/tests/cli-tests/basic/help.sh.stdout.glob @@ -6,7 +6,7 @@ Usage: zstd *OPTIONS...* *INPUT... | -* *-o OUTPUT* Options: -o OUTPUT Write output to a single file, OUTPUT. -k, --keep Preserve INPUT file(s). *Default* - --rm Remove INPUT file(s) after successful (de)compression. + --rm Remove INPUT file(s) after successful (de)compression to file. -# Desired compression level, where `#` is a number between 1 and 19; lower numbers provide faster compression, higher numbers yield From d95123f2e68fc5a0feb222d03cacba5a044f03b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=AD=90=E5=BB=BA?= Date: Fri, 16 May 2025 14:57:32 +0800 Subject: [PATCH 097/245] Improve speed of ZSTD_compressSequencesAndLiterals() using RVV --- lib/common/compiler.h | 6 ++ lib/compress/zstd_compress.c | 151 +++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/lib/common/compiler.h b/lib/common/compiler.h index 944774a7a..cafb35b71 100644 --- a/lib/common/compiler.h +++ b/lib/common/compiler.h @@ -218,6 +218,9 @@ # if defined(__ARM_NEON) || defined(_M_ARM64) # define ZSTD_ARCH_ARM_NEON # endif +# if defined(__riscv) && defined(__riscv_vector) +# define ZSTD_ARCH_RISCV_RVV +# endif # # if defined(ZSTD_ARCH_X86_AVX2) # include @@ -227,6 +230,9 @@ # elif defined(ZSTD_ARCH_ARM_NEON) # include # endif +# if defined(ZSTD_ARCH_RISCV_RVV) +# include +# endif #endif /* C-language Attributes are added in C23. */ diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index c8f6b2865..9b7aaf9f4 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -7284,6 +7284,93 @@ static size_t convertSequences_noRepcodes( return longLen; } +#elif defined ZSTD_ARCH_RISCV_RVV +#include +/* + * Convert `vl` sequences per iteration, using AVX2 intrinsics: + * - offset -> offBase = offset + 2 + * - litLength -> (U16) litLength + * - matchLength -> (U16)(matchLength - 3) + * - rep is ignored + * Store only 8 bytes per SeqDef (offBase[4], litLength[2], mlBase[2]). + * + * @returns 0 on succes, with no long length detected + * @returns > 0 if there is one long length (> 65535), + * indicating the position, and type. + */ +static size_t convertSequences_noRepcodes(SeqDef* dstSeqs, const ZSTD_Sequence* inSeqs, size_t nbSequences) { + size_t longLen = 0; + + /* RVV depends on the specific definition of target structures */ + ZSTD_STATIC_ASSERT(sizeof(ZSTD_Sequence) == 16); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, offset) == 0); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, litLength) == 4); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, matchLength) == 8); + ZSTD_STATIC_ASSERT(sizeof(SeqDef) == 8); + ZSTD_STATIC_ASSERT(offsetof(SeqDef, offBase) == 0); + ZSTD_STATIC_ASSERT(offsetof(SeqDef, litLength) == 4); + ZSTD_STATIC_ASSERT(offsetof(SeqDef, mlBase) == 6); + size_t vl = 0; + for (size_t i = 0; i < nbSequences; i += vl) { + + vl = __riscv_vsetvl_e32m2(nbSequences-i); + // Loading structure member variables + vuint32m2x4_t v_tuple = __riscv_vlseg4e32_v_u32m2x4( + (const int32_t*)&inSeqs[i], + vl + ); + vuint32m2_t v_offset = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 0); + vuint32m2_t v_lit = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 1); + vuint32m2_t v_match = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 2); + // offset + ZSTD_REP_NUM + vuint32m2_t v_offBase = __riscv_vadd_vx_u32m2(v_offset, ZSTD_REP_NUM, vl); + // Check for integer overflow + // Cast to a 16-bit variable + vbool16_t lit_overflow = __riscv_vmsgtu_vx_u32m2_b16(v_lit, 65535, vl); + vuint16m1_t v_lit_clamped = __riscv_vncvt_x_x_w_u16m1(v_lit, vl); + + vbool16_t ml_overflow = __riscv_vmsgtu_vx_u32m2_b16(v_match, 65535+MINMATCH, vl); + vuint16m1_t v_ml_clamped = __riscv_vncvt_x_x_w_u16m1(__riscv_vsub_vx_u32m2(v_match, MINMATCH, vl), vl); + + // Pack two 16-bit fields into a 32-bit value (little-endian) + // The lower 16 bits contain litLength, and the upper 16 bits contain mlBase + vuint32m2_t v_lit_ml_combined = __riscv_vsll_vx_u32m2( + __riscv_vwcvtu_x_x_v_u32m2(v_ml_clamped, vl), // Convert matchLength to 32-bit + 16, + vl + ); + v_lit_ml_combined = __riscv_vor_vv_u32m2( + v_lit_ml_combined, + __riscv_vwcvtu_x_x_v_u32m2(v_lit_clamped, vl), + vl + ); + // Create a vector of SeqDef structures + // Store the offBase, litLength, and mlBase in a vector of SeqDef + vuint32m2x2_t store_data = __riscv_vcreate_v_u32m2x2( + v_offBase, + v_lit_ml_combined + ); + __riscv_vsseg2e32_v_u32m2x2( + (uint32_t*)&dstSeqs[i], + store_data, + vl + ); + // Find the first index where an overflow occurs + int first_ml = __riscv_vfirst_m_b16(ml_overflow, vl); + int first_lit = __riscv_vfirst_m_b16(lit_overflow, vl); + + if (UNLIKELY(first_ml != -1)) { + assert(longLen == 0); + longLen = i + first_ml + 1; + } + if (UNLIKELY(first_lit != -1)) { + assert(longLen == 0); + longLen = i + first_lit + 1 + nbSequences; + } + } + return longLen; +} + /* the vector implementation could also be ported to SSSE3, * but since this implementation is targeting modern systems (>= Sapphire Rapid), * it's not useful to develop and maintain code for older pre-AVX2 platforms */ @@ -7451,6 +7538,70 @@ BlockSummary ZSTD_get1BlockSummary(const ZSTD_Sequence* seqs, size_t nbSeqs) } } +#elif defined ZSTD_ARCH_RISCV_RVV + +BlockSummary ZSTD_get1BlockSummary(const ZSTD_Sequence* seqs, size_t nbSeqs) +{ + size_t totalMatchSize = 0; + size_t litSize = 0; + size_t i = 0; + int found_terminator = 0; + size_t vl_max = __riscv_vsetvlmax_e32m1(); + vuint32m1_t v_lit_sum = __riscv_vmv_v_x_u32m1(0, vl_max); + vuint32m1_t v_match_sum = __riscv_vmv_v_x_u32m1(0, vl_max); + + for (; i < nbSeqs; ) { + size_t vl = __riscv_vsetvl_e32m2(nbSeqs - i); + + ptrdiff_t stride = sizeof(ZSTD_Sequence); // 16 + vuint32m2x4_t v_tuple = __riscv_vlseg4e32_v_u32m2x4( + (const int32_t*)&seqs[i], + vl + ); + vuint32m2_t v_offset = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 0); + vuint32m2_t v_lit = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 1); + vuint32m2_t v_match = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 2); + + // Check if any element has a matchLength of 0 + vbool16_t mask = __riscv_vmseq_vx_u32m2_b16(v_match, 0, vl); + int first_zero = __riscv_vfirst_m_b16(mask, vl); + + if (first_zero >= 0) { + // Find the first zero byte and set the effective length to that index + 1 to + // recompute the cumulative vector length of literals and matches + vl = first_zero + 1; + + // recompute the cumulative vector length of literals and matches + v_lit_sum = __riscv_vredsum_vs_u32m2_u32m1(__riscv_vslidedown_vx_u32m2(v_lit, 0, vl), v_lit_sum, vl); + v_match_sum = __riscv_vredsum_vs_u32m2_u32m1(__riscv_vslidedown_vx_u32m2(v_match, 0, vl), v_match_sum, vl); + + i += vl; + found_terminator = 1; + assert(seqs[i - 1].offset == 0); + break; + } else { + + v_lit_sum = __riscv_vredsum_vs_u32m2_u32m1(v_lit, v_lit_sum, vl); + v_match_sum = __riscv_vredsum_vs_u32m2_u32m1(v_match, v_match_sum, vl); + i += vl; + } + } + litSize = __riscv_vmv_x_s_u32m1_u32(v_lit_sum); + totalMatchSize = __riscv_vmv_x_s_u32m1_u32(v_match_sum); + + if (!found_terminator && i==nbSeqs) { + BlockSummary bs; + bs.nbSequences = ERROR(externalSequences_invalid); + return bs; + } + { BlockSummary bs; + bs.nbSequences = i; + bs.blockSize = litSize + totalMatchSize; + bs.litSize = litSize; + return bs; + } +} + #else BlockSummary ZSTD_get1BlockSummary(const ZSTD_Sequence* seqs, size_t nbSeqs) From dd4cee9190cce231f56bc4f318e71f6b69270993 Mon Sep 17 00:00:00 2001 From: jinyaoguo Date: Tue, 3 Jun 2025 15:28:11 -0400 Subject: [PATCH 098/245] Release resources before returning In main, resources were freed on the success path but not in the error path. This change ensures all allocated resources are released before returning. --- contrib/externalSequenceProducer/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contrib/externalSequenceProducer/main.c b/contrib/externalSequenceProducer/main.c index e67e29538..c81e9bf40 100644 --- a/contrib/externalSequenceProducer/main.c +++ b/contrib/externalSequenceProducer/main.c @@ -27,6 +27,7 @@ do { \ } while (0) \ int main(int argc, char *argv[]) { + int retn = 0; if (argc != 2) { printf("Usage: externalSequenceProducer \n"); return 1; @@ -96,12 +97,12 @@ int main(int argc, char *argv[]) { break; } } - return 1; + retn = 1; } ZSTD_freeCCtx(zc); free(src); free(dst); free(val); - return 0; + return retn; } From a81ffe11d439d6336bbe9aca938264773beaf43d Mon Sep 17 00:00:00 2001 From: jinyaoguo Date: Wed, 4 Jun 2025 18:08:11 -0400 Subject: [PATCH 099/245] Release resources in error paths via cleanup Replace direct returns in error-handling branches with a unified cleanup block that frees allocated resources before returning, improving code quality and robustness. --- tests/bigdict.c | 31 +++++++++++++++---------------- tests/largeDictionary.c | 32 +++++++++++++++++--------------- tests/regression/method.c | 6 +++--- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/tests/bigdict.c b/tests/bigdict.c index 748b60e79..33c4ab8ea 100644 --- a/tests/bigdict.c +++ b/tests/bigdict.c @@ -70,39 +70,38 @@ int main(int argc, const char** argv) char* buffer = (char*)malloc(bufferSize); void* out = malloc(outSize); void* roundtrip = malloc(dataSize); - int _exit_code = 0; + int _exit_code = 1; (void)argc; (void)argv; if (!buffer || !out || !roundtrip || !cctx || !dctx) { fprintf(stderr, "Allocation failure\n"); - _exit_code = 1; goto cleanup; } if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 31))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 1))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_overlapLog, 9))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, ZSTD_btopt))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, 7))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 7))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, 1))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, 10))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, 10))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, 31))) - return 1; + goto cleanup; RDG_genBuffer(buffer, bufferSize, 1.0, 0.0, 0xbeefcafe); @@ -112,16 +111,16 @@ int main(int argc, const char** argv) for (i = 0; i < 10; ++i) { fprintf(stderr, "Compressing 1 GB\n"); if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_continue)) - return 1; + goto cleanup; } } fprintf(stderr, "Compressing 1 GB\n"); if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_end)) - return 1; + goto cleanup; fprintf(stderr, "Success!\n"); - goto cleanup; + _exit_code = 0; cleanup: free(roundtrip); diff --git a/tests/largeDictionary.c b/tests/largeDictionary.c index ff2bb2d70..998fd9fa8 100644 --- a/tests/largeDictionary.c +++ b/tests/largeDictionary.c @@ -70,37 +70,38 @@ int main(int argc, const char** argv) char* buffer = (char*)malloc(bufferSize); void* out = malloc(outSize); void* roundtrip = malloc(dataSize); + int _exit_code = 1; (void)argc; (void)argv; if (!buffer || !out || !roundtrip || !cctx || !dctx) { fprintf(stderr, "Allocation failure\n"); - return 1; + goto cleanup; } if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 31))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 1))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_overlapLog, 9))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, ZSTD_btopt))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, 7))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 7))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, 1))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, 10))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, 10))) - return 1; + goto cleanup; if (ZSTD_isError(ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, 31))) - return 1; + goto cleanup; RDG_genBuffer(buffer, bufferSize, 1.0, 0.0, 0xbeefcafe); @@ -110,19 +111,20 @@ int main(int argc, const char** argv) for (i = 0; i < 10; ++i) { fprintf(stderr, "Compressing 1 GB\n"); if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_continue)) - return 1; + goto cleanup; } } fprintf(stderr, "Compressing 1 GB\n"); if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_end)) - return 1; + goto cleanup; fprintf(stderr, "Success!\n"); +cleanup: free(roundtrip); free(out); free(buffer); ZSTD_freeDCtx(dctx); ZSTD_freeCCtx(cctx); - return 0; + return _exit_code; } diff --git a/tests/regression/method.c b/tests/regression/method.c index f84a15ef3..ac6fdd712 100644 --- a/tests/regression/method.c +++ b/tests/regression/method.c @@ -159,15 +159,15 @@ static result_t compress_cctx_compress( return result_error(result_error_skip); int const level = config_get_level(config); - + result_t result; ZSTD_CCtx* cctx = ZSTD_createCCtx(); ZSTD_DCtx* dctx = ZSTD_createDCtx(); if (cctx == NULL || dctx == NULL) { fprintf(stderr, "context creation failed\n"); - return result_error(result_error_system_error); + result = result_error(result_error_system_error); + goto out; } - result_t result; result_data_t data = {.total_size = 0}; for (size_t i = 0; i < state->inputs.size; ++i) { data_buffer_t const input = state->inputs.buffers[i]; From 4be08ba12283ca60b3704002c3c761047eec879c Mon Sep 17 00:00:00 2001 From: Dominik Loidolt Date: Thu, 5 Jun 2025 15:36:29 +0200 Subject: [PATCH 100/245] fuzz: Fix FUZZ_malloc_rand() to return non-NULL for zero-size allocations The FUZZ_malloc_rand() function was incorrectly always returning NULL for zero-size allocations. The random offset generated by FUZZ_dataProducer_int32Range() was not being added to the pointer variable, causing the function to always return (void *)0. --- tests/fuzz/fuzz_helpers.c | 5 ++--- tests/fuzz/fuzz_helpers.h | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/fuzz/fuzz_helpers.c b/tests/fuzz/fuzz_helpers.c index f47ff2eb4..5c530f0e9 100644 --- a/tests/fuzz/fuzz_helpers.c +++ b/tests/fuzz/fuzz_helpers.c @@ -31,12 +31,11 @@ void* FUZZ_malloc_rand(size_t size, FUZZ_dataProducer_t *producer) return mem; } else { uintptr_t ptr = 0; - /* Add +- 1M 50% of the time */ + /* Return junk pointer 50% of the time */ if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) - FUZZ_dataProducer_int32Range(producer, -1000000, 1000000); + ptr += FUZZ_dataProducer_int32Range(producer, -1000000, 1000000); return (void*)ptr; } - } int FUZZ_memcmp(void const* lhs, void const* rhs, size_t size) diff --git a/tests/fuzz/fuzz_helpers.h b/tests/fuzz/fuzz_helpers.h index f21ec4751..c5d75b402 100644 --- a/tests/fuzz/fuzz_helpers.h +++ b/tests/fuzz/fuzz_helpers.h @@ -66,6 +66,7 @@ void* FUZZ_malloc(size_t size); /** * malloc except returns random pointer for zero sized data and FUZZ_ASSERT * that malloc doesn't fail. + * WARNING: Only free the returned pointer if size > 0! */ void* FUZZ_malloc_rand(size_t size, FUZZ_dataProducer_t *producer); From 80cac404c7507e93591ac881e59f96327e8ee88e Mon Sep 17 00:00:00 2001 From: Michael Kolupaev Date: Thu, 17 Apr 2025 02:10:14 +0000 Subject: [PATCH 101/245] Add unwind information in huf_decompress_amd64.S --- lib/decompress/huf_decompress_amd64.S | 154 ++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/lib/decompress/huf_decompress_amd64.S b/lib/decompress/huf_decompress_amd64.S index 656aada95..66e12d11b 100644 --- a/lib/decompress/huf_decompress_amd64.S +++ b/lib/decompress/huf_decompress_amd64.S @@ -117,22 +117,55 @@ ZSTD_HIDE_ASM_FUNCTION(_HUF_decompress4X1_usingDTable_internal_fast_asm_loop) _HUF_decompress4X1_usingDTable_internal_fast_asm_loop: HUF_decompress4X1_usingDTable_internal_fast_asm_loop: ZSTD_CET_ENDBRANCH + .cfi_startproc + .cfi_def_cfa_offset 8 + .cfi_offset %rip, -8 /* Save all registers - even if they are callee saved for simplicity. */ push %rax + .cfi_def_cfa_offset 16 + .cfi_offset rax, -16 push %rbx + .cfi_def_cfa_offset 24 + .cfi_offset rbx, -24 push %rcx + .cfi_def_cfa_offset 32 + .cfi_offset rcx, -32 push %rdx + .cfi_def_cfa_offset 40 + .cfi_offset rdx, -40 push %rbp + .cfi_def_cfa_offset 48 + .cfi_offset rbp, -48 push %rsi + .cfi_def_cfa_offset 56 + .cfi_offset rsi, -56 push %rdi + .cfi_def_cfa_offset 64 + .cfi_offset rdi, -64 push %r8 + .cfi_def_cfa_offset 72 + .cfi_offset r8, -72 push %r9 + .cfi_def_cfa_offset 80 + .cfi_offset r9, -80 push %r10 + .cfi_def_cfa_offset 88 + .cfi_offset r10, -88 push %r11 + .cfi_def_cfa_offset 96 + .cfi_offset r11, -96 push %r12 + .cfi_def_cfa_offset 104 + .cfi_offset r12, -104 push %r13 + .cfi_def_cfa_offset 112 + .cfi_offset r13, -112 push %r14 + .cfi_def_cfa_offset 120 + .cfi_offset r14, -120 push %r15 + .cfi_def_cfa_offset 128 + .cfi_offset r15, -128 /* Read HUF_DecompressAsmArgs* args from %rax */ #if defined(_WIN32) @@ -154,11 +187,16 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop: movq 88(%rax), %bits3 movq 96(%rax), %dtable push %rax /* argument */ + .cfi_def_cfa_offset 136 push 104(%rax) /* ilowest */ + .cfi_def_cfa_offset 144 push 112(%rax) /* oend */ + .cfi_def_cfa_offset 152 push %olimit /* olimit space */ + .cfi_def_cfa_offset 160 subq $24, %rsp + .cfi_def_cfa_offset 184 .L_4X1_compute_olimit: /* Computes how many iterations we can do safely @@ -334,12 +372,17 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop: #undef RELOAD_BITS .L_4X1_exit: addq $24, %rsp + .cfi_def_cfa_offset 160 /* Restore stack (oend & olimit) */ pop %rax /* olimit */ + .cfi_def_cfa_offset 152 pop %rax /* oend */ + .cfi_def_cfa_offset 144 pop %rax /* ilowest */ + .cfi_def_cfa_offset 136 pop %rax /* arg */ + .cfi_def_cfa_offset 128 /* Save ip / op / bits */ movq %ip0, 0(%rax) @@ -357,41 +400,105 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop: /* Restore registers */ pop %r15 + .cfi_restore r15 + .cfi_def_cfa_offset 120 pop %r14 + .cfi_restore r14 + .cfi_def_cfa_offset 112 pop %r13 + .cfi_restore r13 + .cfi_def_cfa_offset 104 pop %r12 + .cfi_restore r12 + .cfi_def_cfa_offset 96 pop %r11 + .cfi_restore r11 + .cfi_def_cfa_offset 88 pop %r10 + .cfi_restore r10 + .cfi_def_cfa_offset 80 pop %r9 + .cfi_restore r9 + .cfi_def_cfa_offset 72 pop %r8 + .cfi_restore r8 + .cfi_def_cfa_offset 64 pop %rdi + .cfi_restore rdi + .cfi_def_cfa_offset 56 pop %rsi + .cfi_restore rsi + .cfi_def_cfa_offset 48 pop %rbp + .cfi_restore rbp + .cfi_def_cfa_offset 40 pop %rdx + .cfi_restore rdx + .cfi_def_cfa_offset 32 pop %rcx + .cfi_restore rcx + .cfi_def_cfa_offset 24 pop %rbx + .cfi_restore rbx + .cfi_def_cfa_offset 16 pop %rax + .cfi_restore rax + .cfi_def_cfa_offset 8 ret + .cfi_endproc _HUF_decompress4X2_usingDTable_internal_fast_asm_loop: HUF_decompress4X2_usingDTable_internal_fast_asm_loop: ZSTD_CET_ENDBRANCH + .cfi_startproc + .cfi_def_cfa_offset 8 + .cfi_offset %rip, -8 /* Save all registers - even if they are callee saved for simplicity. */ push %rax + .cfi_def_cfa_offset 16 + .cfi_offset rax, -16 push %rbx + .cfi_def_cfa_offset 24 + .cfi_offset rbx, -24 push %rcx + .cfi_def_cfa_offset 32 + .cfi_offset rcx, -32 push %rdx + .cfi_def_cfa_offset 40 + .cfi_offset rdx, -40 push %rbp + .cfi_def_cfa_offset 48 + .cfi_offset rbp, -48 push %rsi + .cfi_def_cfa_offset 56 + .cfi_offset rsi, -56 push %rdi + .cfi_def_cfa_offset 64 + .cfi_offset rdi, -64 push %r8 + .cfi_def_cfa_offset 72 + .cfi_offset r8, -72 push %r9 + .cfi_def_cfa_offset 80 + .cfi_offset r9, -80 push %r10 + .cfi_def_cfa_offset 88 + .cfi_offset r10, -88 push %r11 + .cfi_def_cfa_offset 96 + .cfi_offset r11, -96 push %r12 + .cfi_def_cfa_offset 104 + .cfi_offset r12, -104 push %r13 + .cfi_def_cfa_offset 112 + .cfi_offset r13, -112 push %r14 + .cfi_def_cfa_offset 120 + .cfi_offset r14, -120 push %r15 + .cfi_def_cfa_offset 128 + .cfi_offset r15, -128 /* Read HUF_DecompressAsmArgs* args from %rax */ #if defined(_WIN32) @@ -413,23 +520,31 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop: movq 88(%rax), %bits3 movq 96(%rax), %dtable push %rax /* argument */ + .cfi_def_cfa_offset 136 push %rax /* olimit */ + .cfi_def_cfa_offset 144 push 104(%rax) /* ilowest */ + .cfi_def_cfa_offset 152 movq 112(%rax), %rax push %rax /* oend3 */ + .cfi_def_cfa_offset 160 movq %op3, %rax push %rax /* oend2 */ + .cfi_def_cfa_offset 168 movq %op2, %rax push %rax /* oend1 */ + .cfi_def_cfa_offset 176 movq %op1, %rax push %rax /* oend0 */ + .cfi_def_cfa_offset 184 /* Scratch space */ subq $8, %rsp + .cfi_def_cfa_offset 192 .L_4X2_compute_olimit: /* Computes how many iterations we can do safely @@ -558,14 +673,22 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop: #undef RELOAD_BITS .L_4X2_exit: addq $8, %rsp + .cfi_def_cfa_offset 184 /* Restore stack (oend & olimit) */ pop %rax /* oend0 */ + .cfi_def_cfa_offset 176 pop %rax /* oend1 */ + .cfi_def_cfa_offset 168 pop %rax /* oend2 */ + .cfi_def_cfa_offset 160 pop %rax /* oend3 */ + .cfi_def_cfa_offset 152 pop %rax /* ilowest */ + .cfi_def_cfa_offset 144 pop %rax /* olimit */ + .cfi_def_cfa_offset 136 pop %rax /* arg */ + .cfi_def_cfa_offset 128 /* Save ip / op / bits */ movq %ip0, 0(%rax) @@ -583,20 +706,51 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop: /* Restore registers */ pop %r15 + .cfi_restore r15 + .cfi_def_cfa_offset 120 pop %r14 + .cfi_restore r14 + .cfi_def_cfa_offset 112 pop %r13 + .cfi_restore r13 + .cfi_def_cfa_offset 104 pop %r12 + .cfi_restore r12 + .cfi_def_cfa_offset 96 pop %r11 + .cfi_restore r11 + .cfi_def_cfa_offset 88 pop %r10 + .cfi_restore r10 + .cfi_def_cfa_offset 80 pop %r9 + .cfi_restore r9 + .cfi_def_cfa_offset 72 pop %r8 + .cfi_restore r8 + .cfi_def_cfa_offset 64 pop %rdi + .cfi_restore rdi + .cfi_def_cfa_offset 56 pop %rsi + .cfi_restore rsi + .cfi_def_cfa_offset 48 pop %rbp + .cfi_restore rbp + .cfi_def_cfa_offset 40 pop %rdx + .cfi_restore rdx + .cfi_def_cfa_offset 32 pop %rcx + .cfi_restore rcx + .cfi_def_cfa_offset 24 pop %rbx + .cfi_restore rbx + .cfi_def_cfa_offset 16 pop %rax + .cfi_restore rax + .cfi_def_cfa_offset 8 ret + .cfi_endproc #endif From a480191f9ec3704da1c79e4cccce726f29e4581b Mon Sep 17 00:00:00 2001 From: Michael Kolupaev Date: Thu, 17 Apr 2025 20:43:19 +0000 Subject: [PATCH 102/245] Fix Darwin build of huf_decompress_amd64.S --- lib/decompress/huf_decompress_amd64.S | 46 ++++++++++++++++----------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/lib/decompress/huf_decompress_amd64.S b/lib/decompress/huf_decompress_amd64.S index 66e12d11b..dc1f3d921 100644 --- a/lib/decompress/huf_decompress_amd64.S +++ b/lib/decompress/huf_decompress_amd64.S @@ -38,6 +38,16 @@ #endif +// There appears to be an unreconcilable syntax difference between Linux and Darwin assemblers. +// Name of a private label (i.e. not exported to symbol table) on Darwin has to start with "L", +// on Linux has to start with ".". There's no way to have a name start with both "." and "L", so +// we have to use a macro. +#if defined(__APPLE__) +#define LOCAL_LABEL(label) L_ ## label +#else +#define LOCAL_LABEL(label) .L_ ## label +#endif + #if ZSTD_ENABLE_ASM_X86_64_BMI2 /* Calling convention: @@ -198,7 +208,7 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop: subq $24, %rsp .cfi_def_cfa_offset 184 -.L_4X1_compute_olimit: +LOCAL_LABEL(4X1_compute_olimit): /* Computes how many iterations we can do safely * %r15, %rax may be clobbered * rbx, rdx must be saved @@ -245,19 +255,19 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop: /* If (op3 + 20 > olimit) */ movq %op3, %rax /* rax = op3 */ cmpq %rax, %olimit /* op3 == olimit */ - je .L_4X1_exit + je LOCAL_LABEL(4X1_exit) /* If (ip1 < ip0) go to exit */ cmpq %ip0, %ip1 - jb .L_4X1_exit + jb LOCAL_LABEL(4X1_exit) /* If (ip2 < ip1) go to exit */ cmpq %ip1, %ip2 - jb .L_4X1_exit + jb LOCAL_LABEL(4X1_exit) /* If (ip3 < ip2) go to exit */ cmpq %ip2, %ip3 - jb .L_4X1_exit + jb LOCAL_LABEL(4X1_exit) /* Reads top 11 bits from bits[n] * Loads dt[bits[n]] into var[n] @@ -318,7 +328,7 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop: .p2align 6 -.L_4X1_loop_body: +LOCAL_LABEL(4X1_loop_body): /* Decode 5 symbols in each of the 4 streams (20 total) * Must have called GET_NEXT_DELT for each stream */ @@ -356,7 +366,7 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop: /* If op3 < olimit: continue the loop */ cmp %op3, 24(%rsp) - ja .L_4X1_loop_body + ja LOCAL_LABEL(4X1_loop_body) /* Reload ip[1,2,3] from stack */ movq 0(%rsp), %ip1 @@ -364,13 +374,13 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop: movq 16(%rsp), %ip3 /* Re-compute olimit */ - jmp .L_4X1_compute_olimit + jmp LOCAL_LABEL(4X1_compute_olimit) #undef GET_NEXT_DELT #undef DECODE_FROM_DELT #undef DECODE #undef RELOAD_BITS -.L_4X1_exit: +LOCAL_LABEL(4X1_exit): addq $24, %rsp .cfi_def_cfa_offset 160 @@ -546,7 +556,7 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop: subq $8, %rsp .cfi_def_cfa_offset 192 -.L_4X2_compute_olimit: +LOCAL_LABEL(4X2_compute_olimit): /* Computes how many iterations we can do safely * %r15, %rax may be clobbered * rdx must be saved @@ -610,19 +620,19 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop: /* If (op3 + 10 > olimit) */ movq %op3, %rax /* rax = op3 */ cmpq %rax, %olimit /* op3 == olimit */ - je .L_4X2_exit + je LOCAL_LABEL(4X2_exit) /* If (ip1 < ip0) go to exit */ cmpq %ip0, %ip1 - jb .L_4X2_exit + jb LOCAL_LABEL(4X2_exit) /* If (ip2 < ip1) go to exit */ cmpq %ip1, %ip2 - jb .L_4X2_exit + jb LOCAL_LABEL(4X2_exit) /* If (ip3 < ip2) go to exit */ cmpq %ip2, %ip3 - jb .L_4X2_exit + jb LOCAL_LABEL(4X2_exit) #define DECODE(n, idx) \ movq %bits##n, %rax; \ @@ -649,7 +659,7 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop: .p2align 6 -.L_4X2_loop_body: +LOCAL_LABEL(4X2_loop_body): /* We clobber r8, so store it on the stack */ movq %r8, 0(%rsp) @@ -666,12 +676,12 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop: FOR_EACH_STREAM(RELOAD_BITS) cmp %op3, 48(%rsp) - ja .L_4X2_loop_body - jmp .L_4X2_compute_olimit + ja LOCAL_LABEL(4X2_loop_body) + jmp LOCAL_LABEL(4X2_compute_olimit) #undef DECODE #undef RELOAD_BITS -.L_4X2_exit: +LOCAL_LABEL(4X2_exit): addq $8, %rsp .cfi_def_cfa_offset 184 /* Restore stack (oend & olimit) */ From a2dba85fd13f6dbd5158c14d9cc147fb5b31bf27 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 8 Jun 2025 20:25:25 +0000 Subject: [PATCH 103/245] ci: separate cmake tests into dedicated workflow file - Create new .github/workflows/cmake-tests.yml with all cmake-related jobs - Move cmake-build-and-test-check, cmake-source-directory-with-spaces, and cmake-visual-2022 jobs - Remove cmake tests from dev-short-tests.yml to improve organization - Maintain same trigger conditions and test configurations - Add dedicated concurrency group for cmake tests This separation allows cmake tests to run independently and makes the CI configuration more modular and easier to maintain. --- .github/workflows/cmake-tests.yml | 74 +++++++++++++++++++++++++++ .github/workflows/dev-short-tests.yml | 62 ---------------------- 2 files changed, 74 insertions(+), 62 deletions(-) create mode 100644 .github/workflows/cmake-tests.yml diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml new file mode 100644 index 000000000..ea4181359 --- /dev/null +++ b/.github/workflows/cmake-tests.yml @@ -0,0 +1,74 @@ +name: cmake-tests +# CMake-specific build and test workflows + +concurrency: + group: cmake-${{ github.ref }} + cancel-in-progress: true + +on: + pull_request: + branches: [ dev, release, actionsTest ] + +permissions: read-all + +jobs: + cmake-build-and-test-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - name: cmake build and test + run: | + sudo apt install liblzma-dev + FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild V=1 + + cmake-source-directory-with-spaces: + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + generator: "Unix Makefiles" + - os: windows-latest + generator: "NMake Makefiles" + - os: macos-latest + generator: "Unix Makefiles" + env: + SRC_DIR: "source directory with spaces" + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + with: + path: "${{ env.SRC_DIR }}" + - uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 + if: ${{ matrix.generator == 'NMake Makefiles' }} + - name: cmake build on a source directory with spaces + run: | + cmake -S "${{ env.SRC_DIR }}/build/cmake" -B build -DBUILD_TESTING=ON -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release --install-prefix "${{ runner.temp }}/install" + cmake --build build --config Release + cmake --install build --config Release + + cmake-visual-2022: + strategy: + matrix: + include: + - generator: "Visual Studio 17 2022" + flags: "-A x64" + - generator: "Visual Studio 17 2022" + flags: "-A Win32" + - generator: "MinGW Makefiles" + - generator: "Visual Studio 17 2022" + flags: "-T ClangCL" + - generator: "Visual Studio 17 2022" + flags: "-T ClangCL -A x64 -DCMAKE_C_FLAGS=/arch:AVX2" + runs-on: windows-2022 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - name: Add MSBuild to PATH + uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0 + - name: Build & Test + run: | + cd build\cmake + mkdir build + cd build + cmake.exe -G "${{matrix.generator}}" ${{matrix.flags}} -DCMAKE_BUILD_TYPE=Debug -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS:BOOL=ON -DZSTD_ZSTREAM_FLAGS=-T30s -DZSTD_FUZZER_FLAGS=-T30s -DZSTD_FULLBENCH_FLAGS=-i0 .. + cmake.exe --build . + ctest.exe -V -C Debug diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 227b01a0c..8e8753658 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -72,40 +72,6 @@ jobs: # candidate test (for discussion) : underlink test # LDFLAGS=-Wl,--no-undefined : will make the linker fail if dll is underlinked - cmake-build-and-test-check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - - name: cmake build and test - run: | - sudo apt install liblzma-dev - FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild V=1 - - cmake-source-directory-with-spaces: - runs-on: ${{ matrix.os }} - strategy: - matrix: - include: - - os: ubuntu-latest - generator: "Unix Makefiles" - - os: windows-latest - generator: "NMake Makefiles" - - os: macos-latest - generator: "Unix Makefiles" - env: - SRC_DIR: "source directory with spaces" - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - with: - path: "${{ env.SRC_DIR }}" - - uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 - if: ${{ matrix.generator == 'NMake Makefiles' }} - - name: cmake build on a source directory with spaces - run: | - cmake -S "${{ env.SRC_DIR }}/build/cmake" -B build -DBUILD_TESTING=ON -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release --install-prefix "${{ runner.temp }}/install" - cmake --build build --config Release - cmake --install build --config Release - cpp-gnu90-c99-compatibility: runs-on: ubuntu-latest steps: @@ -339,34 +305,6 @@ jobs: run: | meson install -C builddir --destdir staging/ - cmake-visual-2022: - strategy: - matrix: - include: - - generator: "Visual Studio 17 2022" - flags: "-A x64" - - generator: "Visual Studio 17 2022" - flags: "-A Win32" - - generator: "MinGW Makefiles" - - generator: "Visual Studio 17 2022" - flags: "-T ClangCL" - - generator: "Visual Studio 17 2022" - flags: "-T ClangCL -A x64 -DCMAKE_C_FLAGS=/arch:AVX2" - runs-on: windows-2022 - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0 - - name: Build & Test - working-directory: ${{env.GITHUB_WORKSPACE}} - run: | - cd build\cmake - mkdir build - cd build - cmake.exe -G "${{matrix.generator}}" ${{matrix.flags}} -DCMAKE_BUILD_TYPE=Debug -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS:BOOL=ON -DZSTD_ZSTREAM_FLAGS=-T30s -DZSTD_FUZZER_FLAGS=-T30s -DZSTD_FULLBENCH_FLAGS=-i0 .. - cmake.exe --build . - ctest.exe -V -C Debug - msbuild-visual-studio: strategy: fail-fast: false # 'false' means Don't stop matrix workflows even if some matrix failed. From b92277460210a34391e7da58eac67800e0c70afa Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 8 Jun 2025 21:39:59 +0000 Subject: [PATCH 104/245] refactor CMake tests workflow for readability --- .github/workflows/cmake-tests.yml | 55 +++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index ea4181359..0f91059af 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -1,5 +1,7 @@ name: cmake-tests # CMake-specific build and test workflows +# This workflow validates zstd builds across different CMake configurations, +# platforms, and edge cases to ensure broad compatibility. concurrency: group: cmake-${{ github.ref }} @@ -11,27 +13,48 @@ on: permissions: read-all +env: + # Centralized test timeouts for consistency + QUICK_TEST_TIME: "30s" + STANDARD_TEST_TIME: "1mn" + # Common CMake flags + COMMON_CMAKE_FLAGS: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON" + jobs: - cmake-build-and-test-check: + # Ubuntu-based cmake build using make wrapper + # This test uses the make-driven cmake build to ensure compatibility + # with the existing build system integration + cmake-ubuntu-basic: + name: "CMake Ubuntu Basic Build" runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - - name: cmake build and test + - name: Install dependencies run: | - sudo apt install liblzma-dev - FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild V=1 + sudo apt install liblzma-dev # Required for compression algorithms + - name: CMake build and test via make + run: | + # Use make wrapper for cmake build with quick test timeouts + FUZZERTEST=-T${{ env.STANDARD_TEST_TIME }} ZSTREAM_TESTTIME=-T${{ env.STANDARD_TEST_TIME }} make cmakebuild V=1 - cmake-source-directory-with-spaces: + # Cross-platform cmake build with edge case: source paths containing spaces + # This test ensures cmake handles filesystem paths with spaces correctly + # across different operating systems and build generators + cmake-cross-platform-spaces: + name: "CMake Cross-Platform (Spaces in Path)" runs-on: ${{ matrix.os }} strategy: matrix: include: - os: ubuntu-latest generator: "Unix Makefiles" + name: "Linux" - os: windows-latest generator: "NMake Makefiles" + name: "Windows NMake" - os: macos-latest generator: "Unix Makefiles" + name: "macOS" env: SRC_DIR: "source directory with spaces" steps: @@ -40,35 +63,47 @@ jobs: path: "${{ env.SRC_DIR }}" - uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 if: ${{ matrix.generator == 'NMake Makefiles' }} - - name: cmake build on a source directory with spaces + - name: "CMake build and install (${{ matrix.name }})" run: | + # Test Release build with installation to verify packaging cmake -S "${{ env.SRC_DIR }}/build/cmake" -B build -DBUILD_TESTING=ON -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release --install-prefix "${{ runner.temp }}/install" cmake --build build --config Release cmake --install build --config Release - cmake-visual-2022: + # Windows-specific cmake testing with Visual Studio 2022 + # Tests multiple generators and toolchains to ensure broad Windows compatibility + # including MSVC, MinGW, and Clang-CL with various architectures and optimizations + cmake-windows-comprehensive: + name: "CMake Windows VS2022 (${{ matrix.name }})" + runs-on: windows-2022 strategy: matrix: include: - generator: "Visual Studio 17 2022" flags: "-A x64" + name: "MSVC x64" - generator: "Visual Studio 17 2022" flags: "-A Win32" + name: "MSVC Win32" - generator: "MinGW Makefiles" + flags: "" + name: "MinGW" - generator: "Visual Studio 17 2022" flags: "-T ClangCL" + name: "Clang-CL" - generator: "Visual Studio 17 2022" flags: "-T ClangCL -A x64 -DCMAKE_C_FLAGS=/arch:AVX2" - runs-on: windows-2022 + name: "Clang-CL AVX2" steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: Add MSBuild to PATH uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0 - - name: Build & Test + - name: "Build & Test (${{ matrix.name }})" run: | + # Configure and build in Debug mode with comprehensive testing cd build\cmake mkdir build cd build - cmake.exe -G "${{matrix.generator}}" ${{matrix.flags}} -DCMAKE_BUILD_TYPE=Debug -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS:BOOL=ON -DZSTD_ZSTREAM_FLAGS=-T30s -DZSTD_FUZZER_FLAGS=-T30s -DZSTD_FULLBENCH_FLAGS=-i0 .. + cmake.exe -G "${{matrix.generator}}" ${{matrix.flags}} -DCMAKE_BUILD_TYPE=Debug ${{ env.COMMON_CMAKE_FLAGS }} -DZSTD_ZSTREAM_FLAGS=-T${{ env.QUICK_TEST_TIME }} -DZSTD_FUZZER_FLAGS=-T${{ env.QUICK_TEST_TIME }} -DZSTD_FULLBENCH_FLAGS=-i0 .. cmake.exe --build . ctest.exe -V -C Debug From a168ae723286f54321abb69dcb10ad07f074802b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 8 Jun 2025 22:19:57 +0000 Subject: [PATCH 105/245] added windows arm64 runner to cmake tests --- .github/workflows/cmake-tests.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index 0f91059af..5d9dac00d 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -72,28 +72,37 @@ jobs: # Windows-specific cmake testing with Visual Studio 2022 # Tests multiple generators and toolchains to ensure broad Windows compatibility - # including MSVC, MinGW, and Clang-CL with various architectures and optimizations + # including MSVC (x64, Win32, ARM64), MinGW, and Clang-CL with various architectures and optimizations cmake-windows-comprehensive: name: "CMake Windows VS2022 (${{ matrix.name }})" - runs-on: windows-2022 + runs-on: ${{ matrix.runner }} strategy: matrix: include: - generator: "Visual Studio 17 2022" flags: "-A x64" name: "MSVC x64" + runner: "windows-2022" - generator: "Visual Studio 17 2022" flags: "-A Win32" name: "MSVC Win32" + runner: "windows-2022" + - generator: "Visual Studio 17 2022" + flags: "-A ARM64" + name: "MSVC ARM64" + runner: "windows-2022-arm64" - generator: "MinGW Makefiles" flags: "" name: "MinGW" + runner: "windows-2022" - generator: "Visual Studio 17 2022" flags: "-T ClangCL" name: "Clang-CL" + runner: "windows-2022" - generator: "Visual Studio 17 2022" flags: "-T ClangCL -A x64 -DCMAKE_C_FLAGS=/arch:AVX2" name: "Clang-CL AVX2" + runner: "windows-2022" steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: Add MSBuild to PATH From c826c572cf246e1c08d6927a249e9e11bcb11679 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 8 Jun 2025 22:40:15 +0000 Subject: [PATCH 106/245] added macos arm64 tests and comment out windows arm64 tests due to unacceptably long queue time --- .github/workflows/cmake-tests.yml | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index 5d9dac00d..0dae6c763 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -87,10 +87,10 @@ jobs: flags: "-A Win32" name: "MSVC Win32" runner: "windows-2022" - - generator: "Visual Studio 17 2022" - flags: "-A ARM64" - name: "MSVC ARM64" - runner: "windows-2022-arm64" + # - generator: "Visual Studio 17 2022" + # flags: "-A ARM64" + # name: "MSVC ARM64" + # runner: "windows-2022-arm64" # Disabled due to very long queue times - generator: "MinGW Makefiles" flags: "" name: "MinGW" @@ -116,3 +116,21 @@ jobs: cmake.exe -G "${{matrix.generator}}" ${{matrix.flags}} -DCMAKE_BUILD_TYPE=Debug ${{ env.COMMON_CMAKE_FLAGS }} -DZSTD_ZSTREAM_FLAGS=-T${{ env.QUICK_TEST_TIME }} -DZSTD_FUZZER_FLAGS=-T${{ env.QUICK_TEST_TIME }} -DZSTD_FULLBENCH_FLAGS=-i0 .. cmake.exe --build . ctest.exe -V -C Debug + + # macOS ARM64 (Apple Silicon) specific cmake testing + # Validates zstd builds and runs correctly on Apple Silicon architecture + # Uses native ARM64 hardware for optimal performance and compatibility testing + cmake-macos-arm64: + name: "CMake macOS ARM64 (Apple Silicon)" + runs-on: macos-14 # ARM64 runner + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - name: "CMake build and test (ARM64)" + run: | + # Configure and build with ARM64-specific optimizations + cd build/cmake + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release ${{ env.COMMON_CMAKE_FLAGS }} -DZSTD_ZSTREAM_FLAGS=-T${{ env.QUICK_TEST_TIME }} -DZSTD_FUZZER_FLAGS=-T${{ env.QUICK_TEST_TIME }} -DZSTD_FULLBENCH_FLAGS=-i1 .. + make -j$(sysctl -n hw.ncpu) + ctest -V From 75abb8bc1c4cf57c994204a7e01552c2fad94a90 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 8 Jun 2025 23:51:55 +0000 Subject: [PATCH 107/245] add cmake build test with ZSTD_BUILD_TESTS disabled should reproduce #4405 and fail --- .github/workflows/cmake-tests.yml | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index 0dae6c763..f9212e254 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -83,10 +83,18 @@ jobs: flags: "-A x64" name: "MSVC x64" runner: "windows-2022" + cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON" - generator: "Visual Studio 17 2022" flags: "-A Win32" name: "MSVC Win32" runner: "windows-2022" + cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON" + - generator: "Visual Studio 17 2022" + flags: "-A x64" + name: "MSVC x64 (No ZSTD_BUILD_TESTS)" + runner: "windows-2022" + # Intentionally omit ZSTD_BUILD_TESTS to reproduce the CXX language configuration bug + cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON" # - generator: "Visual Studio 17 2022" # flags: "-A ARM64" # name: "MSVC ARM64" @@ -95,26 +103,34 @@ jobs: flags: "" name: "MinGW" runner: "windows-2022" + cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON" - generator: "Visual Studio 17 2022" flags: "-T ClangCL" name: "Clang-CL" runner: "windows-2022" + cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON" - generator: "Visual Studio 17 2022" flags: "-T ClangCL -A x64 -DCMAKE_C_FLAGS=/arch:AVX2" name: "Clang-CL AVX2" runner: "windows-2022" + cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON" steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - name: Add MSBuild to PATH uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0 - - name: "Build & Test (${{ matrix.name }})" + - name: "Configure CMake (${{ matrix.name }})" run: | - # Configure and build in Debug mode with comprehensive testing cd build\cmake mkdir build cd build - cmake.exe -G "${{matrix.generator}}" ${{matrix.flags}} -DCMAKE_BUILD_TYPE=Debug ${{ env.COMMON_CMAKE_FLAGS }} -DZSTD_ZSTREAM_FLAGS=-T${{ env.QUICK_TEST_TIME }} -DZSTD_FUZZER_FLAGS=-T${{ env.QUICK_TEST_TIME }} -DZSTD_FULLBENCH_FLAGS=-i0 .. + cmake.exe -G "${{matrix.generator}}" ${{matrix.flags}} -DCMAKE_BUILD_TYPE=Debug ${{ matrix.cmake_extra_flags }} -DZSTD_ZSTREAM_FLAGS=-T${{ env.QUICK_TEST_TIME }} -DZSTD_FUZZER_FLAGS=-T${{ env.QUICK_TEST_TIME }} -DZSTD_FULLBENCH_FLAGS=-i0 .. + - name: "Build (${{ matrix.name }})" + run: | + cd build\cmake\build cmake.exe --build . + - name: "Test (${{ matrix.name }})" + run: | + cd build\cmake\build ctest.exe -V -C Debug # macOS ARM64 (Apple Silicon) specific cmake testing From 49fe2ec79332b6706bdcac3ddca6c15a84da85b1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 9 Jun 2025 03:47:33 +0000 Subject: [PATCH 108/245] refactor: modularize CMakeLists.txt for better maintainability - Split monolithic 235-line CMakeLists.txt into focused modules - Main file reduced to 78 lines with clear section organization - Created 5 specialized modules: * ZstdVersion.cmake - CMake policies and version management * ZstdOptions.cmake - Build options and platform configuration * ZstdDependencies.cmake - External dependency management * ZstdBuild.cmake - Build targets and validation * ZstdPackage.cmake - Package configuration generation Benefits: - Improved readability and maintainability - Better separation of concerns - Easier debugging and modification - Preserved 100% backward compatibility - All existing build options and targets unchanged The refactored build system passes all tests and maintains identical functionality while being much easier to understand and maintain. --- build/cmake/CMakeLists.txt | 245 ++++-------------- build/cmake/CMakeModules/ZstdBuild.cmake | 42 +++ .../cmake/CMakeModules/ZstdDependencies.cmake | 30 +++ build/cmake/CMakeModules/ZstdOptions.cmake | 68 +++++ build/cmake/CMakeModules/ZstdPackage.cmake | 42 +++ build/cmake/CMakeModules/ZstdVersion.cmake | 31 +++ 6 files changed, 259 insertions(+), 199 deletions(-) create mode 100644 build/cmake/CMakeModules/ZstdBuild.cmake create mode 100644 build/cmake/CMakeModules/ZstdDependencies.cmake create mode 100644 build/cmake/CMakeModules/ZstdOptions.cmake create mode 100644 build/cmake/CMakeModules/ZstdPackage.cmake create mode 100644 build/cmake/CMakeModules/ZstdVersion.cmake diff --git a/build/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt index f08905345..753cf4a9e 100644 --- a/build/cmake/CMakeLists.txt +++ b/build/cmake/CMakeLists.txt @@ -9,226 +9,73 @@ cmake_minimum_required(VERSION 3.10 FATAL_ERROR) -# As of 2018-12-26 ZSTD has been validated to build with cmake version 3.13.2 new policies. -# Set and use the newest cmake policies that are validated to work -set(ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION "3") -set(ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION "13") #Policies never changed at PATCH level -if("${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}" EQUAL "${CMAKE_MAJOR_VERSION}" AND - "${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}" GREATER "${CMAKE_MINOR_VERSION}") - set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}") -else() - set(ZSTD_CMAKE_POLICY_VERSION "${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}.${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}.0") -endif() -cmake_policy(VERSION ${ZSTD_CMAKE_POLICY_VERSION}) - -set(CMAKE_BUILD_WITH_INSTALL_RPATH on) - +#----------------------------------------------------------------------------- +# Setup CMake environment +#----------------------------------------------------------------------------- +set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules") + +# Define project paths set(ZSTD_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../..") set(LIBRARY_DIR ${ZSTD_SOURCE_DIR}/lib) -# Parse version -include(GetZstdLibraryVersion) -GetZstdLibraryVersion(${LIBRARY_DIR}/zstd.h zstd_VERSION_MAJOR zstd_VERSION_MINOR zstd_VERSION_PATCH) - -set(ZSTD_SHORT_VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}") -set(ZSTD_FULL_VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}") - -project(zstd - VERSION "${ZSTD_FULL_VERSION}" - LANGUAGES C # Main library is in C - ASM # And ASM - ) - -message(STATUS "ZSTD VERSION: ${zstd_VERSION}") -set(zstd_HOMEPAGE_URL "https://facebook.github.io/zstd") -set(zstd_DESCRIPTION "Zstandard is a real-time compression algorithm, providing high compression ratios.") - -# Set a default build type if none was specified -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting build type to 'Release' as none was specified.") - set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") -endif() - -include(GNUInstallDirs) - -# Always hide XXHash symbols -add_definitions(-DXXH_NAMESPACE=ZSTD_) #----------------------------------------------------------------------------- -# Installation variables +# Configure CMake policies and version +#----------------------------------------------------------------------------- +include(ZstdVersion) + +#----------------------------------------------------------------------------- +# Project declaration +#----------------------------------------------------------------------------- +project(zstd + VERSION "${ZSTD_FULL_VERSION}" + LANGUAGES C ASM # Main library is in C and ASM + HOMEPAGE_URL "${zstd_HOMEPAGE_URL}" + DESCRIPTION "${zstd_DESCRIPTION}" +) + +#----------------------------------------------------------------------------- +# Build type configuration +#----------------------------------------------------------------------------- +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to 'Release' as none was specified.") + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +#----------------------------------------------------------------------------- +# Include standard modules +#----------------------------------------------------------------------------- +include(GNUInstallDirs) + +#----------------------------------------------------------------------------- +# Display installation information #----------------------------------------------------------------------------- message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}") #----------------------------------------------------------------------------- -# Options +# Configure build options #----------------------------------------------------------------------------- - -# Legacy support -option(ZSTD_LEGACY_SUPPORT "LEGACY SUPPORT" ON) - -if (ZSTD_LEGACY_SUPPORT) - message(STATUS "ZSTD_LEGACY_SUPPORT defined!") - set(ZSTD_LEGACY_LEVEL 5 CACHE STRING "") - add_definitions(-DZSTD_LEGACY_SUPPORT=${ZSTD_LEGACY_LEVEL}) -else () - message(STATUS "ZSTD_LEGACY_SUPPORT not defined!") - add_definitions(-DZSTD_LEGACY_SUPPORT=0) -endif () - -if (APPLE) - option(ZSTD_FRAMEWORK "Build as Apple Frameworks" OFF) -endif () - -if (ANDROID) - set(ZSTD_MULTITHREAD_SUPPORT_DEFAULT OFF) - # Old versions of bionic libc don't have fseeko/ftello - if ((NOT ${ANDROID_PLATFORM_LEVEL}) OR ${ANDROID_PLATFORM_LEVEL} VERSION_LESS 24) - message(STATUS "Setting compile definitions for old Android API") - add_compile_definitions(LIBC_NO_FSEEKO) - endif () -else() - set(ZSTD_MULTITHREAD_SUPPORT_DEFAULT ON) -endif() - -# Multi-threading support -option(ZSTD_MULTITHREAD_SUPPORT "MULTITHREADING SUPPORT" ${ZSTD_MULTITHREAD_SUPPORT_DEFAULT}) - -if (ZSTD_MULTITHREAD_SUPPORT) - message(STATUS "ZSTD_MULTITHREAD_SUPPORT is enabled") -else () - message(STATUS "ZSTD_MULTITHREAD_SUPPORT is disabled") -endif () - -option(ZSTD_BUILD_PROGRAMS "BUILD PROGRAMS" ON) -option(ZSTD_BUILD_CONTRIB "BUILD CONTRIB" OFF) - -# Respect the conventional CMake option for enabling tests if it was specified on the first configure -if (BUILD_TESTING) - set(ZSTD_BUILD_TESTS_default ON) -else() - set(ZSTD_BUILD_TESTS_default OFF) -endif() -option(ZSTD_BUILD_TESTS "BUILD TESTS" ${ZSTD_BUILD_TESTS_default}) -if (MSVC) - option(ZSTD_USE_STATIC_RUNTIME "LINK TO STATIC RUN-TIME LIBRARIES" OFF) -endif () - -# Enable C++ support for testing. -set(ZSTD_ENABLE_CXX ${ZSTD_BUILD_TESTS}) - -if(ZSTD_ENABLE_CXX) - enable_language(CXX) -endif() +include(ZstdOptions) #----------------------------------------------------------------------------- -# Add extra compilation flags +# Configure compilation flags #----------------------------------------------------------------------------- include(AddZstdCompilationFlags) -ADD_ZSTD_COMPILATION_FLAGS(ON ZSTD_ENABLE_CXX ON) # C CXX LD +ADD_ZSTD_COMPILATION_FLAGS(ON ZSTD_ENABLE_CXX ON) #----------------------------------------------------------------------------- -# External dependencies +# Configure dependencies #----------------------------------------------------------------------------- -# Define a function to handle special thread settings for HP-UX -# See https://github.com/facebook/zstd/pull/3862 for details. -function(setup_hpux_threads) - find_package(Threads) - if (NOT Threads_FOUND) - set(CMAKE_USE_PTHREADS_INIT 1 PARENT_SCOPE) - set(CMAKE_THREAD_LIBS_INIT -lpthread PARENT_SCOPE) - set(CMAKE_HAVE_THREADS_LIBRARY 1 PARENT_SCOPE) - set(Threads_FOUND TRUE PARENT_SCOPE) - endif() -endfunction() - -if (ZSTD_MULTITHREAD_SUPPORT AND UNIX) - if (CMAKE_SYSTEM_NAME MATCHES "HP-UX") - setup_hpux_threads() - else() - set(THREADS_PREFER_PTHREAD_FLAG ON) - find_package(Threads REQUIRED) - endif() - if (CMAKE_USE_PTHREADS_INIT) - set(THREADS_LIBS "${CMAKE_THREAD_LIBS_INIT}") - else() - message(SEND_ERROR "ZSTD currently does not support thread libraries other than pthreads") - endif() -endif () +include(ZstdDependencies) #----------------------------------------------------------------------------- -# Add source directories +# Configure build targets #----------------------------------------------------------------------------- -add_subdirectory(lib) - -option(ZSTD_PROGRAMS_LINK_SHARED "PROGRAMS LINK SHARED" OFF) - -if (ZSTD_BUILD_PROGRAMS) - if (NOT ZSTD_BUILD_STATIC AND NOT ZSTD_PROGRAMS_LINK_SHARED) - message(SEND_ERROR "You need to build static library to build zstd CLI") - elseif(NOT ZSTD_BUILD_SHARED AND ZSTD_PROGRAMS_LINK_SHARED) - message(SEND_ERROR "You need to build shared library to build zstd CLI") - endif () - - add_subdirectory(programs) -endif () - -if (ZSTD_BUILD_TESTS) - enable_testing() - if (NOT ZSTD_BUILD_STATIC) - message(SEND_ERROR "You need to build static library to build tests") - endif () - - add_subdirectory(tests) -endif () - -if (ZSTD_BUILD_CONTRIB) - add_subdirectory(contrib) -endif () +include(ZstdBuild) #----------------------------------------------------------------------------- -# Add clean-all target +# Configure package generation #----------------------------------------------------------------------------- -add_custom_target(clean-all - COMMAND ${CMAKE_BUILD_TOOL} clean - COMMAND rm -rf ${CMAKE_BINARY_DIR}/ -) - -#----------------------------------------------------------------------------- -# Generate Package Config files -# -# This section is based on the boiler plate code from: -# https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#creating-packages -#----------------------------------------------------------------------------- -include(CMakePackageConfigHelpers) -write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/zstdConfigVersion.cmake" - VERSION ${zstd_VERSION} - COMPATIBILITY SameMajorVersion - ) - -# A Package Config file that works from the build directory -export(EXPORT zstdExports - FILE "${CMAKE_CURRENT_BINARY_DIR}/zstdTargets.cmake" - NAMESPACE zstd:: - ) - -# A Package Config file that works from the installation directory -set(ConfigPackageLocation ${CMAKE_INSTALL_LIBDIR}/cmake/zstd) -install(EXPORT zstdExports - FILE zstdTargets.cmake - NAMESPACE zstd:: - DESTINATION ${ConfigPackageLocation} - ) -configure_package_config_file( - zstdConfig.cmake.in - "${CMAKE_CURRENT_BINARY_DIR}/zstdConfig.cmake" - INSTALL_DESTINATION ${ConfigPackageLocation} -) -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/zstdConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/zstdConfigVersion.cmake" - DESTINATION ${ConfigPackageLocation} - ) +include(ZstdPackage) diff --git a/build/cmake/CMakeModules/ZstdBuild.cmake b/build/cmake/CMakeModules/ZstdBuild.cmake new file mode 100644 index 000000000..ada44a966 --- /dev/null +++ b/build/cmake/CMakeModules/ZstdBuild.cmake @@ -0,0 +1,42 @@ +# ################################################################ +# ZSTD Build Targets Configuration +# ################################################################ + +# Always build the library first (this defines ZSTD_BUILD_STATIC/SHARED options) +add_subdirectory(lib) + +# Validate build configuration after lib options are defined +if(ZSTD_BUILD_PROGRAMS) + if(NOT ZSTD_BUILD_STATIC AND NOT ZSTD_PROGRAMS_LINK_SHARED) + message(SEND_ERROR "Static library required to build zstd CLI programs") + elseif(NOT ZSTD_BUILD_SHARED AND ZSTD_PROGRAMS_LINK_SHARED) + message(SEND_ERROR "Shared library required to build zstd CLI programs") + endif() +endif() + +if(ZSTD_BUILD_TESTS AND NOT ZSTD_BUILD_STATIC) + message(SEND_ERROR "Static library required to build test suite") +endif() + +# Add programs if requested +if(ZSTD_BUILD_PROGRAMS) + add_subdirectory(programs) +endif() + +# Add tests if requested +if(ZSTD_BUILD_TESTS) + enable_testing() + add_subdirectory(tests) +endif() + +# Add contrib utilities if requested +if(ZSTD_BUILD_CONTRIB) + add_subdirectory(contrib) +endif() + +# Clean-all target for thorough cleanup +add_custom_target(clean-all + COMMAND ${CMAKE_BUILD_TOOL} clean + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/ + COMMENT "Performing complete clean including build directory" +) diff --git a/build/cmake/CMakeModules/ZstdDependencies.cmake b/build/cmake/CMakeModules/ZstdDependencies.cmake new file mode 100644 index 000000000..4e90c5f1b --- /dev/null +++ b/build/cmake/CMakeModules/ZstdDependencies.cmake @@ -0,0 +1,30 @@ +# ################################################################ +# ZSTD Dependencies Configuration +# ################################################################ + +# Function to handle HP-UX thread configuration +function(setup_hpux_threads) + find_package(Threads) + if(NOT Threads_FOUND) + set(CMAKE_USE_PTHREADS_INIT 1 PARENT_SCOPE) + set(CMAKE_THREAD_LIBS_INIT -lpthread PARENT_SCOPE) + set(CMAKE_HAVE_THREADS_LIBRARY 1 PARENT_SCOPE) + set(Threads_FOUND TRUE PARENT_SCOPE) + endif() +endfunction() + +# Configure threading support +if(ZSTD_MULTITHREAD_SUPPORT AND UNIX) + if(CMAKE_SYSTEM_NAME MATCHES "HP-UX") + setup_hpux_threads() + else() + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + endif() + + if(CMAKE_USE_PTHREADS_INIT) + set(THREADS_LIBS "${CMAKE_THREAD_LIBS_INIT}") + else() + message(SEND_ERROR "ZSTD currently does not support thread libraries other than pthreads") + endif() +endif() diff --git a/build/cmake/CMakeModules/ZstdOptions.cmake b/build/cmake/CMakeModules/ZstdOptions.cmake new file mode 100644 index 000000000..3fca543a7 --- /dev/null +++ b/build/cmake/CMakeModules/ZstdOptions.cmake @@ -0,0 +1,68 @@ +# ################################################################ +# ZSTD Build Options Configuration +# ################################################################ + +# Legacy support configuration +option(ZSTD_LEGACY_SUPPORT "Enable legacy format support" ON) + +if(ZSTD_LEGACY_SUPPORT) + message(STATUS "ZSTD_LEGACY_SUPPORT enabled") + set(ZSTD_LEGACY_LEVEL 5 CACHE STRING "Legacy support level") + add_definitions(-DZSTD_LEGACY_SUPPORT=${ZSTD_LEGACY_LEVEL}) +else() + message(STATUS "ZSTD_LEGACY_SUPPORT disabled") + add_definitions(-DZSTD_LEGACY_SUPPORT=0) +endif() + +# Platform-specific options +if(APPLE) + option(ZSTD_FRAMEWORK "Build as Apple Framework" OFF) +endif() + +# Android-specific configuration +if(ANDROID) + set(ZSTD_MULTITHREAD_SUPPORT_DEFAULT OFF) + # Handle old Android API levels + if((NOT ANDROID_PLATFORM_LEVEL) OR (ANDROID_PLATFORM_LEVEL VERSION_LESS 24)) + message(STATUS "Configuring for old Android API - disabling fseeko/ftello") + add_compile_definitions(LIBC_NO_FSEEKO) + endif() +else() + set(ZSTD_MULTITHREAD_SUPPORT_DEFAULT ON) +endif() + +# Multi-threading support +option(ZSTD_MULTITHREAD_SUPPORT "Enable multi-threading support" ${ZSTD_MULTITHREAD_SUPPORT_DEFAULT}) + +if(ZSTD_MULTITHREAD_SUPPORT) + message(STATUS "Multi-threading support enabled") +else() + message(STATUS "Multi-threading support disabled") +endif() + +# Build component options +option(ZSTD_BUILD_PROGRAMS "Build command-line programs" ON) +option(ZSTD_BUILD_CONTRIB "Build contrib utilities" OFF) +option(ZSTD_PROGRAMS_LINK_SHARED "Link programs against shared library" OFF) + +# Test configuration +if(BUILD_TESTING) + set(ZSTD_BUILD_TESTS_default ON) +else() + set(ZSTD_BUILD_TESTS_default OFF) +endif() +option(ZSTD_BUILD_TESTS "Build test suite" ${ZSTD_BUILD_TESTS_default}) + +# MSVC-specific options +if(MSVC) + option(ZSTD_USE_STATIC_RUNTIME "Link to static runtime libraries" OFF) +endif() + +# C++ support (needed for tests) +set(ZSTD_ENABLE_CXX ${ZSTD_BUILD_TESTS}) +if(ZSTD_ENABLE_CXX) + enable_language(CXX) +endif() + +# Set global definitions +add_definitions(-DXXH_NAMESPACE=ZSTD_) diff --git a/build/cmake/CMakeModules/ZstdPackage.cmake b/build/cmake/CMakeModules/ZstdPackage.cmake new file mode 100644 index 000000000..5e40dd2c1 --- /dev/null +++ b/build/cmake/CMakeModules/ZstdPackage.cmake @@ -0,0 +1,42 @@ +# ################################################################ +# ZSTD Package Configuration +# ################################################################ + +include(CMakePackageConfigHelpers) + +# Generate version file +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/zstdConfigVersion.cmake" + VERSION ${zstd_VERSION} + COMPATIBILITY SameMajorVersion +) + +# Export targets for build directory +export(EXPORT zstdExports + FILE "${CMAKE_CURRENT_BINARY_DIR}/zstdTargets.cmake" + NAMESPACE zstd:: +) + +# Configure package for installation +set(ConfigPackageLocation ${CMAKE_INSTALL_LIBDIR}/cmake/zstd) + +# Install exported targets +install(EXPORT zstdExports + FILE zstdTargets.cmake + NAMESPACE zstd:: + DESTINATION ${ConfigPackageLocation} +) + +# Configure and install package config file +configure_package_config_file( + zstdConfig.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/zstdConfig.cmake" + INSTALL_DESTINATION ${ConfigPackageLocation} +) + +# Install config files +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/zstdConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/zstdConfigVersion.cmake" + DESTINATION ${ConfigPackageLocation} +) diff --git a/build/cmake/CMakeModules/ZstdVersion.cmake b/build/cmake/CMakeModules/ZstdVersion.cmake new file mode 100644 index 000000000..fceb0ec0c --- /dev/null +++ b/build/cmake/CMakeModules/ZstdVersion.cmake @@ -0,0 +1,31 @@ +# ################################################################ +# ZSTD Version Configuration +# ################################################################ + +# Setup CMake policy version +set(ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION "3") +set(ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION "13") + +# Determine appropriate policy version +if("${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}" EQUAL "${CMAKE_MAJOR_VERSION}" AND + "${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}" GREATER "${CMAKE_MINOR_VERSION}") + set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}") +else() + set(ZSTD_CMAKE_POLICY_VERSION "${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}.${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}.0") +endif() + +cmake_policy(VERSION ${ZSTD_CMAKE_POLICY_VERSION}) + +# Parse version from header file +include(GetZstdLibraryVersion) +GetZstdLibraryVersion(${LIBRARY_DIR}/zstd.h zstd_VERSION_MAJOR zstd_VERSION_MINOR zstd_VERSION_PATCH) + +# Set version variables +set(ZSTD_SHORT_VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}") +set(ZSTD_FULL_VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}") + +# Project metadata +set(zstd_HOMEPAGE_URL "https://facebook.github.io/zstd") +set(zstd_DESCRIPTION "Zstandard is a real-time compression algorithm, providing high compression ratios.") + +message(STATUS "ZSTD VERSION: ${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}") From b6dc2924f81a07c1833c255e9e2a0dabef5f3619 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 9 Jun 2025 06:47:28 +0000 Subject: [PATCH 109/245] remove fail-fast so that the outcome of other tests can be observed --- .github/workflows/cmake-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index f9212e254..b02385708 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -77,6 +77,7 @@ jobs: name: "CMake Windows VS2022 (${{ matrix.name }})" runs-on: ${{ matrix.runner }} strategy: + fail-fast: false matrix: include: - generator: "Visual Studio 17 2022" From 7e0324e124f0814fd6ffd1587f683313bcafe1f2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 9 Jun 2025 07:09:51 +0000 Subject: [PATCH 110/245] fixed cmake + windows + visual + clang-cl by removing processing of resource files in this case --- build/cmake/lib/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt index 0a93e8d31..a6b894c4d 100644 --- a/build/cmake/lib/CMakeLists.txt +++ b/build/cmake/lib/CMakeLists.txt @@ -97,9 +97,11 @@ if (ZSTD_LEGACY_SUPPORT) ${LIBRARY_LEGACY_DIR}/zstd_v07.h) endif () -if (MSVC) +if (MSVC AND NOT (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")) set(MSVC_RESOURCE_DIR ${ZSTD_SOURCE_DIR}/build/VS2010/libzstd-dll) set(PlatformDependResources ${MSVC_RESOURCE_DIR}/libzstd-dll.rc) +else() + set(PlatformDependResources) endif () # Explicitly set the language to C for all files, including ASM files. From 472acf5d83e0f059c0d5938dea6556e21385a71c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 9 Jun 2025 07:24:03 +0000 Subject: [PATCH 111/245] fix #4405 --- build/cmake/CMakeModules/AddZstdCompilationFlags.cmake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake b/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake index 25231b5ec..dbe4118eb 100644 --- a/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake +++ b/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake @@ -1,5 +1,10 @@ -include(CheckCXXCompilerFlag) include(CheckCCompilerFlag) +if(CMAKE_CXX_COMPILER) + include(CheckCXXCompilerFlag) + set(ZSTD_CXX_ENABLED TRUE) +else() + set(ZSTD_CXX_ENABLED FALSE) +endif() if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18) set(ZSTD_HAVE_CHECK_LINKER_FLAG true) @@ -21,7 +26,7 @@ function(EnableCompilerFlag _flag _C _CXX _LD) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_flag}" PARENT_SCOPE) endif () endif () - if (_CXX) + if (_CXX AND ZSTD_CXX_ENABLED) CHECK_CXX_COMPILER_FLAG(${_flag} CXX_FLAG_${varname}) if (CXX_FLAG_${varname}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flag}" PARENT_SCOPE) From de8d9e8914fbc26cb7d4e864429b906744514a38 Mon Sep 17 00:00:00 2001 From: shixuantong Date: Sun, 1 Jun 2025 00:37:57 +0800 Subject: [PATCH 112/245] Fix several locations with potential memory leak --- .../seekable_format/tests/seekable_tests.c | 12 +++ programs/util.c | 1 + tests/bigdict.c | 78 +++++++++++------ tests/largeDictionary.c | 85 +++++++++++++------ tests/legacy.c | 2 + tests/longmatch.c | 55 ++++++++---- 6 files changed, 162 insertions(+), 71 deletions(-) diff --git a/contrib/seekable_format/tests/seekable_tests.c b/contrib/seekable_format/tests/seekable_tests.c index f89bdc930..809ea6425 100644 --- a/contrib/seekable_format/tests/seekable_tests.c +++ b/contrib/seekable_format/tests/seekable_tests.c @@ -316,6 +316,10 @@ int main(int argc, const char** argv) for (pos = 0; pos < inSize; pos += 2) { size_t const decStatus = ZSTD_seekable_decompress(stream, outBuffer, 1, pos); if (decStatus != 1 || outBuffer[0] != inBuffer[pos]) { + free(seekBuffer); + free(outBuffer); + ZSTD_seekable_freeCStream(zscs); + ZSTD_seekable_free(stream); goto _test_error; } } @@ -323,6 +327,10 @@ int main(int argc, const char** argv) /* We read more than the compressed size, meaning there were some rereads. This is unneeded because we only seeked forward. */ printf("Too much data read: %zu read, with compressed size %zu\n", buffWrapper.totalRead, seekSize); + free(seekBuffer); + free(outBuffer); + ZSTD_seekable_freeCStream(zscs); + ZSTD_seekable_free(stream); goto _test_error; } @@ -342,6 +350,10 @@ int main(int argc, const char** argv) for (idx = 0; idx < sizeof(tests) / sizeof(tests[0]); idx++) { size_t const decStatus = ZSTD_seekable_decompress(stream, outBuffer, tests[idx].size, tests[idx].offset); if (decStatus != tests[idx].size || memcmp(outBuffer, inBuffer + tests[idx].offset, tests[idx].size) != 0) { + free(seekBuffer); + free(outBuffer); + ZSTD_seekable_freeCStream(zscs); + ZSTD_seekable_free(stream); goto _test_error; } } diff --git a/programs/util.c b/programs/util.c index d11f13cfd..652530b12 100644 --- a/programs/util.c +++ b/programs/util.c @@ -928,6 +928,7 @@ static int UTIL_prepareFileList(const char* dirName, hFile=FindFirstFileA(path, &cFile); if (hFile == INVALID_HANDLE_VALUE) { UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s'\n", dirName); + free(path); return 0; } free(path); diff --git a/tests/bigdict.c b/tests/bigdict.c index 748b60e79..230e5b979 100644 --- a/tests/bigdict.c +++ b/tests/bigdict.c @@ -80,29 +80,51 @@ int main(int argc, const char** argv) goto cleanup; } - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 31))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 1))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_overlapLog, 9))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, ZSTD_btopt))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, 7))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 7))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, 1))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, 10))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, 10))) - return 1; + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 31))) { + _exit_code = 1; + goto cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 1))) { + _exit_code = 1; + goto cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_overlapLog, 9))) { + _exit_code = 1; + goto cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1))) { + _exit_code = 1; + goto cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, ZSTD_btopt))) { + _exit_code = 1; + goto cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, 7))) { + _exit_code = 1; + goto cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 7))) { + _exit_code = 1; + goto cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, 1))) { + _exit_code = 1; + goto cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, 10))) { + _exit_code = 1; + goto cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, 10))) { + _exit_code = 1; + goto cleanup; + } - if (ZSTD_isError(ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, 31))) - return 1; + if (ZSTD_isError(ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, 31))) { + _exit_code = 1; + goto cleanup; + } RDG_genBuffer(buffer, bufferSize, 1.0, 0.0, 0xbeefcafe); @@ -111,13 +133,17 @@ int main(int argc, const char** argv) int i; for (i = 0; i < 10; ++i) { fprintf(stderr, "Compressing 1 GB\n"); - if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_continue)) - return 1; + if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_continue)) { + _exit_code = 1; + goto cleanup; + } } } fprintf(stderr, "Compressing 1 GB\n"); - if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_end)) - return 1; + if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_end)) { + _exit_code = 1; + goto cleanup; + } fprintf(stderr, "Success!\n"); diff --git a/tests/largeDictionary.c b/tests/largeDictionary.c index ff2bb2d70..a3b96135f 100644 --- a/tests/largeDictionary.c +++ b/tests/largeDictionary.c @@ -72,35 +72,59 @@ int main(int argc, const char** argv) void* roundtrip = malloc(dataSize); (void)argc; (void)argv; + int _exit_code = 0; if (!buffer || !out || !roundtrip || !cctx || !dctx) { fprintf(stderr, "Allocation failure\n"); - return 1; + _exit_code = 1; + goto _cleanup; } - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 31))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 1))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_overlapLog, 9))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, ZSTD_btopt))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, 7))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 7))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, 1))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, 10))) - return 1; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, 10))) - return 1; + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 31))) { + _exit_code = 1; + goto _cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 1))) { + _exit_code = 1; + goto _cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_overlapLog, 9))) { + _exit_code = 1; + goto _cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1))) { + _exit_code = 1; + goto _cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, ZSTD_btopt))) { + _exit_code = 1; + goto _cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, 7))) { + _exit_code = 1; + goto _cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 7))) { + _exit_code = 1; + goto _cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, 1))) { + _exit_code = 1; + goto _cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, 10))) { + _exit_code = 1; + goto _cleanup; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, 10))) { + _exit_code = 1; + goto _cleanup; + } - if (ZSTD_isError(ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, 31))) - return 1; + if (ZSTD_isError(ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, 31))) { + _exit_code = 1; + goto _cleanup; + } RDG_genBuffer(buffer, bufferSize, 1.0, 0.0, 0xbeefcafe); @@ -109,20 +133,25 @@ int main(int argc, const char** argv) int i; for (i = 0; i < 10; ++i) { fprintf(stderr, "Compressing 1 GB\n"); - if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_continue)) - return 1; + if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_continue)) { + _exit_code = 1; + goto _cleanup; + } } } fprintf(stderr, "Compressing 1 GB\n"); - if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_end)) - return 1; + if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_end)) { + _exit_code = 1; + goto _cleanup; + } fprintf(stderr, "Success!\n"); +_cleanup: free(roundtrip); free(out); free(buffer); ZSTD_freeDCtx(dctx); ZSTD_freeCCtx(cctx); - return 0; + return _exit_code; } diff --git a/tests/legacy.c b/tests/legacy.c index 3be386495..8fe291c5a 100644 --- a/tests/legacy.c +++ b/tests/legacy.c @@ -56,6 +56,7 @@ static int testSimpleAPI(void) } else { DISPLAY("ERROR: %s\n", ZSTD_getErrorName(ret)); } + free(output); return 1; } if (ret != size) { @@ -64,6 +65,7 @@ static int testSimpleAPI(void) } if (memcmp(EXPECTED, output, size) != 0) { DISPLAY("ERROR: Wrong decoded output produced\n"); + free(output); return 1; } diff --git a/tests/longmatch.c b/tests/longmatch.c index 547b26190..8e4e51dc1 100644 --- a/tests/longmatch.c +++ b/tests/longmatch.c @@ -39,24 +39,39 @@ int main(int argc, const char** argv) unsigned windowLog = 18; (void)argc; (void)argv; + int _exit_code = 0; /* Create stream */ ctx = ZSTD_createCCtx(); if (!ctx) { return 1; } /* Set parameters */ - if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_windowLog, windowLog))) - return 2; - if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_chainLog, 13))) - return 2; - if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_hashLog, 14))) - return 2; - if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_searchLog, 1))) - return 2; - if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_minMatch, 7))) - return 2; - if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_targetLength, 16))) - return 2; - if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_strategy, ZSTD_fast))) - return 2; + if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_windowLog, windowLog))) { + _exit_code = 2; + goto _clean_ctx; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_chainLog, 13))) { + _exit_code = 2; + goto _clean_ctx; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_hashLog, 14))) { + _exit_code = 2; + goto _clean_ctx; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_searchLog, 1))) { + _exit_code = 2; + goto _clean_ctx; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_minMatch, 7))) { + _exit_code = 2; + goto _clean_ctx; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_targetLength, 16))) { + _exit_code = 2; + goto _clean_ctx; + } + if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_strategy, ZSTD_fast))) { + _exit_code = 2; + goto _clean_ctx; + } { U64 compressed = 0; const U64 toCompress = ((U64)1) << 33; @@ -81,22 +96,28 @@ int main(int argc, const char** argv) } printf("Compressing, trying to generate a segfault \n"); if (compress(ctx, out, srcBuffer, size)) { - return 1; + _exit_code = 1; + goto _clean_buffer; } compressed += size; while (compressed < toCompress) { const size_t block = rand() % (size - pos + 1); if (pos == size) { pos = 0; } if (compress(ctx, out, srcBuffer + pos, block)) { - return 1; + _exit_code = 1; + goto _clean_buffer; } pos += block; compressed += block; } printf("Compression completed successfully (no error triggered)\n"); + +_clean_buffer: free(srcBuffer); free(dstBuffer); } + +_clean_ctx: ZSTD_freeCCtx(ctx); - return 0; + return _exit_code; } From 9a6fe9a428751b82be76cdf010cf89aae64897ce Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 9 Jun 2025 21:55:06 +0000 Subject: [PATCH 113/245] remove global variable overkill and leaky to transport a test result just in one place. --- build/cmake/CMakeModules/AddZstdCompilationFlags.cmake | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake b/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake index dbe4118eb..3e7bcce59 100644 --- a/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake +++ b/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake @@ -1,9 +1,6 @@ include(CheckCCompilerFlag) if(CMAKE_CXX_COMPILER) include(CheckCXXCompilerFlag) - set(ZSTD_CXX_ENABLED TRUE) -else() - set(ZSTD_CXX_ENABLED FALSE) endif() if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18) @@ -26,7 +23,7 @@ function(EnableCompilerFlag _flag _C _CXX _LD) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_flag}" PARENT_SCOPE) endif () endif () - if (_CXX AND ZSTD_CXX_ENABLED) + if (_CXX AND CMAKE_CXX_COMPILER) CHECK_CXX_COMPILER_FLAG(${_flag} CXX_FLAG_${varname}) if (CXX_FLAG_${varname}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flag}" PARENT_SCOPE) From 7e4937bc7533914370be181234384650cf519b53 Mon Sep 17 00:00:00 2001 From: Arpad Panyik Date: Wed, 11 Jun 2025 12:14:22 +0000 Subject: [PATCH 114/245] AArch64: Add SVE2 implementation of histogram computation The existing scalar implementation uses a 4-way pipelined histogram calculation which is very efficient on out-of-order CPUs. However, this can be further accelerated using the SVE2 HISTSEG instructions - which compute a histogram for 16 byte chunks in a vector register. On a system with 128-bit vectors (VL128) we need 16 HISTSEG executions to compute the histogram for the whole symbol space (0..255) of 16 bytes input. However we can only accumulate 15 of such 16 byte strips before possible overflow. So we need to extend and save the 8-bit histogram accumulators to 16-bit after every 240 byte chunks of input. To store all in registers we would need 32 128-bit registers. Longer SVE2 vectors could help here, if such machines become available. The maximum input block size in Zstd is 128 KiB, so 16-bit accumulators would not be enough. However an LZ pass will prepend the histogram calculation, so it is impossible (my assumption) to overflow the 16-bit accumulators. The symbol distribution is also not uniform, the lower values are more common, so we used a 3 pass algorithm to prevent stack spilling. In the first pass we only compute histograms for 64 symbols (4-way SIMD) while also computing the maximum symbol value. If we have symbol values larger than 64 we start the second pass to compute the next 96 elements of the histogram. The final pass calculates the remaining part of the histogram (256 symbols in total) if needed. This split of histogram generation gave the best overall results for performance. This implementation is the best performing of a number of different cache blocking schemes tested. Compression uplifts on a Neoverse V2 system, using Zstd-1.5.8 (e26dde3d) as a baseline, compiled with "-O3 -march=armv8.2-a+sve2": Clang-20 GCC-14 1#silesia.tar: +6.173% +5.987% 2#silesia.tar: +5.200% +5.011% 3#silesia.tar: +4.332% +5.031% 4#silesia.tar: +2.789% +3.064% 5#silesia.tar: +2.028% +1.838% 6#silesia.tar: +1.562% +1.340% 7#silesia.tar: +1.160% +0.959% --- lib/common/compiler.h | 9 ++ lib/compress/hist.c | 261 +++++++++++++++++++++++++++++++++++++++++- lib/compress/hist.h | 4 + 3 files changed, 271 insertions(+), 3 deletions(-) diff --git a/lib/common/compiler.h b/lib/common/compiler.h index cafb35b71..6131ad068 100644 --- a/lib/common/compiler.h +++ b/lib/common/compiler.h @@ -218,6 +218,12 @@ # if defined(__ARM_NEON) || defined(_M_ARM64) # define ZSTD_ARCH_ARM_NEON # endif +# if defined(__ARM_FEATURE_SVE) +# define ZSTD_ARCH_ARM_SVE +# endif +# if defined(__ARM_FEATURE_SVE2) +# define ZSTD_ARCH_ARM_SVE2 +# endif # if defined(__riscv) && defined(__riscv_vector) # define ZSTD_ARCH_RISCV_RVV # endif @@ -230,6 +236,9 @@ # elif defined(ZSTD_ARCH_ARM_NEON) # include # endif +# if defined(ZSTD_ARCH_ARM_SVE) || defined(ZSTD_ARCH_ARM_SVE2) +# include +# endif # if defined(ZSTD_ARCH_RISCV_RVV) # include # endif diff --git a/lib/compress/hist.c b/lib/compress/hist.c index 4ccf9a90a..3692bc250 100644 --- a/lib/compress/hist.c +++ b/lib/compress/hist.c @@ -19,6 +19,12 @@ #include "../common/error_private.h" /* ERROR */ #include "hist.h" +#if defined(ZSTD_ARCH_ARM_SVE2) +#define HIST_FAST_THRESHOLD 500 +#else +#define HIST_FAST_THRESHOLD 1500 +#endif + /* --- Error management --- */ unsigned HIST_isError(size_t code) { return ERR_isError(code); } @@ -65,6 +71,244 @@ unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, typedef enum { trustInput, checkMaxSymbolValue } HIST_checkInput_e; +#if defined(ZSTD_ARCH_ARM_SVE2) +FORCE_INLINE_TEMPLATE size_t min_size(size_t a, size_t b) { return a < b ? a : b; } + +static +svuint16_t HIST_count_6_sve2(const BYTE* const src, size_t size, U32* const dst, + const svuint8_t c0, const svuint8_t c1, + const svuint8_t c2, const svuint8_t c3, + const svuint8_t c4, const svuint8_t c5, + const svuint16_t histmax, size_t maxCount) +{ + const svbool_t vl128 = svptrue_pat_b8(SV_VL16); + svuint16_t hh0 = svdup_n_u16(0); + svuint16_t hh1 = svdup_n_u16(0); + svuint16_t hh2 = svdup_n_u16(0); + svuint16_t hh3 = svdup_n_u16(0); + svuint16_t hh4 = svdup_n_u16(0); + svuint16_t hh5 = svdup_n_u16(0); + svuint16_t hh6 = svdup_n_u16(0); + svuint16_t hh7 = svdup_n_u16(0); + svuint16_t hh8 = svdup_n_u16(0); + svuint16_t hh9 = svdup_n_u16(0); + svuint16_t hha = svdup_n_u16(0); + svuint16_t hhb = svdup_n_u16(0); + + size_t i = 0; + while (i < size) { + /* We can only accumulate 15 (15 * 16 <= 255) iterations of histogram + * in 8-bit accumulators! */ + const size_t size240 = min_size(i + 240, size); + + svbool_t pred = svwhilelt_b8_u64(i, size); + svuint8_t c = svld1rq_u8(pred, src + i); + svuint8_t h0 = svhistseg_u8(c0, c); + svuint8_t h1 = svhistseg_u8(c1, c); + svuint8_t h2 = svhistseg_u8(c2, c); + svuint8_t h3 = svhistseg_u8(c3, c); + svuint8_t h4 = svhistseg_u8(c4, c); + svuint8_t h5 = svhistseg_u8(c5, c); + + for (i += 16; i < size240; i += 16) { + pred = svwhilelt_b8_u64(i, size); + c = svld1rq_u8(pred, src + i); + h0 = svadd_u8_x(vl128, h0, svhistseg_u8(c0, c)); + h1 = svadd_u8_x(vl128, h1, svhistseg_u8(c1, c)); + h2 = svadd_u8_x(vl128, h2, svhistseg_u8(c2, c)); + h3 = svadd_u8_x(vl128, h3, svhistseg_u8(c3, c)); + h4 = svadd_u8_x(vl128, h4, svhistseg_u8(c4, c)); + h5 = svadd_u8_x(vl128, h5, svhistseg_u8(c5, c)); + } + + hh0 = svaddwb_u16(hh0, h0); + hh1 = svaddwt_u16(hh1, h0); + hh2 = svaddwb_u16(hh2, h1); + hh3 = svaddwt_u16(hh3, h1); + hh4 = svaddwb_u16(hh4, h2); + hh5 = svaddwt_u16(hh5, h2); + hh6 = svaddwb_u16(hh6, h3); + hh7 = svaddwt_u16(hh7, h3); + hh8 = svaddwb_u16(hh8, h4); + hh9 = svaddwt_u16(hh9, h4); + hha = svaddwb_u16(hha, h5); + hhb = svaddwt_u16(hhb, h5); + } + + svst1_u32(svwhilelt_b32_u64( 0, maxCount), dst + 0, svshllb_n_u32(hh0, 0)); + svst1_u32(svwhilelt_b32_u64( 4, maxCount), dst + 4, svshllt_n_u32(hh0, 0)); + svst1_u32(svwhilelt_b32_u64( 8, maxCount), dst + 8, svshllb_n_u32(hh1, 0)); + svst1_u32(svwhilelt_b32_u64(12, maxCount), dst + 12, svshllt_n_u32(hh1, 0)); + svst1_u32(svwhilelt_b32_u64(16, maxCount), dst + 16, svshllb_n_u32(hh2, 0)); + svst1_u32(svwhilelt_b32_u64(20, maxCount), dst + 20, svshllt_n_u32(hh2, 0)); + svst1_u32(svwhilelt_b32_u64(24, maxCount), dst + 24, svshllb_n_u32(hh3, 0)); + svst1_u32(svwhilelt_b32_u64(28, maxCount), dst + 28, svshllt_n_u32(hh3, 0)); + svst1_u32(svwhilelt_b32_u64(32, maxCount), dst + 32, svshllb_n_u32(hh4, 0)); + svst1_u32(svwhilelt_b32_u64(36, maxCount), dst + 36, svshllt_n_u32(hh4, 0)); + svst1_u32(svwhilelt_b32_u64(40, maxCount), dst + 40, svshllb_n_u32(hh5, 0)); + svst1_u32(svwhilelt_b32_u64(44, maxCount), dst + 44, svshllt_n_u32(hh5, 0)); + svst1_u32(svwhilelt_b32_u64(48, maxCount), dst + 48, svshllb_n_u32(hh6, 0)); + svst1_u32(svwhilelt_b32_u64(52, maxCount), dst + 52, svshllt_n_u32(hh6, 0)); + svst1_u32(svwhilelt_b32_u64(56, maxCount), dst + 56, svshllb_n_u32(hh7, 0)); + svst1_u32(svwhilelt_b32_u64(60, maxCount), dst + 60, svshllt_n_u32(hh7, 0)); + svst1_u32(svwhilelt_b32_u64(64, maxCount), dst + 64, svshllb_n_u32(hh8, 0)); + svst1_u32(svwhilelt_b32_u64(68, maxCount), dst + 68, svshllt_n_u32(hh8, 0)); + svst1_u32(svwhilelt_b32_u64(72, maxCount), dst + 72, svshllb_n_u32(hh9, 0)); + svst1_u32(svwhilelt_b32_u64(76, maxCount), dst + 76, svshllt_n_u32(hh9, 0)); + svst1_u32(svwhilelt_b32_u64(80, maxCount), dst + 80, svshllb_n_u32(hha, 0)); + svst1_u32(svwhilelt_b32_u64(84, maxCount), dst + 84, svshllt_n_u32(hha, 0)); + svst1_u32(svwhilelt_b32_u64(88, maxCount), dst + 88, svshllb_n_u32(hhb, 0)); + svst1_u32(svwhilelt_b32_u64(92, maxCount), dst + 92, svshllt_n_u32(hhb, 0)); + + hh0 = svmax_u16_x(vl128, hh0, hh1); + hh2 = svmax_u16_x(vl128, hh2, hh3); + hh4 = svmax_u16_x(vl128, hh4, hh5); + hh6 = svmax_u16_x(vl128, hh6, hh7); + hh8 = svmax_u16_x(vl128, hh8, hh9); + hha = svmax_u16_x(vl128, hha, hhb); + hh0 = svmax_u16_x(vl128, hh0, hh2); + hh4 = svmax_u16_x(vl128, hh4, hh6); + hh8 = svmax_u16_x(vl128, hh8, hha); + hh0 = svmax_u16_x(vl128, hh0, hh4); + hh8 = svmax_u16_x(vl128, hh8, histmax); + return svmax_u16_x(vl128, hh0, hh8); +} + +static size_t HIST_count_sve2(unsigned* count, unsigned* maxSymbolValuePtr, + const void* source, size_t sourceSize, + HIST_checkInput_e check) +{ + const BYTE* ip = (const BYTE*)source; + const size_t maxCount = *maxSymbolValuePtr + 1; + + assert(*maxSymbolValuePtr <= 255); + if (!sourceSize) { + ZSTD_memset(count, 0, maxCount * sizeof(*count)); + *maxSymbolValuePtr = 0; + return 0; + } + + { const svbool_t vl128 = svptrue_pat_b8(SV_VL16); + const svuint8_t c0 = svreinterpret_u8(svindex_u32(0x0C040800, 0x01010101)); + const svuint8_t c1 = svadd_n_u8_x(vl128, c0, 16); + const svuint8_t c2 = svadd_n_u8_x(vl128, c0, 32); + const svuint8_t c3 = svadd_n_u8_x(vl128, c1, 32); + + svuint8_t symbolMax = svdup_n_u8(0); + svuint16_t hh0 = svdup_n_u16(0); + svuint16_t hh1 = svdup_n_u16(0); + svuint16_t hh2 = svdup_n_u16(0); + svuint16_t hh3 = svdup_n_u16(0); + svuint16_t hh4 = svdup_n_u16(0); + svuint16_t hh5 = svdup_n_u16(0); + svuint16_t hh6 = svdup_n_u16(0); + svuint16_t hh7 = svdup_n_u16(0); + svuint16_t max; + size_t maxSymbolValue; + + size_t i = 0; + while (i < sourceSize) { + /* We can only accumulate 15 (15 * 16 <= 255) iterations of + * histogram in 8-bit accumulators! */ + const size_t size240 = min_size(i + 240, sourceSize); + + svbool_t pred = svwhilelt_b8_u64(i, sourceSize); + svuint8_t c = svld1rq_u8(pred, ip + i); + svuint8_t h0 = svhistseg_u8(c0, c); + svuint8_t h1 = svhistseg_u8(c1, c); + svuint8_t h2 = svhistseg_u8(c2, c); + svuint8_t h3 = svhistseg_u8(c3, c); + symbolMax = svmax_u8_x(vl128, symbolMax, c); + + for (i += 16; i < size240; i += 16) { + pred = svwhilelt_b8_u64(i, sourceSize); + c = svld1rq_u8(pred, ip + i); + h0 = svadd_u8_x(vl128, h0, svhistseg_u8(c0, c)); + h1 = svadd_u8_x(vl128, h1, svhistseg_u8(c1, c)); + h2 = svadd_u8_x(vl128, h2, svhistseg_u8(c2, c)); + h3 = svadd_u8_x(vl128, h3, svhistseg_u8(c3, c)); + symbolMax = svmax_u8_x(vl128, symbolMax, c); + } + + hh0 = svaddwb_u16(hh0, h0); + hh1 = svaddwt_u16(hh1, h0); + hh2 = svaddwb_u16(hh2, h1); + hh3 = svaddwt_u16(hh3, h1); + hh4 = svaddwb_u16(hh4, h2); + hh5 = svaddwt_u16(hh5, h2); + hh6 = svaddwb_u16(hh6, h3); + hh7 = svaddwt_u16(hh7, h3); + } + maxSymbolValue = svmaxv_u8(vl128, symbolMax); + + if (check && maxSymbolValue > *maxSymbolValuePtr) return ERROR(maxSymbolValue_tooSmall); + *maxSymbolValuePtr = maxSymbolValue; + + /* If the buffer size is not divisible by 16, the last elements of the final + * vector register read will be zeros, and these elements must be subtracted + * from the histogram. + */ + hh0 = svsub_n_u16_m(svptrue_pat_b32(SV_VL1), hh0, -sourceSize & 15); + + svst1_u32(svwhilelt_b32_u64( 0, maxCount), count + 0, svshllb_n_u32(hh0, 0)); + svst1_u32(svwhilelt_b32_u64( 4, maxCount), count + 4, svshllt_n_u32(hh0, 0)); + svst1_u32(svwhilelt_b32_u64( 8, maxCount), count + 8, svshllb_n_u32(hh1, 0)); + svst1_u32(svwhilelt_b32_u64(12, maxCount), count + 12, svshllt_n_u32(hh1, 0)); + svst1_u32(svwhilelt_b32_u64(16, maxCount), count + 16, svshllb_n_u32(hh2, 0)); + svst1_u32(svwhilelt_b32_u64(20, maxCount), count + 20, svshllt_n_u32(hh2, 0)); + svst1_u32(svwhilelt_b32_u64(24, maxCount), count + 24, svshllb_n_u32(hh3, 0)); + svst1_u32(svwhilelt_b32_u64(28, maxCount), count + 28, svshllt_n_u32(hh3, 0)); + svst1_u32(svwhilelt_b32_u64(32, maxCount), count + 32, svshllb_n_u32(hh4, 0)); + svst1_u32(svwhilelt_b32_u64(36, maxCount), count + 36, svshllt_n_u32(hh4, 0)); + svst1_u32(svwhilelt_b32_u64(40, maxCount), count + 40, svshllb_n_u32(hh5, 0)); + svst1_u32(svwhilelt_b32_u64(44, maxCount), count + 44, svshllt_n_u32(hh5, 0)); + svst1_u32(svwhilelt_b32_u64(48, maxCount), count + 48, svshllb_n_u32(hh6, 0)); + svst1_u32(svwhilelt_b32_u64(52, maxCount), count + 52, svshllt_n_u32(hh6, 0)); + svst1_u32(svwhilelt_b32_u64(56, maxCount), count + 56, svshllb_n_u32(hh7, 0)); + svst1_u32(svwhilelt_b32_u64(60, maxCount), count + 60, svshllt_n_u32(hh7, 0)); + + hh0 = svmax_u16_x(vl128, hh0, hh1); + hh2 = svmax_u16_x(vl128, hh2, hh3); + hh4 = svmax_u16_x(vl128, hh4, hh5); + hh6 = svmax_u16_x(vl128, hh6, hh7); + hh0 = svmax_u16_x(vl128, hh0, hh2); + hh4 = svmax_u16_x(vl128, hh4, hh6); + max = svmax_u16_x(vl128, hh0, hh4); + + maxSymbolValue = min_size(maxSymbolValue, maxCount); + if (maxSymbolValue >= 64) { + const svuint8_t c4 = svadd_n_u8_x(vl128, c0, 64); + const svuint8_t c5 = svadd_n_u8_x(vl128, c1, 64); + const svuint8_t c6 = svadd_n_u8_x(vl128, c2, 64); + const svuint8_t c7 = svadd_n_u8_x(vl128, c3, 64); + const svuint8_t c8 = svadd_n_u8_x(vl128, c0, 128); + const svuint8_t c9 = svadd_n_u8_x(vl128, c1, 128); + + max = HIST_count_6_sve2(ip, sourceSize, count + 64, c4, c5, c6, c7, + c8, c9, max, maxCount - 64); + + if (maxSymbolValue >= 160) { + const svuint8_t ca = svadd_n_u8_x(vl128, c2, 128); + const svuint8_t cb = svadd_n_u8_x(vl128, c3, 128); + const svuint8_t cc = svadd_n_u8_x(vl128, c4, 128); + const svuint8_t cd = svadd_n_u8_x(vl128, c5, 128); + const svuint8_t ce = svadd_n_u8_x(vl128, c6, 128); + const svuint8_t cf = svadd_n_u8_x(vl128, c7, 128); + + max = HIST_count_6_sve2(ip, sourceSize, count + 160, ca, cb, cc, + cd, ce, cf, max, maxCount - 160); + } else if (maxCount > 160) { + ZSTD_memset(count + 160, 0, (maxCount - 160) * sizeof(*count)); + } + } else if (maxCount > 64) { + ZSTD_memset(count + 64, 0, (maxCount - 64) * sizeof(*count)); + } + + return svmaxv_u16(vl128, max); + } +} +#endif + /* HIST_count_parallel_wksp() : * store histogram into 4 intermediate tables, recombined at the end. * this design makes better use of OoO cpus, @@ -73,8 +317,8 @@ typedef enum { trustInput, checkMaxSymbolValue } HIST_checkInput_e; * `workSpace` must be a U32 table of size >= HIST_WKSP_SIZE_U32. * @return : largest histogram frequency, * or an error code (notably when histogram's alphabet is larger than *maxSymbolValuePtr) */ -static size_t HIST_count_parallel_wksp( - unsigned* count, unsigned* maxSymbolValuePtr, +static UNUSED_ATTR +size_t HIST_count_parallel_wksp(unsigned* count, unsigned* maxSymbolValuePtr, const void* source, size_t sourceSize, HIST_checkInput_e check, U32* const workSpace) @@ -151,11 +395,17 @@ size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, const void* source, size_t sourceSize, void* workSpace, size_t workSpaceSize) { - if (sourceSize < 1500) /* heuristic threshold */ + if (sourceSize < HIST_FAST_THRESHOLD) /* heuristic threshold */ return HIST_count_simple(count, maxSymbolValuePtr, source, sourceSize); +#if defined(ZSTD_ARCH_ARM_SVE2) + (void)workSpace; + (void)workSpaceSize; + return HIST_count_sve2(count, maxSymbolValuePtr, source, sourceSize, trustInput); +#else if ((size_t)workSpace & 3) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall); return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace); +#endif } /* HIST_count_wksp() : @@ -165,10 +415,15 @@ size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr, const void* source, size_t sourceSize, void* workSpace, size_t workSpaceSize) { +#if defined(ZSTD_ARCH_ARM_SVE2) + if (*maxSymbolValuePtr < 255) + return HIST_count_sve2(count, maxSymbolValuePtr, source, sourceSize, checkMaxSymbolValue); +#else if ((size_t)workSpace & 3) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ if (workSpaceSize < HIST_WKSP_SIZE) return ERROR(workSpace_tooSmall); if (*maxSymbolValuePtr < 255) return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, checkMaxSymbolValue, (U32*)workSpace); +#endif *maxSymbolValuePtr = 255; return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize); } diff --git a/lib/compress/hist.h b/lib/compress/hist.h index bea2a9ebf..e526e9532 100644 --- a/lib/compress/hist.h +++ b/lib/compress/hist.h @@ -35,7 +35,11 @@ unsigned HIST_isError(size_t code); /**< tells if a return value is an error co /* --- advanced histogram functions --- */ +#if defined(__ARM_FEATURE_SVE2) +#define HIST_WKSP_SIZE_U32 0 +#else #define HIST_WKSP_SIZE_U32 1024 +#endif #define HIST_WKSP_SIZE (HIST_WKSP_SIZE_U32 * sizeof(unsigned)) /** HIST_count_wksp() : * Same as HIST_count(), but using an externally provided scratch buffer. From cad0b72ad8ca6d413843af453e274750ba717012 Mon Sep 17 00:00:00 2001 From: jinyaoguo Date: Thu, 12 Jun 2025 19:52:58 -0400 Subject: [PATCH 115/245] Ensure BMK_timedFnState is always freed in benchMem When an error occurs in BMK_isSuccessful_runOutcome, the code previously skipped the call to BMK_freeTimedFnState(tfs), leaking the allocated tfs object. Fiexed by calling BMK_freeTimedFnState(tfs) before goto _cleanOut. --- tests/fullbench.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/fullbench.c b/tests/fullbench.c index 12a27f48c..5841e5db5 100644 --- a/tests/fullbench.c +++ b/tests/fullbench.c @@ -890,6 +890,7 @@ static int benchMem(unsigned scenarioID, if (!BMK_isSuccessful_runOutcome(bOutcome)) { DISPLAY("ERROR: Scenario %u: %s \n", scenarioID, ZSTD_getErrorName(BMK_extract_errorResult(bOutcome))); errorcode = 1; + BMK_freeTimedFnState(tfs); goto _cleanOut; } From d28a7377505087174a5d3b259a232b8ab7f0cb60 Mon Sep 17 00:00:00 2001 From: Arpad Panyik Date: Wed, 11 Jun 2025 12:19:42 +0000 Subject: [PATCH 116/245] Add unit tests for HIST_count_wksp The following tests are included: - Empty input scenario test. - Workspace size and alignment tests. - Symbol out-of-range tests. - Cover multiple input sizes, vary permitted maximum symbol values, and include diverse symbol distributions. These tests verifies count table correctness, maxSymbolValuePtr updates, and error-handling paths. It enables automated regression of core histogram logic as well. --- .github/workflows/dev-short-tests.yml | 2 + tests/cli-tests/run.py | 2 +- tests/fuzzer.c | 126 ++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 8e8753658..31d44542f 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -435,6 +435,8 @@ jobs: make clean LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j check LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j -C tests test-cli-tests + CFLAGS="-march=armv8.2-a+sve2" LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j check + CFLAGS="-march=armv8.2-a+sve2" LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j -C tests test-cli-tests # This test is only compatible with standard libraries that support BTI (Branch Target Identification). # Unfortunately, the standard library provided on Ubuntu 24.04 does not have this feature enabled. # make clean diff --git a/tests/cli-tests/run.py b/tests/cli-tests/run.py index 011c8478e..0addd6b1a 100755 --- a/tests/cli-tests/run.py +++ b/tests/cli-tests/run.py @@ -640,7 +640,7 @@ if __name__ == "__main__": help="Preserve the scratch directory TEST_DIR/scratch/ for debugging purposes." ) parser.add_argument("--verbose", action="store_true", help="Verbose test output.") - parser.add_argument("--timeout", default=200, type=int, help="Test case timeout in seconds. Set to 0 to disable timeouts.") + parser.add_argument("--timeout", default=800, type=int, help="Test case timeout in seconds. Set to 0 to disable timeouts.") parser.add_argument( "--exec-prefix", default=None, diff --git a/tests/fuzzer.c b/tests/fuzzer.c index b74460bb5..da380aced 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -44,6 +44,13 @@ /* must be included after util.h, due to ERROR macro redefinition issue on Visual Studio */ #include "zstd_internal.h" /* ZSTD_WORKSPACETOOLARGE_MAXDURATION, ZSTD_WORKSPACETOOLARGE_FACTOR, KB, MB */ #include "threading.h" /* ZSTD_pthread_create, ZSTD_pthread_join */ +#include "compress/hist.h" /* HIST_count_wksp */ + + +/*-************************************ +* Macros +**************************************/ +#define COUNTOF(array) (sizeof(array) / sizeof(*(array))) /*-************************************ @@ -567,6 +574,123 @@ static void test_decompressBound(unsigned tnb) DISPLAYLEVEL(3, "OK \n"); } +static unsigned test_histCountWksp(unsigned seed, unsigned testNb) +{ + static const unsigned symLowLimits[] = { 0, 27, 0, 0, 27, 42, 0, 0, 27, 42, 27, 42 }; + static const unsigned symHighLimits[] = { 255, 255, 210, 110, 42, 42, 210, 110, 42, 42, 42, 42 }; + static const unsigned symMaxLimits[] = { 255, 255, 255, 255, 255, 255, 230, 130, 99, 99, 42, 42 }; + static const size_t inputSizes[] = { 3367, 1761, 893, 117 }; + unsigned workspace[HIST_WKSP_SIZE_U32]; + size_t res, i, is, il; + + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with empty source : ", testNb++); + { + /* With NULL source UBSan of older Clang could fail: applying zero offset to null pointer. */ + static const unsigned char source[4] = { 0 }; + unsigned count[1] = { 0 }; + unsigned maxSym = 0; + res = HIST_count_wksp(count, &maxSym, source, 0, workspace, sizeof(workspace)); + CHECK_EQ(res, 0); + CHECK_EQ(maxSym, 0); + CHECK_EQ(count[0], 0); + } + DISPLAYLEVEL(3, "OK \n"); + +#if HIST_WKSP_SIZE_U32 + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with small workspace : ", testNb++); + { + unsigned count[1] = { 0 }; + unsigned maxSym = 0; + res = HIST_count_wksp(count, &maxSym, NULL, 0, workspace, sizeof(workspace) - 1); + CHECK_EQ(res, ERROR(workSpace_tooSmall)); + CHECK_EQ(maxSym, 0); + CHECK_EQ(count[0], 0); + } + DISPLAYLEVEL(3, "OK \n"); + + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with wrong workspace alignment : ", testNb++); + { + unsigned count[1] = { 0 }; + unsigned maxSym = 0; + res = HIST_count_wksp(count, &maxSym, NULL, 0, (unsigned*)(void*)((char*)workspace + 1), sizeof(workspace)); + CHECK_EQ(res, ERROR(GENERIC)); + CHECK_EQ(maxSym, 0); + CHECK_EQ(count[0], 0); + } + DISPLAYLEVEL(3, "OK \n"); +#endif + + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with symbol out of range, small size : ", testNb++); + { + /* For less elements HIST_count_parallel_wksp would fail. */ + static const unsigned char source[4] = { 1, 4, 0, 2 }; + static const unsigned expected[6] = { 0 }; + unsigned count[6] = { 0 }; + unsigned maxSym = 2; + res = HIST_count_wksp(count, &maxSym, source, sizeof(source), workspace, sizeof(workspace)); + CHECK_EQ(res, ERROR(maxSymbolValue_tooSmall)); + CHECK_EQ(maxSym, 2); + for (i = 0; i < COUNTOF(expected); ++i) CHECK_EQ(count[i], expected[i]); + } + DISPLAYLEVEL(3, "OK \n"); + + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with symbol out of range, medium size : ", testNb++); + { + unsigned char source[3407]; + unsigned count[6] = { 0 }; + unsigned maxSym = 2; + for (i = 0; i < COUNTOF(source); ++i) { + source[i] = (48271 * (i + 1)) & 3; + } + res = HIST_count_wksp(count, &maxSym, source, sizeof(source), workspace, sizeof(workspace)); + CHECK_EQ(res, ERROR(maxSymbolValue_tooSmall)); + CHECK_EQ(maxSym, 2); + for (i = 0; i < COUNTOF(count); ++i) CHECK_EQ(count[i], 0); + } + DISPLAYLEVEL(3, "OK \n"); + + for (il = 0; il < COUNTOF(symMaxLimits); ++il) { + unsigned symMax = symMaxLimits[il]; + unsigned symLow = symLowLimits[il]; + unsigned symHigh = symHighLimits[il]; + unsigned symRange = symHigh - symLow + 1; + + for (is = 0; is < COUNTOF(inputSizes); ++is) { + unsigned char source[4000]; + size_t inputSize = inputSizes[is]; + assert(inputSize <= sizeof(source)); + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp test in [%u..%u], symMax: %u, inputSize: %u : ", + testNb++, symLow, symHigh, symMax, (unsigned)inputSize); + { + unsigned count[260] = { 0 }; + unsigned expected[COUNTOF(count)] = { 0 }; + unsigned maxSym = symMax; + unsigned realMaxSym = symMax; + unsigned maxCount = 0; + for (i = 0; i < inputSize; ++i) { + unsigned prng = (48271 * (i + seed)) % symRange + symLow; + source[i] = (unsigned char)prng; + ++expected[prng]; + } + /* for basic buffer overwrite checks */ + for (i = maxSym + 1; i < COUNTOF(count); ++i) expected[i] = count[i] = ~0u; + for (i = 0; i <= maxSym; ++i) maxCount = MAX(maxCount, expected[i]); + for (i = realMaxSym; i > 0; --i) { + if (expected[i]) break; + --realMaxSym; + } + res = HIST_count_wksp(count, &maxSym, source, inputSize, workspace, sizeof(workspace)); + CHECK_EQ(res, maxCount); + CHECK_EQ(maxSym, realMaxSym); + for (i = 0; i < COUNTOF(expected); ++i) CHECK_EQ(count[i], expected[i]); + } + DISPLAYLEVEL(3, "OK \n"); + } + } + + return testNb; +} + static void test_setCParams(unsigned tnb) { ZSTD_CCtx* const cctx = ZSTD_createCCtx(); @@ -712,6 +836,8 @@ static int basicUnitTests(U32 const seed, double compressibility) } DISPLAYLEVEL(3, "OK \n"); + testNb = test_histCountWksp(seed, testNb); + DISPLAYLEVEL(3, "test%3u : compress %u bytes : ", testNb++, (unsigned)CNBuffSize); { ZSTD_CCtx* const cctx = ZSTD_createCCtx(); if (cctx==NULL) goto _output_error; From 57bd0eb6a700717500f0c8c9a00d2b468b728d15 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Sat, 14 Jun 2025 19:47:54 -0700 Subject: [PATCH 117/245] meson: use SPDX expression for license This is the format recommended by Meson documentation. --- build/meson/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/meson/meson.build b/build/meson/meson.build index 5c35478d5..bae4d2501 100644 --- a/build/meson/meson.build +++ b/build/meson/meson.build @@ -10,7 +10,7 @@ project('zstd', ['c', 'cpp'], - license: ['BSD', 'GPLv2'], + license: 'BSD-3-Clause OR GPL-2.0-only', default_options : [ # There shouldn't be any need to force a C standard convention for zstd # but in case one would want that anyway, this can be done here. From e315155cc2bbfa72243c51dc083f64931a08d4a3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 18 Jun 2025 15:07:32 -0700 Subject: [PATCH 118/245] removed duplicate this file is already present as `largeDictionary.c` --- tests/bigdict.c | 159 ------------------------------------------------ 1 file changed, 159 deletions(-) delete mode 100644 tests/bigdict.c diff --git a/tests/bigdict.c b/tests/bigdict.c deleted file mode 100644 index 230e5b979..000000000 --- a/tests/bigdict.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#include -#include -#include -#include -#include -#include "datagen.h" -#include "mem.h" -#define ZSTD_STATIC_LINKING_ONLY -#include "zstd.h" - -static int -compress(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx, - void* dst, size_t dstCapacity, - void const* src, size_t srcSize, - void* roundtrip, ZSTD_EndDirective end) -{ - ZSTD_inBuffer in = {src, srcSize, 0}; - ZSTD_outBuffer out = {dst, dstCapacity, 0}; - int ended = 0; - - while (!ended && (in.pos < in.size || out.pos > 0)) { - size_t rc; - out.pos = 0; - rc = ZSTD_compressStream2(cctx, &out, &in, end); - if (ZSTD_isError(rc)) - return 1; - if (end == ZSTD_e_end && rc == 0) - ended = 1; - { - ZSTD_inBuffer rtIn = {dst, out.pos, 0}; - ZSTD_outBuffer rtOut = {roundtrip, srcSize, 0}; - rc = 1; - while (rtIn.pos < rtIn.size || rtOut.pos > 0) { - rtOut.pos = 0; - rc = ZSTD_decompressStream(dctx, &rtOut, &rtIn); - if (ZSTD_isError(rc)) { - fprintf(stderr, "Decompression error: %s\n", ZSTD_getErrorName(rc)); - return 1; - } - if (rc == 0) - break; - } - if (ended && rc != 0) { - fprintf(stderr, "Frame not finished!\n"); - return 1; - } - } - } - - return 0; -} - -int main(int argc, const char** argv) -{ - ZSTD_CCtx* cctx = ZSTD_createCCtx(); - ZSTD_DCtx* dctx = ZSTD_createDCtx(); - const size_t dataSize = (size_t)1 << 30; - const size_t outSize = ZSTD_compressBound(dataSize); - const size_t bufferSize = (size_t)1 << 31; - char* buffer = (char*)malloc(bufferSize); - void* out = malloc(outSize); - void* roundtrip = malloc(dataSize); - int _exit_code = 0; - (void)argc; - (void)argv; - - if (!buffer || !out || !roundtrip || !cctx || !dctx) { - fprintf(stderr, "Allocation failure\n"); - _exit_code = 1; - goto cleanup; - } - - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 31))) { - _exit_code = 1; - goto cleanup; - } - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 1))) { - _exit_code = 1; - goto cleanup; - } - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_overlapLog, 9))) { - _exit_code = 1; - goto cleanup; - } - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1))) { - _exit_code = 1; - goto cleanup; - } - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, ZSTD_btopt))) { - _exit_code = 1; - goto cleanup; - } - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, 7))) { - _exit_code = 1; - goto cleanup; - } - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 7))) { - _exit_code = 1; - goto cleanup; - } - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, 1))) { - _exit_code = 1; - goto cleanup; - } - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, 10))) { - _exit_code = 1; - goto cleanup; - } - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, 10))) { - _exit_code = 1; - goto cleanup; - } - - if (ZSTD_isError(ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, 31))) { - _exit_code = 1; - goto cleanup; - } - - RDG_genBuffer(buffer, bufferSize, 1.0, 0.0, 0xbeefcafe); - - /* Compress 30 GB */ - { - int i; - for (i = 0; i < 10; ++i) { - fprintf(stderr, "Compressing 1 GB\n"); - if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_continue)) { - _exit_code = 1; - goto cleanup; - } - } - } - fprintf(stderr, "Compressing 1 GB\n"); - if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_end)) { - _exit_code = 1; - goto cleanup; - } - - fprintf(stderr, "Success!\n"); - - goto cleanup; - -cleanup: - free(roundtrip); - free(out); - free(buffer); - ZSTD_freeCCtx(cctx); - ZSTD_freeDCtx(dctx); - return _exit_code; -} From 1e9d2006ae2601df6c3ec36464e1622921424a91 Mon Sep 17 00:00:00 2001 From: Arpad Panyik Date: Fri, 20 Jun 2025 14:48:33 +0000 Subject: [PATCH 119/245] AArch64: Use better block copy8 The vector copy is only necessary for 16-byte blocks on AArch64. Decompression uplifts on a Neoverse V2 system, using Zstd-1.5.8 compiled with "-O3 -march=armv8.2-a+sve2": Clang-19 Clang-20 GCC-14 GCC-15 1#silesia.tar: +0.316% +0.865% +0.025% +0.096% 2#silesia.tar: +0.689% +1.374% +0.027% +0.065% 3#silesia.tar: +0.811% +1.654% +0.034% +0.033% 4#silesia.tar: +0.912% +1.755% +0.027% +0.042% 5#silesia.tar: +0.995% +1.826% +0.062% +0.094% 6#silesia.tar: +0.976% +1.777% +0.065% +0.104% 7#silesia.tar: +0.910% +1.738% +0.077% +0.110% --- lib/common/zstd_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index c1647689b..791b6485d 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -168,7 +168,7 @@ static UNUSED_ATTR const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG; * Shared functions to include for inlining *********************************************/ static void ZSTD_copy8(void* dst, const void* src) { -#if defined(ZSTD_ARCH_ARM_NEON) +#if defined(ZSTD_ARCH_ARM_NEON) && !defined(__aarch64__) vst1_u8((uint8_t*)dst, vld1_u8((const uint8_t*)src)); #else ZSTD_memcpy(dst, src, 8); From a4b9ebcbebe551af315093f556250aacae1de33d Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Fri, 20 Jun 2025 23:34:13 -0700 Subject: [PATCH 120/245] meson: drop unused variable --- build/meson/meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/build/meson/meson.build b/build/meson/meson.build index bae4d2501..a9768d43a 100644 --- a/build/meson/meson.build +++ b/build/meson/meson.build @@ -65,7 +65,6 @@ zstd_docdir = join_paths(zstd_datadir, 'doc', meson.project_name()) # Built-in options use_debug = get_option('debug') -buildtype = get_option('buildtype') default_library_type = get_option('default_library') # Custom options From 16e13ebdeb0cc29c90c4dd8884c366fdce7cd283 Mon Sep 17 00:00:00 2001 From: jinyaoguo Date: Sat, 21 Jun 2025 13:03:13 -0400 Subject: [PATCH 121/245] delete --- tests/bigdict.c | 132 ------------------------------------------------ 1 file changed, 132 deletions(-) delete mode 100644 tests/bigdict.c diff --git a/tests/bigdict.c b/tests/bigdict.c deleted file mode 100644 index 33c4ab8ea..000000000 --- a/tests/bigdict.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#include -#include -#include -#include -#include -#include "datagen.h" -#include "mem.h" -#define ZSTD_STATIC_LINKING_ONLY -#include "zstd.h" - -static int -compress(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx, - void* dst, size_t dstCapacity, - void const* src, size_t srcSize, - void* roundtrip, ZSTD_EndDirective end) -{ - ZSTD_inBuffer in = {src, srcSize, 0}; - ZSTD_outBuffer out = {dst, dstCapacity, 0}; - int ended = 0; - - while (!ended && (in.pos < in.size || out.pos > 0)) { - size_t rc; - out.pos = 0; - rc = ZSTD_compressStream2(cctx, &out, &in, end); - if (ZSTD_isError(rc)) - return 1; - if (end == ZSTD_e_end && rc == 0) - ended = 1; - { - ZSTD_inBuffer rtIn = {dst, out.pos, 0}; - ZSTD_outBuffer rtOut = {roundtrip, srcSize, 0}; - rc = 1; - while (rtIn.pos < rtIn.size || rtOut.pos > 0) { - rtOut.pos = 0; - rc = ZSTD_decompressStream(dctx, &rtOut, &rtIn); - if (ZSTD_isError(rc)) { - fprintf(stderr, "Decompression error: %s\n", ZSTD_getErrorName(rc)); - return 1; - } - if (rc == 0) - break; - } - if (ended && rc != 0) { - fprintf(stderr, "Frame not finished!\n"); - return 1; - } - } - } - - return 0; -} - -int main(int argc, const char** argv) -{ - ZSTD_CCtx* cctx = ZSTD_createCCtx(); - ZSTD_DCtx* dctx = ZSTD_createDCtx(); - const size_t dataSize = (size_t)1 << 30; - const size_t outSize = ZSTD_compressBound(dataSize); - const size_t bufferSize = (size_t)1 << 31; - char* buffer = (char*)malloc(bufferSize); - void* out = malloc(outSize); - void* roundtrip = malloc(dataSize); - int _exit_code = 1; - (void)argc; - (void)argv; - - if (!buffer || !out || !roundtrip || !cctx || !dctx) { - fprintf(stderr, "Allocation failure\n"); - goto cleanup; - } - - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 31))) - goto cleanup; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 1))) - goto cleanup; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_overlapLog, 9))) - goto cleanup; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1))) - goto cleanup; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, ZSTD_btopt))) - goto cleanup; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, 7))) - goto cleanup; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 7))) - goto cleanup; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, 1))) - goto cleanup; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, 10))) - goto cleanup; - if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, 10))) - goto cleanup; - - if (ZSTD_isError(ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, 31))) - goto cleanup; - - RDG_genBuffer(buffer, bufferSize, 1.0, 0.0, 0xbeefcafe); - - /* Compress 30 GB */ - { - int i; - for (i = 0; i < 10; ++i) { - fprintf(stderr, "Compressing 1 GB\n"); - if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_continue)) - goto cleanup; - } - } - fprintf(stderr, "Compressing 1 GB\n"); - if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_end)) - goto cleanup; - - fprintf(stderr, "Success!\n"); - - _exit_code = 0; - -cleanup: - free(roundtrip); - free(out); - free(buffer); - ZSTD_freeCCtx(cctx); - ZSTD_freeDCtx(dctx); - return _exit_code; -} From 878be1c8f0260db5b028694da53bdd97635d8fc7 Mon Sep 17 00:00:00 2001 From: jinyaoguo Date: Sat, 21 Jun 2025 13:43:47 -0400 Subject: [PATCH 122/245] fix --- tests/largeDictionary.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/largeDictionary.c b/tests/largeDictionary.c index 30ff98d98..b824960fc 100644 --- a/tests/largeDictionary.c +++ b/tests/largeDictionary.c @@ -73,7 +73,6 @@ int main(int argc, const char** argv) int _exit_code = 1; (void)argc; (void)argv; - int _exit_code = 0; if (!buffer || !out || !roundtrip || !cctx || !dctx) { fprintf(stderr, "Allocation failure\n"); @@ -119,6 +118,7 @@ int main(int argc, const char** argv) if (compress(cctx, dctx, out, outSize, buffer, dataSize, roundtrip, ZSTD_e_end)) goto cleanup; + _exit_code = 0; fprintf(stderr, "Success!\n"); cleanup: @@ -128,5 +128,4 @@ cleanup: ZSTD_freeDCtx(dctx); ZSTD_freeCCtx(cctx); return _exit_code; - return _exit_code; } From d77a7b689546d62bb728caa2dd1d2d0f9820612d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 21 Jun 2025 10:55:34 -0700 Subject: [PATCH 123/245] added test-largeDictionary to dev-long CI script --- .github/workflows/dev-long-tests.yml | 8 ++++++++ tests/.gitignore | 1 + 2 files changed, 9 insertions(+) diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index bf287857f..f92c777d0 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -56,6 +56,14 @@ jobs: make clean CFLAGS="-m32 -O2" make -j test V=1 + test-largeDictionary: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - name: largeDictionary + run: | + CFLAGS="-Werror -O3" make -j -C tests test-largeDictionary + no-intrinsics-fuzztest: runs-on: ubuntu-latest steps: diff --git a/tests/.gitignore b/tests/.gitignore index 311a8b5eb..0f155764b 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -5,6 +5,7 @@ fullbench-lib fuzzer fuzzer32 fuzzer-dll +largeDictionary zbufftest zbufftest32 zbufftest-dll From 2295826266c16d2e9e6d345ed67d513588eb967d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 21 Jun 2025 12:01:07 -0700 Subject: [PATCH 124/245] update tests duration indications --- .github/workflows/dev-long-tests.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index f92c777d0..84eda4fa4 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -1,5 +1,5 @@ name: dev-long-tests -# Tests longer than 10mn +# Tests generally longer than 10mn concurrency: group: long-${{ github.ref }} @@ -12,6 +12,7 @@ on: permissions: read-all jobs: + # lasts ~7mn make-all: runs-on: ubuntu-latest steps: @@ -19,7 +20,7 @@ jobs: - name: make all run: make all - # lasts ~24mn + # lasts ~19mn make-test: runs-on: ubuntu-latest env: @@ -33,7 +34,7 @@ jobs: make -j zstd ./tests/test_process_substitution.bash ./zstd - # lasts ~26mn + # lasts ~16mn make-test-macos: runs-on: macos-latest steps: @@ -41,7 +42,7 @@ jobs: - name: make test on macos run: make test - # lasts ~24mn + # lasts ~10mn make-test-32bit: runs-on: ubuntu-latest env: @@ -56,6 +57,7 @@ jobs: make clean CFLAGS="-m32 -O2" make -j test V=1 + # lasts ~7mn test-largeDictionary: runs-on: ubuntu-latest steps: @@ -64,6 +66,7 @@ jobs: run: | CFLAGS="-Werror -O3" make -j -C tests test-largeDictionary + # lasts ~9mn no-intrinsics-fuzztest: runs-on: ubuntu-latest steps: @@ -71,6 +74,7 @@ jobs: - name: no intrinsics fuzztest run: MOREFLAGS="-DZSTD_NO_INTRINSICS" make -C tests fuzztest + # lasts ~8mn tsan-zstreamtest: runs-on: ubuntu-latest steps: @@ -85,7 +89,7 @@ jobs: - name: ub + address sanitizer on zstreamtest run: CC=clang make uasan-test-zstream - # lasts ~15mn + # lasts ~11mn tsan-fuzztest: runs-on: ubuntu-latest steps: @@ -93,7 +97,6 @@ jobs: - name: thread sanitizer fuzztest run: CC=clang make tsan-fuzztest - big-tests-zstreamtest32: runs-on: ubuntu-latest steps: @@ -104,7 +107,7 @@ jobs: make libc6install CC=clang make -C tests test-zstream32 FUZZER_FLAGS="--big-tests" - # lasts ~23mn + # lasts ~13mn gcc-8-asan-ubsan-testzstd: runs-on: ubuntu-latest steps: From 7b1b6a0d2da35d9b97aab060140d548e60503ccd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 06:24:00 +0000 Subject: [PATCH 125/245] Bump msys2/setup-msys2 from 2.27.0 to 2.28.0 Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.27.0 to 2.28.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/61f9e5e925871ba6c9e3e8da24ede83ea27fa91f...40677d36a502eb2cf0fb808cc9dec31bf6152638) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.28.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dev-long-tests.yml | 2 +- .github/workflows/dev-short-tests.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 84eda4fa4..3fa971a34 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -274,7 +274,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # tag=v2.27.0 + - uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # tag=v2.28.0 with: msystem: MINGW64 install: make diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 31d44542f..53f640dae 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -485,7 +485,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # tag=v2.27.0 + - uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # tag=v2.28.0 with: msystem: ${{ matrix.msystem }} install: make diffutils diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 4baa2f555..6ffdb330a 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -26,7 +26,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # tag=v2.27.0 + - uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # tag=v2.28.0 with: msystem: ${{ matrix.msystem }} install: make p7zip git mingw-w64-${{matrix.env}}-gcc From bd38fc2c5f21536bc523f9a42c5e642ea9407ae4 Mon Sep 17 00:00:00 2001 From: Arpad Panyik Date: Fri, 20 Jun 2025 15:29:17 +0000 Subject: [PATCH 126/245] AArch64: Enhance struct access in Huffman decode 2X MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the multi-stream multi-symbol Huffman decoder GCC generates suboptimal code - emitting more loads for HUF_DEltX2 struct member accesses. Forcing it to use 32-bit loads and bit arithmetic to extract the necessary parts (UBFX) improves the overall decode speed. Also avoid integer type conversions in the symbol decodes, which leads to better instruction selection in table lookup accesses. On AArch64 the decoder no longer runs into register-pressure limits, so we can simplify the hot path and improve throughput Decompression uplifts on a Neoverse V2 system, using Zstd-1.5.8 compiled with "-O3 -march=armv8.2-a+sve2": Clang-20 Clang-* GCC-13 GCC-14 GCC-15 1#silesia.tar: +0.820% +1.365% +2.480% +1.348% +0.987% 2#silesia.tar: +0.426% +0.784% +1.218% +0.665% +0.554% 3#silesia.tar: +0.112% +0.389% +0.508% +0.188% +0.261% * Requires Clang-21 support from LLVM commit hash `a53003fe23cb6c871e72d70ff2d3a075a7490da2` (Clang-21 hasn’t been released as of this writing) --- lib/decompress/huf_decompress.c | 90 ++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/lib/decompress/huf_decompress.c b/lib/decompress/huf_decompress.c index c7e342648..920206178 100644 --- a/lib/decompress/huf_decompress.c +++ b/lib/decompress/huf_decompress.c @@ -785,19 +785,19 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* } #endif -#define HUF_4X1_DECODE_SYMBOL(_stream, _symbol) \ - do { \ - int const index = (int)(bits[(_stream)] >> 53); \ - int const entry = (int)dtable[index]; \ - bits[(_stream)] <<= (entry & 0x3F); \ - op[(_stream)][(_symbol)] = (BYTE)((entry >> 8) & 0xFF); \ +#define HUF_4X1_DECODE_SYMBOL(_stream, _symbol) \ + do { \ + U64 const index = bits[(_stream)] >> 53; \ + U16 const entry = dtable[index]; \ + bits[(_stream)] <<= entry & 0x3F; \ + op[(_stream)][(_symbol)] = (BYTE)(entry >> 8); \ } while (0) -#define HUF_4X1_RELOAD_STREAM(_stream) \ +#define HUF_5X1_RELOAD_STREAM(_stream) \ do { \ - int const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \ - int const nbBits = ctz & 7; \ - int const nbBytes = ctz >> 3; \ + U64 const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \ + U64 const nbBits = ctz & 7; \ + U64 const nbBytes = ctz >> 3; \ op[(_stream)] += 5; \ ip[(_stream)] -= nbBytes; \ bits[(_stream)] = MEM_read64(ip[(_stream)]) | 1; \ @@ -816,11 +816,11 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 4); /* Reload each of the 4 the bitstreams */ - HUF_4X_FOR_EACH_STREAM(HUF_4X1_RELOAD_STREAM); + HUF_4X_FOR_EACH_STREAM(HUF_5X1_RELOAD_STREAM); } while (op[3] < olimit); #undef HUF_4X1_DECODE_SYMBOL -#undef HUF_4X1_RELOAD_STREAM +#undef HUF_5X1_RELOAD_STREAM } _out: @@ -1603,57 +1603,65 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* } #endif -#define HUF_4X2_DECODE_SYMBOL(_stream, _decode3) \ - do { \ - if ((_decode3) || (_stream) != 3) { \ - int const index = (int)(bits[(_stream)] >> 53); \ - HUF_DEltX2 const entry = dtable[index]; \ - MEM_write16(op[(_stream)], entry.sequence); \ - bits[(_stream)] <<= (entry.nbBits) & 0x3F; \ - op[(_stream)] += (entry.length); \ - } \ +#define HUF_4X2_DECODE_SYMBOL(_stream, _decode3) \ + do { \ + if ((_decode3) || (_stream) != 3) { \ + U64 const index = bits[(_stream)] >> 53; \ + size_t const entry = MEM_readLE32(&dtable[index]); \ + MEM_write16(op[(_stream)], (U16)entry); \ + bits[(_stream)] <<= (entry >> 16) & 0x3F; \ + op[(_stream)] += entry >> 24; \ + } \ } while (0) -#define HUF_4X2_RELOAD_STREAM(_stream) \ +#define HUF_5X2_RELOAD_STREAM(_stream, _decode3) \ do { \ - HUF_4X2_DECODE_SYMBOL(3, 1); \ + if (_decode3) HUF_4X2_DECODE_SYMBOL(3, 1); \ { \ - int const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \ - int const nbBits = ctz & 7; \ - int const nbBytes = ctz >> 3; \ + U64 const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \ + U64 const nbBits = ctz & 7; \ + U64 const nbBytes = ctz >> 3; \ ip[(_stream)] -= nbBytes; \ bits[(_stream)] = MEM_read64(ip[(_stream)]) | 1; \ bits[(_stream)] <<= nbBits; \ } \ } while (0) +#if defined(__aarch64__) +# define HUF_4X2_4WAY 1 +#else +# define HUF_4X2_4WAY 0 +#endif +#define HUF_4X2_3WAY !HUF_4X2_4WAY + /* Manually unroll the loop because compilers don't consistently * unroll the inner loops, which destroys performance. */ do { - /* Decode 5 symbols from each of the first 3 streams. - * The final stream will be decoded during the reload phase - * to reduce register pressure. + /* Decode 5 symbols from each of the first 3 or 4 streams. + * In the 3-way case the final stream will be decoded during + * the reload phase to reduce register pressure. */ - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, HUF_4X2_4WAY); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, HUF_4X2_4WAY); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, HUF_4X2_4WAY); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, HUF_4X2_4WAY); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, HUF_4X2_4WAY); - /* Decode one symbol from the final stream */ - HUF_4X2_DECODE_SYMBOL(3, 1); + /* In the 3-way case decode one symbol from the final stream. */ + HUF_4X2_DECODE_SYMBOL(3, HUF_4X2_3WAY); - /* Decode 4 symbols from the final stream & reload bitstreams. - * The final stream is reloaded last, meaning that all 5 symbols - * are decoded from the final stream before it is reloaded. + /* In the 3-way case decode 4 symbols from the final stream & + * reload bitstreams. The final stream is reloaded last, meaning + * that all 5 symbols are decoded from the final stream before + * it is reloaded. */ - HUF_4X_FOR_EACH_STREAM(HUF_4X2_RELOAD_STREAM); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_5X2_RELOAD_STREAM, HUF_4X2_3WAY); } while (op[3] < olimit); } #undef HUF_4X2_DECODE_SYMBOL -#undef HUF_4X2_RELOAD_STREAM +#undef HUF_5X2_RELOAD_STREAM _out: From a28e8182b1aa6e1e17bcdd099630ea67c4143d32 Mon Sep 17 00:00:00 2001 From: Arpad Panyik Date: Tue, 24 Jun 2025 11:26:58 +0000 Subject: [PATCH 127/245] AArch64: Improve ZSTD_decodeSequence performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LLVM's alias-analysis sometimes fails to see that a static-array member of a struct cannot alias other members. This patch: - Reduces array accesses via struct indirection to aid load/store alias analysis under Clang. - Converts dynamic array indexing into conditional-move arithmetic, eliminating branches and extra loads/stores on out-of-order CPUs. - Reloads the bitstream only when match-length bits are consumed (assuming each reload only needs to happen once per match-length read), improving branch-prediction rates. - Removes the UNLIKELY() hint, which recent compilers already handle well without cost. Decompression uplifts on a Neoverse V2 system, using Zstd-1.5.8 compiled with "-O3 -march=armv8.2-a+sve2": Clang-19 Clang-20 Clang-* GCC-14 GCC-15 1#silesia.tar: +11.556% +16.203% +0.240% +2.216% +7.891% 2#silesia.tar: +15.493% +21.140% -0.041% +2.850% +9.926% 3#silesia.tar: +16.887% +22.570% -0.183% +3.056% +10.660% 4#silesia.tar: +17.785% +23.315% -0.262% +3.343% +11.187% 5#silesia.tar: +18.125% +24.175% -0.466% +3.350% +11.228% 6#silesia.tar: +17.607% +23.339% -0.591% +3.175% +10.851% 7#silesia.tar: +17.463% +22.837% -0.486% +3.292% +10.868% * Requires Clang-21 support from LLVM commit hash `a53003fe23cb6c871e72d70ff2d3a075a7490da2` (Clang-21 hasn’t been released as of this writing) Co-authored by: David Sherwood, David.Sherwood@arm.com Ola Liljedahl, Ola.Liljedahl@arm.com --- lib/decompress/zstd_decompress_block.c | 127 +++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 8 deletions(-) diff --git a/lib/decompress/zstd_decompress_block.c b/lib/decompress/zstd_decompress_block.c index 6174a250b..b2ccd92a1 100644 --- a/lib/decompress/zstd_decompress_block.c +++ b/lib/decompress/zstd_decompress_block.c @@ -1236,6 +1236,10 @@ FORCE_INLINE_TEMPLATE seq_t ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, const int isLastSeq) { seq_t seq; +#if defined(__aarch64__) + size_t prevOffset0 = seqState->prevOffset[0]; + size_t prevOffset1 = seqState->prevOffset[1]; + size_t prevOffset2 = seqState->prevOffset[2]; /* * ZSTD_seqSymbol is a 64 bits wide structure. * It can be loaded in one operation @@ -1244,7 +1248,7 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c * operations that cause performance drop. This can be avoided by using this * ZSTD_memcpy hack. */ -#if defined(__aarch64__) && (defined(__GNUC__) && !defined(__clang__)) +# if defined(__GNUC__) && !defined(__clang__) ZSTD_seqSymbol llDInfoS, mlDInfoS, ofDInfoS; ZSTD_seqSymbol* const llDInfo = &llDInfoS; ZSTD_seqSymbol* const mlDInfo = &mlDInfoS; @@ -1252,11 +1256,11 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c ZSTD_memcpy(llDInfo, seqState->stateLL.table + seqState->stateLL.state, sizeof(ZSTD_seqSymbol)); ZSTD_memcpy(mlDInfo, seqState->stateML.table + seqState->stateML.state, sizeof(ZSTD_seqSymbol)); ZSTD_memcpy(ofDInfo, seqState->stateOffb.table + seqState->stateOffb.state, sizeof(ZSTD_seqSymbol)); -#else +# else const ZSTD_seqSymbol* const llDInfo = seqState->stateLL.table + seqState->stateLL.state; const ZSTD_seqSymbol* const mlDInfo = seqState->stateML.table + seqState->stateML.state; const ZSTD_seqSymbol* const ofDInfo = seqState->stateOffb.table + seqState->stateOffb.state; -#endif +# endif seq.matchLength = mlDInfo->baseValue; seq.litLength = llDInfo->baseValue; { U32 const ofBase = ofDInfo->baseValue; @@ -1275,10 +1279,116 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c assert(llBits <= MaxLLBits); assert(mlBits <= MaxMLBits); assert(ofBits <= MaxOff); - /* - * As gcc has better branch and block analyzers, sometimes it is only - * valuable to mark likeliness for clang, it gives around 3-4% of - * performance. + /* As GCC has better branch and block analyzers, sometimes it is only + * valuable to mark likeliness for Clang. + */ + + /* sequence */ + { size_t offset; + if (ofBits > 1) { + ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); + ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); + ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 > LONG_OFFSETS_MAX_EXTRA_BITS_32); + ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 - LONG_OFFSETS_MAX_EXTRA_BITS_32 >= MaxMLBits); + if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { + /* Always read extra bits, this keeps the logic simple, + * avoids branches, and avoids accidentally reading 0 bits. + */ + U32 const extraBits = LONG_OFFSETS_MAX_EXTRA_BITS_32; + offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); + BIT_reloadDStream(&seqState->DStream); + offset += BIT_readBitsFast(&seqState->DStream, extraBits); + } else { + offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); + } + prevOffset2 = prevOffset1; + prevOffset1 = prevOffset0; + prevOffset0 = offset; + } else { + U32 const ll0 = (llDInfo->baseValue == 0); + if (LIKELY((ofBits == 0))) { + if (ll0) { + offset = prevOffset1; + prevOffset1 = prevOffset0; + prevOffset0 = offset; + } else { + offset = prevOffset0; + } + } else { + offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1); + { size_t temp = (offset == 1) ? prevOffset1 + : (offset == 3) ? prevOffset0 - 1 + : (offset >= 2) ? prevOffset2 + : prevOffset0; + /* 0 is not valid: input corrupted => force offset to -1 => + * corruption detected at execSequence. + */ + temp -= !temp; + prevOffset2 = (offset == 1) ? prevOffset2 : prevOffset1; + prevOffset1 = prevOffset0; + prevOffset0 = offset = temp; + } } } + seq.offset = offset; + } + + if (mlBits > 0) { + seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/); + + if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) + BIT_reloadDStream(&seqState->DStream); + if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) + BIT_reloadDStream(&seqState->DStream); + } + + /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ + ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); + + if (llBits > 0) + seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/); + + if (MEM_32bits()) + BIT_reloadDStream(&seqState->DStream); + + DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + + if (!isLastSeq) { + /* Don't update FSE state for last sequence. */ + ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llNext, llnbBits); /* <= 9 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlNext, mlnbBits); /* <= 9 bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofNext, ofnbBits); /* <= 8 bits */ + BIT_reloadDStream(&seqState->DStream); + } + } + seqState->prevOffset[0] = prevOffset0; + seqState->prevOffset[1] = prevOffset1; + seqState->prevOffset[2] = prevOffset2; +#else /* !defined(__aarch64__) */ + const ZSTD_seqSymbol* const llDInfo = seqState->stateLL.table + seqState->stateLL.state; + const ZSTD_seqSymbol* const mlDInfo = seqState->stateML.table + seqState->stateML.state; + const ZSTD_seqSymbol* const ofDInfo = seqState->stateOffb.table + seqState->stateOffb.state; + seq.matchLength = mlDInfo->baseValue; + seq.litLength = llDInfo->baseValue; + { U32 const ofBase = ofDInfo->baseValue; + BYTE const llBits = llDInfo->nbAdditionalBits; + BYTE const mlBits = mlDInfo->nbAdditionalBits; + BYTE const ofBits = ofDInfo->nbAdditionalBits; + BYTE const totalBits = llBits+mlBits+ofBits; + + U16 const llNext = llDInfo->nextState; + U16 const mlNext = mlDInfo->nextState; + U16 const ofNext = ofDInfo->nextState; + U32 const llnbBits = llDInfo->nbBits; + U32 const mlnbBits = mlDInfo->nbBits; + U32 const ofnbBits = ofDInfo->nbBits; + + assert(llBits <= MaxLLBits); + assert(mlBits <= MaxMLBits); + assert(ofBits <= MaxOff); + /* As GCC has better branch and block analyzers, sometimes it is only + * valuable to mark likeliness for Clang. */ /* sequence */ @@ -1340,7 +1450,7 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); if (!isLastSeq) { - /* don't update FSE state for last Sequence */ + /* Don't update FSE state for last sequence. */ ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llNext, llnbBits); /* <= 9 bits */ ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlNext, mlnbBits); /* <= 9 bits */ if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ @@ -1348,6 +1458,7 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c BIT_reloadDStream(&seqState->DStream); } } +#endif /* defined(__aarch64__) */ return seq; } From 50f169411bf45e2cab1f221a5dcf3e97e273510d Mon Sep 17 00:00:00 2001 From: Rose Date: Mon, 26 May 2025 15:56:55 -0400 Subject: [PATCH 128/245] Remove redundant setting of allJobsCompleted to 1 This will do it automatically. --- lib/compress/zstdmt_compress.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 0f1fe6d74..6d6f8139b 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -1268,8 +1268,7 @@ size_t ZSTDMT_initCStream_internal( if (mtctx->allJobsCompleted == 0) { /* previous compression not correctly finished */ ZSTDMT_waitForAllJobsCompleted(mtctx); - ZSTDMT_releaseAllJobResources(mtctx); - mtctx->allJobsCompleted = 1; + ZSTDMT_releaseAllJobResources(mtctx); /* Will set allJobsCompleted to 1 */ } mtctx->params = params; From 4efbd56749ff36a7238966e457029e5b64e7dbe3 Mon Sep 17 00:00:00 2001 From: Rose Date: Tue, 24 Jun 2025 14:05:08 -0400 Subject: [PATCH 129/245] Check for job before releasing ZSTDMT_freeCCtx calls ZSTDMT_releaseAllJobResources, but ZSTDMT_releaseAllJobResources may be called when ZSTDMT_freeCCtx is called when initialization fails, resulting in a NULL pointer dereference. --- lib/compress/zstdmt_compress.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 0f1fe6d74..828d5723f 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -1008,18 +1008,20 @@ static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx) { unsigned jobID; DEBUGLOG(3, "ZSTDMT_releaseAllJobResources"); - for (jobID=0; jobID <= mtctx->jobIDMask; jobID++) { - /* Copy the mutex/cond out */ - ZSTD_pthread_mutex_t const mutex = mtctx->jobs[jobID].job_mutex; - ZSTD_pthread_cond_t const cond = mtctx->jobs[jobID].job_cond; - - DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].dstBuff.start); - ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff); - - /* Clear the job description, but keep the mutex/cond */ - ZSTD_memset(&mtctx->jobs[jobID], 0, sizeof(mtctx->jobs[jobID])); - mtctx->jobs[jobID].job_mutex = mutex; - mtctx->jobs[jobID].job_cond = cond; + if (mtctx->jobs) { + for (jobID=0; jobID <= mtctx->jobIDMask; jobID++) { + /* Copy the mutex/cond out */ + ZSTD_pthread_mutex_t const mutex = mtctx->jobs[jobID].job_mutex; + ZSTD_pthread_cond_t const cond = mtctx->jobs[jobID].job_cond; + + DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].dstBuff.start); + ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff); + + /* Clear the job description, but keep the mutex/cond */ + ZSTD_memset(&mtctx->jobs[jobID], 0, sizeof(mtctx->jobs[jobID])); + mtctx->jobs[jobID].job_mutex = mutex; + mtctx->jobs[jobID].job_cond = cond; + } } mtctx->inBuff.buffer = g_nullBuffer; mtctx->inBuff.filled = 0; From 40f64f34935737ed7af6ca727d6b240cba552f0a Mon Sep 17 00:00:00 2001 From: ZijianLi Date: Sun, 29 Jun 2025 15:33:50 +0800 Subject: [PATCH 130/245] add riscv rvv ci --- .github/workflows/dev-short-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 53f640dae..c954353e2 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -461,6 +461,9 @@ jobs: if: ${{ matrix.name == 'RISC-V' }} run: | LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make clean check + CFLAGS="-march=rv64gcv -O3" LDFLAGS="-static" CC=$XCC QEMU_SYS="$XEMU -cpu rv64,v=true,vlen=128" make clean check + CFLAGS="-march=rv64gcv -O3" LDFLAGS="-static" CC=$XCC QEMU_SYS="$XEMU -cpu rv64,v=true,vlen=256" make clean check + CFLAGS="-march=rv64gcv -O3" LDFLAGS="-static" CC=$XCC QEMU_SYS="$XEMU -cpu rv64,v=true,vlen=512" make clean check - name: M68K if: ${{ matrix.name == 'M68K' }} run: | From 2c3f23b018c719451a69b043bb5eaaa28d4aa014 Mon Sep 17 00:00:00 2001 From: ZijianLi Date: Sun, 29 Jun 2025 15:36:25 +0800 Subject: [PATCH 131/245] fix dereferencing type-punned pointer error --- lib/compress/zstd_compress.c | 118 ++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 56 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 9b7aaf9f4..fc29b56ab 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -7287,7 +7287,7 @@ static size_t convertSequences_noRepcodes( #elif defined ZSTD_ARCH_RISCV_RVV #include /* - * Convert `vl` sequences per iteration, using AVX2 intrinsics: + * Convert `vl` sequences per iteration, using RVV intrinsics: * - offset -> offBase = offset + 2 * - litLength -> (U16) litLength * - matchLength -> (U16)(matchLength - 3) @@ -7300,7 +7300,8 @@ static size_t convertSequences_noRepcodes( */ static size_t convertSequences_noRepcodes(SeqDef* dstSeqs, const ZSTD_Sequence* inSeqs, size_t nbSequences) { size_t longLen = 0; - + size_t vl = 0; + typedef uint32_t __attribute__((may_alias)) aliased_u32; /* RVV depends on the specific definition of target structures */ ZSTD_STATIC_ASSERT(sizeof(ZSTD_Sequence) == 16); ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, offset) == 0); @@ -7310,62 +7311,68 @@ static size_t convertSequences_noRepcodes(SeqDef* dstSeqs, const ZSTD_Sequence* ZSTD_STATIC_ASSERT(offsetof(SeqDef, offBase) == 0); ZSTD_STATIC_ASSERT(offsetof(SeqDef, litLength) == 4); ZSTD_STATIC_ASSERT(offsetof(SeqDef, mlBase) == 6); - size_t vl = 0; + for (size_t i = 0; i < nbSequences; i += vl) { - vl = __riscv_vsetvl_e32m2(nbSequences-i); - // Loading structure member variables - vuint32m2x4_t v_tuple = __riscv_vlseg4e32_v_u32m2x4( - (const int32_t*)&inSeqs[i], - vl - ); - vuint32m2_t v_offset = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 0); - vuint32m2_t v_lit = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 1); - vuint32m2_t v_match = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 2); - // offset + ZSTD_REP_NUM - vuint32m2_t v_offBase = __riscv_vadd_vx_u32m2(v_offset, ZSTD_REP_NUM, vl); - // Check for integer overflow - // Cast to a 16-bit variable - vbool16_t lit_overflow = __riscv_vmsgtu_vx_u32m2_b16(v_lit, 65535, vl); - vuint16m1_t v_lit_clamped = __riscv_vncvt_x_x_w_u16m1(v_lit, vl); + vl = __riscv_vsetvl_e32m2(nbSequences-i); + { + // Loading structure member variables + vuint32m2x4_t v_tuple = __riscv_vlseg4e32_v_u32m2x4( + (const aliased_u32*)((const void*)&inSeqs[i]), + vl + ); + vuint32m2_t v_offset = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 0); + vuint32m2_t v_lit = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 1); + vuint32m2_t v_match = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 2); + // offset + ZSTD_REP_NUM + vuint32m2_t v_offBase = __riscv_vadd_vx_u32m2(v_offset, ZSTD_REP_NUM, vl); + // Check for integer overflow + // Cast to a 16-bit variable + vbool16_t lit_overflow = __riscv_vmsgtu_vx_u32m2_b16(v_lit, 65535, vl); + vuint16m1_t v_lit_clamped = __riscv_vncvt_x_x_w_u16m1(v_lit, vl); - vbool16_t ml_overflow = __riscv_vmsgtu_vx_u32m2_b16(v_match, 65535+MINMATCH, vl); - vuint16m1_t v_ml_clamped = __riscv_vncvt_x_x_w_u16m1(__riscv_vsub_vx_u32m2(v_match, MINMATCH, vl), vl); + vbool16_t ml_overflow = __riscv_vmsgtu_vx_u32m2_b16(v_match, 65535+MINMATCH, vl); + vuint16m1_t v_ml_clamped = __riscv_vncvt_x_x_w_u16m1(__riscv_vsub_vx_u32m2(v_match, MINMATCH, vl), vl); - // Pack two 16-bit fields into a 32-bit value (little-endian) - // The lower 16 bits contain litLength, and the upper 16 bits contain mlBase - vuint32m2_t v_lit_ml_combined = __riscv_vsll_vx_u32m2( - __riscv_vwcvtu_x_x_v_u32m2(v_ml_clamped, vl), // Convert matchLength to 32-bit - 16, - vl - ); - v_lit_ml_combined = __riscv_vor_vv_u32m2( - v_lit_ml_combined, - __riscv_vwcvtu_x_x_v_u32m2(v_lit_clamped, vl), - vl - ); - // Create a vector of SeqDef structures - // Store the offBase, litLength, and mlBase in a vector of SeqDef - vuint32m2x2_t store_data = __riscv_vcreate_v_u32m2x2( - v_offBase, - v_lit_ml_combined - ); - __riscv_vsseg2e32_v_u32m2x2( - (uint32_t*)&dstSeqs[i], - store_data, - vl - ); - // Find the first index where an overflow occurs - int first_ml = __riscv_vfirst_m_b16(ml_overflow, vl); - int first_lit = __riscv_vfirst_m_b16(lit_overflow, vl); + // Pack two 16-bit fields into a 32-bit value (little-endian) + // The lower 16 bits contain litLength, and the upper 16 bits contain mlBase + vuint32m2_t v_lit_ml_combined = __riscv_vsll_vx_u32m2( + __riscv_vwcvtu_x_x_v_u32m2(v_ml_clamped, vl), // Convert matchLength to 32-bit + 16, + vl + ); + v_lit_ml_combined = __riscv_vor_vv_u32m2( + v_lit_ml_combined, + __riscv_vwcvtu_x_x_v_u32m2(v_lit_clamped, vl), + vl + ); + { + // Create a vector of SeqDef structures + // Store the offBase, litLength, and mlBase in a vector of SeqDef + vuint32m2x2_t store_data = __riscv_vcreate_v_u32m2x2( + v_offBase, + v_lit_ml_combined + ); + __riscv_vsseg2e32_v_u32m2x2( + (aliased_u32*)((void*)&dstSeqs[i]), + store_data, + vl + ); + } + { + // Find the first index where an overflow occurs + int first_ml = __riscv_vfirst_m_b16(ml_overflow, vl); + int first_lit = __riscv_vfirst_m_b16(lit_overflow, vl); - if (UNLIKELY(first_ml != -1)) { - assert(longLen == 0); - longLen = i + first_ml + 1; - } - if (UNLIKELY(first_lit != -1)) { - assert(longLen == 0); - longLen = i + first_lit + 1 + nbSequences; + if (UNLIKELY(first_ml != -1)) { + assert(longLen == 0); + longLen = i + first_ml + 1; + } + if (UNLIKELY(first_lit != -1)) { + assert(longLen == 0); + longLen = i + first_lit + 1 + nbSequences; + } + } } } return longLen; @@ -7547,18 +7554,17 @@ BlockSummary ZSTD_get1BlockSummary(const ZSTD_Sequence* seqs, size_t nbSeqs) size_t i = 0; int found_terminator = 0; size_t vl_max = __riscv_vsetvlmax_e32m1(); + typedef uint32_t __attribute__((may_alias)) aliased_u32; vuint32m1_t v_lit_sum = __riscv_vmv_v_x_u32m1(0, vl_max); vuint32m1_t v_match_sum = __riscv_vmv_v_x_u32m1(0, vl_max); for (; i < nbSeqs; ) { size_t vl = __riscv_vsetvl_e32m2(nbSeqs - i); - ptrdiff_t stride = sizeof(ZSTD_Sequence); // 16 vuint32m2x4_t v_tuple = __riscv_vlseg4e32_v_u32m2x4( - (const int32_t*)&seqs[i], + (const aliased_u32*)((const void*)&seqs[i]), vl ); - vuint32m2_t v_offset = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 0); vuint32m2_t v_lit = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 1); vuint32m2_t v_match = __riscv_vget_v_u32m2x4_u32m2(v_tuple, 2); From d04e7944dddd07962baa1f6e00c6cb0a92ca891c Mon Sep 17 00:00:00 2001 From: ZijianLi Date: Mon, 7 Jul 2025 23:07:39 +0800 Subject: [PATCH 132/245] add compiler version check. --- lib/common/compiler.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/common/compiler.h b/lib/common/compiler.h index 6131ad068..410068de4 100644 --- a/lib/common/compiler.h +++ b/lib/common/compiler.h @@ -224,9 +224,17 @@ # if defined(__ARM_FEATURE_SVE2) # define ZSTD_ARCH_ARM_SVE2 # endif -# if defined(__riscv) && defined(__riscv_vector) -# define ZSTD_ARCH_RISCV_RVV -# endif +#if defined(__riscv) && defined(__riscv_vector) + #if defined(__GNUC__) + #if (__GNUC__ > 14 || (__GNUC__ == 14 && __GNUC_MINOR__ >= 1)) + #define ZSTD_ARCH_RISCV_RVV + #endif + #elif defined(__clang__) + #if __clang_major__ > 18 || (__clang_major__ == 18 && __clang_minor__ >= 1) + #define ZSTD_ARCH_RISCV_RVV + #endif + #endif +#endif # # if defined(ZSTD_ARCH_X86_AVX2) # include From 8e4400463adc7bc7633641d6a485cfef4f28bc31 Mon Sep 17 00:00:00 2001 From: Arpad Panyik Date: Tue, 8 Jul 2025 17:05:45 +0000 Subject: [PATCH 133/245] Improve ZSTD_get1BlockSummary Add a faster scalar implementation of ZSTD_get1BlockSummary which removes the data dependency of the accumulators in the hot loop to leverage the superscalar potential of recent out-of-order CPUs. The new algorithm leverages SWAR (SIMD Within A Register) methodology to exploit the capabilities of 64-bit architectures. It achieves this by packing two 32-bit data elements into a single 64-bit register, enabling parallel operations on these subcomponents while ensuring that the 32-bit boundaries prevent overflow, thereby optimizing computational efficiency. Corresponding unit tests are included. Relative performance to GCC-13 using: `./fullbench -b19 -l5 enwik5` Neoverse-V2 before after GCC-13: 100.000% 290.527% GCC-14: 100.000% 291.714% GCC-15: 99.914% 291.495% Clang-18: 148.072% 264.524% Clang-19: 148.075% 264.512% Clang-20: 148.062% 264.490% Cortex-A720 before after GCC-13: 100.000% 235.261% GCC-14: 101.064% 234.903% GCC-15: 112.977% 218.547% Clang-18: 127.135% 180.359% Clang-19: 127.149% 180.297% Clang-20: 127.154% 180.260% Co-authored by, Thomas Daubney --- lib/compress/zstd_compress.c | 101 ++++++++++++++++++++++++++++++----- tests/fuzzer.c | 83 ++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 13 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 9b7aaf9f4..16423f6ee 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -7604,29 +7604,104 @@ BlockSummary ZSTD_get1BlockSummary(const ZSTD_Sequence* seqs, size_t nbSeqs) #else +/* + * The function assumes `litMatchLength` is a packed 64-bit value where the + * lower 32 bits represent the match length. The check varies based on the + * system's endianness: + * - On little-endian systems, it verifies if the entire 64-bit value is at most + * 0xFFFFFFFF, indicating the match length (lower 32 bits) is zero. + * - On big-endian systems, it directly checks if the lower 32 bits are zero. + * + * @returns 1 if the match length is zero, 0 otherwise. + */ +FORCE_INLINE_TEMPLATE int matchLengthHalfIsZero(U64 litMatchLength) +{ + if (MEM_isLittleEndian()) { + return litMatchLength <= 0xFFFFFFFFULL; + } else { + return (U32)litMatchLength == 0; + } +} + BlockSummary ZSTD_get1BlockSummary(const ZSTD_Sequence* seqs, size_t nbSeqs) { - size_t totalMatchSize = 0; - size_t litSize = 0; - size_t n; + /* Use multiple accumulators for efficient use of wide out-of-order machines. */ + U64 litMatchSize0 = 0; + U64 litMatchSize1 = 0; + U64 litMatchSize2 = 0; + U64 litMatchSize3 = 0; + size_t n = 0; + + ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, litLength) + 4 == offsetof(ZSTD_Sequence, matchLength)); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, matchLength) + 4 == offsetof(ZSTD_Sequence, rep)); assert(seqs); - for (n=0; n 3) { + /* Process the input in 4 independent streams to reach high throughput. */ + do { + /* Load `litLength` and `matchLength` as a packed `U64`. It is safe + * to use 64-bit unsigned arithmetic here because the sum of `litLength` + * and `matchLength` cannot exceed the block size, so the 32-bit + * subparts will never overflow. */ + U64 litMatchLength = MEM_read64(&seqs[n].litLength); + litMatchSize0 += litMatchLength; + if (matchLengthHalfIsZero(litMatchLength)) { + assert(seqs[n].offset == 0); + goto _out; + } + + litMatchLength = MEM_read64(&seqs[n + 1].litLength); + litMatchSize1 += litMatchLength; + if (matchLengthHalfIsZero(litMatchLength)) { + n += 1; + assert(seqs[n].offset == 0); + goto _out; + } + + litMatchLength = MEM_read64(&seqs[n + 2].litLength); + litMatchSize2 += litMatchLength; + if (matchLengthHalfIsZero(litMatchLength)) { + n += 2; + assert(seqs[n].offset == 0); + goto _out; + } + + litMatchLength = MEM_read64(&seqs[n + 3].litLength); + litMatchSize3 += litMatchLength; + if (matchLengthHalfIsZero(litMatchLength)) { + n += 3; + assert(seqs[n].offset == 0); + goto _out; + } + + n += 4; + } while(n < nbSeqs - 3); + } + + for (; n < nbSeqs; n++) { + U64 litMatchLength = MEM_read64(&seqs[n].litLength); + litMatchSize0 += litMatchLength; + if (matchLengthHalfIsZero(litMatchLength)) { assert(seqs[n].offset == 0); - break; + goto _out; } } - if (n==nbSeqs) { - BlockSummary bs; + /* At this point n == nbSeqs, so no end terminator. */ + { BlockSummary bs; bs.nbSequences = ERROR(externalSequences_invalid); return bs; } +_out: + litMatchSize0 += litMatchSize1 + litMatchSize2 + litMatchSize3; { BlockSummary bs; - bs.nbSequences = n+1; - bs.blockSize = litSize + totalMatchSize; - bs.litSize = litSize; + bs.nbSequences = n + 1; + if (MEM_isLittleEndian()) { + bs.litSize = (U32)litMatchSize0; + bs.blockSize = bs.litSize + (litMatchSize0 >> 32); + } else { + bs.litSize = litMatchSize0 >> 32; + bs.blockSize = bs.litSize + (U32)litMatchSize0; + } return bs; } } diff --git a/tests/fuzzer.c b/tests/fuzzer.c index da380aced..8e30d207d 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -45,6 +45,7 @@ #include "zstd_internal.h" /* ZSTD_WORKSPACETOOLARGE_MAXDURATION, ZSTD_WORKSPACETOOLARGE_FACTOR, KB, MB */ #include "threading.h" /* ZSTD_pthread_create, ZSTD_pthread_join */ #include "compress/hist.h" /* HIST_count_wksp */ +#include "compress/zstd_compress_internal.h" /* ZSTD_get1BlockSummary */ /*-************************************ @@ -769,6 +770,86 @@ static void test_blockSplitter_incompressibleExpansionProtection(unsigned testNb DISPLAYLEVEL(3, "OK \n"); } +static unsigned test_get1BlockSummary(unsigned testNb) +{ + static const ZSTD_Sequence nseqs[] = { + { 10, 2, 4, 1 }, + { 20, 3, 5, 2 }, + { 30, 6, 8, 3 }, + { 40, 7, 9, 4 }, + { 50, 10, 12, 5 }, + { 60, 11, 13, 6 }, + { 0, 14, 0, 7 }, + { 70, 15, 17, 8 }, + { 80, 16, 18, 9 }, + { 90, 19, 21, 1 }, + { 99, 20, 22, 2 }, + }; + static const BlockSummary blocks[] = { + { 7, 104, 53 }, + { 6, 98, 51 }, + { 5, 90, 48 }, + { 4, 76, 42 }, + { 3, 60, 35 }, + { 2, 38, 25 }, + { 1, 14, 14 }, + }; + size_t i; + + DISPLAYLEVEL(3, "test%3u : ZSTD_get1BlockSummary with empty array : ", testNb++); + { + BlockSummary bs = ZSTD_get1BlockSummary(nseqs, 0); + CHECK_EQ(bs.nbSequences, ERROR(externalSequences_invalid)); + } + DISPLAYLEVEL(3, "OK \n"); + + DISPLAYLEVEL(3, "test%3u : ZSTD_get1BlockSummary with 1 literal only : ", testNb++); + { + static const ZSTD_Sequence seqs[] = { { 0, 5, 0, 0 } }; + BlockSummary bs = ZSTD_get1BlockSummary(seqs, 1); + CHECK_EQ(bs.nbSequences, 1); + CHECK_EQ(bs.litSize, 5); + CHECK_EQ(bs.blockSize, 5); + } + DISPLAYLEVEL(3, "OK \n"); + + DISPLAYLEVEL(3, "test%3u : ZSTD_get1BlockSummary with no terminator : ", testNb++); + { + static const ZSTD_Sequence seqs[] = { { 10, 2, 4, 0 }, { 20, 3, 5, 0 } }; + BlockSummary bs = ZSTD_get1BlockSummary(seqs, 2); + CHECK_EQ(bs.nbSequences, ERROR(externalSequences_invalid)); + } + DISPLAYLEVEL(3, "OK \n"); + + DISPLAYLEVEL(3, "test%3u : ZSTD_get1BlockSummary with rep ignored : ", testNb++); + { + static const ZSTD_Sequence seqs[] = { + { 10, 2, 4, 2 }, + { 10, 3, 5, 2 }, + { 0, 7, 0, 3 }, + }; + BlockSummary bs = ZSTD_get1BlockSummary(seqs, 3); + CHECK_EQ(bs.nbSequences, 3); + CHECK_EQ(bs.litSize, 2 + 3 + 7); + CHECK_EQ(bs.blockSize, (4 + 5) + (2 + 3 + 7)); + } + DISPLAYLEVEL(3, "OK \n"); + + assert(COUNTOF(nseqs) > COUNTOF(blocks)); + for (i = 0; i < COUNTOF(blocks); ++i) { + BlockSummary bs; + DISPLAYLEVEL(3, "test%3u : ZSTD_get1BlockSummary with %u inputs : ", + testNb++, (unsigned)(COUNTOF(nseqs) - i)); + bs = ZSTD_get1BlockSummary(nseqs + i, COUNTOF(nseqs) - i); + CHECK_EQ(bs.nbSequences, blocks[i].nbSequences); + CHECK_EQ(bs.litSize, blocks[i].litSize); + CHECK_EQ(bs.blockSize, blocks[i].blockSize); + DISPLAYLEVEL(3, "OK \n"); + } + + return testNb; +} + /* ============================================================= */ static int basicUnitTests(U32 const seed, double compressibility) @@ -4004,6 +4085,8 @@ static int basicUnitTests(U32 const seed, double compressibility) } DISPLAYLEVEL(3, "OK \n"); + testNb = test_get1BlockSummary(testNb); + DISPLAYLEVEL(3, "test%3i : ZSTD_compressSequencesAndLiterals : ", testNb++); { const size_t srcSize = 497000; From 07cd78d3668271cffc9b586d857455bf47aef4fb Mon Sep 17 00:00:00 2001 From: Arpad Panyik Date: Tue, 8 Jul 2025 17:07:41 +0000 Subject: [PATCH 134/245] AArch64: Add Neon path for convertSequences_noRepcodes Add a 4-way Neon implementation for the convertSequences_noRepcodes function. Remove 'static' keywords from all of its implementations to be able to add unit tests. Relative performance to Clang-18 using: `./fullbench -b18 -l5 enwik5` Neoverse-V2 before after Clang-18: 100.000% 311.703% Clang-19: 100.191% 311.714% Clang-20: 100.181% 311.723% GCC-13: 107.520% 252.309% GCC-14: 107.652% 253.158% GCC-15: 107.674% 253.168% Cortex-A720 before after Clang-18: 100.000% 204.512% Clang-19: 102.825% 204.600% Clang-20: 102.807% 204.558% GCC-13: 110.668% 203.594% GCC-14: 110.684% 203.978% GCC-15: 102.864% 204.299% Co-authored by, Thomas Daubney --- lib/compress/zstd_compress.c | 142 +++++++++++++++++++++++++++++++++-- tests/fuzzer.c | 126 +++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 6 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 16423f6ee..008eaba35 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -56,6 +56,14 @@ # define ZSTD_HASHLOG3_MAX 17 #endif + +/*-************************************* +* Forward declarations +***************************************/ +size_t convertSequences_noRepcodes(SeqDef* dstSeqs, const ZSTD_Sequence* inSeqs, + size_t nbSequences); + + /*-************************************* * Helper functions ***************************************/ @@ -7118,7 +7126,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* cctx, } -#if defined(__AVX2__) +#if defined(ZSTD_ARCH_X86_AVX2) #include /* AVX2 intrinsics */ @@ -7138,7 +7146,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* cctx, * @returns > 0 if there is one long length (> 65535), * indicating the position, and type. */ -static size_t convertSequences_noRepcodes( +size_t convertSequences_noRepcodes( SeqDef* dstSeqs, const ZSTD_Sequence* inSeqs, size_t nbSequences) @@ -7298,7 +7306,7 @@ static size_t convertSequences_noRepcodes( * @returns > 0 if there is one long length (> 65535), * indicating the position, and type. */ -static size_t convertSequences_noRepcodes(SeqDef* dstSeqs, const ZSTD_Sequence* inSeqs, size_t nbSequences) { +size_t convertSequences_noRepcodes(SeqDef* dstSeqs, const ZSTD_Sequence* inSeqs, size_t nbSequences) { size_t longLen = 0; /* RVV depends on the specific definition of target structures */ @@ -7375,9 +7383,131 @@ static size_t convertSequences_noRepcodes(SeqDef* dstSeqs, const ZSTD_Sequence* * but since this implementation is targeting modern systems (>= Sapphire Rapid), * it's not useful to develop and maintain code for older pre-AVX2 platforms */ -#else /* no AVX2 */ +#elif defined(ZSTD_ARCH_ARM_NEON) && (defined(__aarch64__) || defined(_M_ARM64)) -static size_t convertSequences_noRepcodes( +size_t convertSequences_noRepcodes( + SeqDef* dstSeqs, + const ZSTD_Sequence* inSeqs, + size_t nbSequences) +{ + size_t longLen = 0; + size_t n = 0; + + /* Neon permutation depends on the specific definition of target structures. */ + ZSTD_STATIC_ASSERT(sizeof(ZSTD_Sequence) == 16); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, offset) == 0); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, litLength) == 4); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, matchLength) == 8); + ZSTD_STATIC_ASSERT(sizeof(SeqDef) == 8); + ZSTD_STATIC_ASSERT(offsetof(SeqDef, offBase) == 0); + ZSTD_STATIC_ASSERT(offsetof(SeqDef, litLength) == 4); + ZSTD_STATIC_ASSERT(offsetof(SeqDef, mlBase) == 6); + + if (nbSequences > 3) { + static const ZSTD_ALIGNED(16) U32 constAddition[4] = { + ZSTD_REP_NUM, 0, -MINMATCH, 0 + }; + static const ZSTD_ALIGNED(16) U8 constMask[16] = { + 0, 1, 2, 3, 4, 5, 8, 9, 16, 17, 18, 19, 20, 21, 24, 25 + }; + static const ZSTD_ALIGNED(16) U16 constCounter[8] = { + 1, 1, 1, 1, 2, 2, 2, 2 + }; + + const uint32x4_t vaddition = vld1q_u32(constAddition); + const uint8x16_t vmask = vld1q_u8(constMask); + uint16x8_t vcounter = vld1q_u16(constCounter); + uint16x8_t vindex01 = vdupq_n_u16(0); + uint16x8_t vindex23 = vdupq_n_u16(0); + + do { + /* Load 4 ZSTD_Sequence (64 bytes). */ + const uint32x4_t vin0 = vld1q_u32(&inSeqs[n + 0].offset); + const uint32x4_t vin1 = vld1q_u32(&inSeqs[n + 1].offset); + const uint32x4_t vin2 = vld1q_u32(&inSeqs[n + 2].offset); + const uint32x4_t vin3 = vld1q_u32(&inSeqs[n + 3].offset); + + /* Add {ZSTD_REP_NUM, 0, -MINMATCH, 0} to each vector. */ + const uint8x16x2_t vadd01 = { { + vreinterpretq_u8_u32(vaddq_u32(vin0, vaddition)), + vreinterpretq_u8_u32(vaddq_u32(vin1, vaddition)), + } }; + const uint8x16x2_t vadd23 = { { + vreinterpretq_u8_u32(vaddq_u32(vin2, vaddition)), + vreinterpretq_u8_u32(vaddq_u32(vin3, vaddition)), + } }; + + /* Shuffle and pack bytes so each vector contains 2 SeqDef structures. */ + const uint8x16_t vout01 = vqtbl2q_u8(vadd01, vmask); + const uint8x16_t vout23 = vqtbl2q_u8(vadd23, vmask); + + /* Pack the upper 16-bits of 32-bit lanes for overflow check. */ + uint16x8_t voverflow01 = vuzp2q_u16(vreinterpretq_u16_u8(vadd01.val[0]), + vreinterpretq_u16_u8(vadd01.val[1])); + uint16x8_t voverflow23 = vuzp2q_u16(vreinterpretq_u16_u8(vadd23.val[0]), + vreinterpretq_u16_u8(vadd23.val[1])); + + /* Store 4 SeqDef structures. */ + vst1q_u32(&dstSeqs[n + 0].offBase, vreinterpretq_u32_u8(vout01)); + vst1q_u32(&dstSeqs[n + 2].offBase, vreinterpretq_u32_u8(vout23)); + + /* Create masks in case of overflow. */ + voverflow01 = vcgtzq_s16(vreinterpretq_s16_u16(voverflow01)); + voverflow23 = vcgtzq_s16(vreinterpretq_s16_u16(voverflow23)); + + /* Update overflow indices. */ + vindex01 = vbslq_u16(voverflow01, vcounter, vindex01); + vindex23 = vbslq_u16(voverflow23, vcounter, vindex23); + + /* Update counter for overflow check. */ + vcounter = vaddq_u16(vcounter, vdupq_n_u16(4)); + + n += 4; + } while(n < nbSequences - 3); + + /* Fixup indices in the second vector, we saved an additional counter + in the loop to update the second overflow index, we need to add 2 + here when the indices are not 0. */ + { uint16x8_t nonzero = vtstq_u16(vindex23, vindex23); + vindex23 = vsubq_u16(vindex23, nonzero); + vindex23 = vsubq_u16(vindex23, nonzero); + } + + /* Merge indices in the vectors, maximums are needed. */ + vindex01 = vmaxq_u16(vindex01, vindex23); + vindex01 = vmaxq_u16(vindex01, vextq_u16(vindex01, vindex01, 4)); + + /* Compute `longLen`, maximums of matchLength and litLength + with a preference on litLength. */ + { U64 maxLitMatchIndices = vgetq_lane_u64(vreinterpretq_u64_u16(vindex01), 0); + size_t maxLitIndex = (maxLitMatchIndices >> 16) & 0xFFFF; + size_t maxMatchIndex = (maxLitMatchIndices >> 32) & 0xFFFF; + longLen = maxLitIndex > maxMatchIndex ? maxLitIndex + nbSequences + : maxMatchIndex; + } + } + + /* Handle remaining elements. */ + for (; n < nbSequences; n++) { + dstSeqs[n].offBase = OFFSET_TO_OFFBASE(inSeqs[n].offset); + dstSeqs[n].litLength = (U16)inSeqs[n].litLength; + dstSeqs[n].mlBase = (U16)(inSeqs[n].matchLength - MINMATCH); + /* Check for long length > 65535. */ + if (UNLIKELY(inSeqs[n].matchLength > 65535 + MINMATCH)) { + assert(longLen == 0); + longLen = n + 1; + } + if (UNLIKELY(inSeqs[n].litLength > 65535)) { + assert(longLen == 0); + longLen = n + nbSequences + 1; + } + } + return longLen; +} + +#else /* No vectorization. */ + +size_t convertSequences_noRepcodes( SeqDef* dstSeqs, const ZSTD_Sequence* inSeqs, size_t nbSequences) @@ -7388,7 +7518,7 @@ static size_t convertSequences_noRepcodes( dstSeqs[n].offBase = OFFSET_TO_OFFBASE(inSeqs[n].offset); dstSeqs[n].litLength = (U16)inSeqs[n].litLength; dstSeqs[n].mlBase = (U16)(inSeqs[n].matchLength - MINMATCH); - /* check for long length > 65535 */ + /* Check for long length > 65535. */ if (UNLIKELY(inSeqs[n].matchLength > 65535+MINMATCH)) { assert(longLen == 0); longLen = n + 1; diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 8e30d207d..0bc160efa 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -770,6 +770,130 @@ static void test_blockSplitter_incompressibleExpansionProtection(unsigned testNb DISPLAYLEVEL(3, "OK \n"); } +size_t convertSequences_noRepcodes(SeqDef* dstSeqs, const ZSTD_Sequence* inSeqs, + size_t nbSequences); + +static size_t convertSequences_noRepcodes_ref( + SeqDef* dstSeqs, + const ZSTD_Sequence* inSeqs, + size_t nbSequences) +{ + size_t longLen = 0; + size_t n; + for (n=0; n 65535. */ + if (UNLIKELY(inSeqs[n].matchLength > 65535+MINMATCH)) { + assert(longLen == 0); + longLen = n + 1; + } + if (UNLIKELY(inSeqs[n].litLength > 65535)) { + assert(longLen == 0); + longLen = n + nbSequences + 1; + } + } + return longLen; +} + +static unsigned test_convertSequences_noRepcodes(unsigned seed, unsigned testNb) +{ + ZSTD_Sequence nsrc[12]; + SeqDef ndst[12], rdst[12]; + size_t ref, ret, i, j; + + seed += 0xDEADBEEF; + for (i = 0; i < COUNTOF(nsrc); ++i) { + seed = 48271 * ((unsigned)i + seed); + nsrc[i].offset = (seed & 0xFFFF) | 1; /* Offset shall not be zero. */ + seed = 48271 * ((unsigned)i + seed); + nsrc[i].litLength = seed & 0xFFFF; + seed = 48271 * ((unsigned)i + seed); + nsrc[i].matchLength = (seed & 0xFFFFFF) % (65536 + MINMATCH); + seed = 48271 * ((unsigned)i + seed); + nsrc[i].rep = seed & 0xFF; + } + + /* For near overflow and proper negative value handling. */ + nsrc[5].matchLength = 65535 + MINMATCH; + nsrc[6].litLength = 65535; + nsrc[6].matchLength = 0; + nsrc[7].litLength = 0; + nsrc[7].matchLength = MINMATCH; + + for (i = 0; i <= COUNTOF(nsrc); ++i) { + DISPLAYLEVEL(3, "test%3u : convertSequences_noRepcodes with %u inputs : ", + testNb++, (unsigned)i); + memset(ndst, 0, sizeof(ndst)); + memset(rdst, 0, sizeof(rdst)); + ref = convertSequences_noRepcodes_ref(rdst, nsrc, i); + ret = convertSequences_noRepcodes(ndst, nsrc, i); + CHECK_EQ(ret, ref); + CHECK_EQ(memcmp(rdst, ndst, sizeof(ndst)), 0); + DISPLAYLEVEL(3, "OK \n"); + } + + nsrc[7].matchLength = 65536 + MINMATCH; + for (i = 8; i <= COUNTOF(nsrc); ++i) { + DISPLAYLEVEL(3, "test%3u : convertSequences_noRepcodes with %u inputs and " + "matchLength overflow : ", + testNb++, (unsigned)i); + memset(ndst, 0, sizeof(ndst)); + memset(rdst, 0, sizeof(rdst)); + ref = convertSequences_noRepcodes_ref(rdst, nsrc, i); + ret = convertSequences_noRepcodes(ndst, nsrc, i); + CHECK_EQ(ret, ref); + CHECK_EQ(memcmp(rdst, ndst, sizeof(ndst)), 0); + DISPLAYLEVEL(3, "OK \n"); + + assert(COUNTOF(nsrc) > 8); + for (j = 4; j < 8; ++j) { + DISPLAYLEVEL(3, "test%3u : convertSequences_noRepcodes with %u inputs and " + "matchLength overflow #%u : ", + testNb++, (unsigned)i, (unsigned)(i - j)); + memset(ndst, 0, sizeof(ndst)); + memset(rdst, 0, sizeof(rdst)); + ref = convertSequences_noRepcodes_ref(rdst, nsrc + j, i - j); + ret = convertSequences_noRepcodes(ndst, nsrc + j, i - j); + CHECK_EQ(ret, ref); + CHECK_EQ(memcmp(rdst, ndst, sizeof(ndst)), 0); + DISPLAYLEVEL(3, "OK \n"); + } + } + nsrc[7].matchLength = 1; + + nsrc[7].litLength = 65536; + for (i = 8; i <= COUNTOF(nsrc); ++i) { + DISPLAYLEVEL(3, "test%3u : convertSequences_noRepcodes with %u inputs and " + "litLength overflow: ", + testNb++, (unsigned)i); + memset(ndst, 0, sizeof(ndst)); + memset(rdst, 0, sizeof(rdst)); + ref = convertSequences_noRepcodes_ref(rdst, nsrc, i); + ret = convertSequences_noRepcodes(ndst, nsrc, i); + CHECK_EQ(ret, ref); + CHECK_EQ(memcmp(rdst, ndst, sizeof(ndst)), 0); + DISPLAYLEVEL(3, "OK \n"); + + assert(COUNTOF(nsrc) > 8); + for (j = 4; j < 8; ++j) { + DISPLAYLEVEL(3, "test%3u : convertSequences_noRepcodes with %u inputs and " + "litLength overflow #%u: ", + testNb++, (unsigned)i, (unsigned)(i - j)); + memset(ndst, 0, sizeof(ndst)); + memset(rdst, 0, sizeof(rdst)); + ref = convertSequences_noRepcodes_ref(rdst, nsrc + j, i - j); + ret = convertSequences_noRepcodes(ndst, nsrc + j, i - j); + CHECK_EQ(ret, ref); + CHECK_EQ(memcmp(rdst, ndst, sizeof(ndst)), 0); + DISPLAYLEVEL(3, "OK \n"); + } + } + + return testNb; +} + static unsigned test_get1BlockSummary(unsigned testNb) { static const ZSTD_Sequence nseqs[] = { @@ -4085,6 +4209,8 @@ static int basicUnitTests(U32 const seed, double compressibility) } DISPLAYLEVEL(3, "OK \n"); + testNb = test_convertSequences_noRepcodes(seed, testNb); + testNb = test_get1BlockSummary(testNb); DISPLAYLEVEL(3, "test%3i : ZSTD_compressSequencesAndLiterals : ", testNb++); From 703f85573467da90f41d729117f75868b91be5cb Mon Sep 17 00:00:00 2001 From: Arpad Panyik Date: Tue, 8 Jul 2025 17:09:09 +0000 Subject: [PATCH 135/245] AArch64: Enable optimized QEMU CI builds Add missing `-O3` flag to the compilation of AArch64 SVE2 builds executed by QEMU. This can decrease the CI job runtime considerably. --- .github/workflows/dev-short-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 53f640dae..af6a2997a 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -435,8 +435,8 @@ jobs: make clean LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j check LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j -C tests test-cli-tests - CFLAGS="-march=armv8.2-a+sve2" LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j check - CFLAGS="-march=armv8.2-a+sve2" LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j -C tests test-cli-tests + CFLAGS="-O3 -march=armv8.2-a+sve2" LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j check + CFLAGS="-O3 -march=armv8.2-a+sve2" LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j -C tests test-cli-tests # This test is only compatible with standard libraries that support BTI (Branch Target Identification). # Unfortunately, the standard library provided on Ubuntu 24.04 does not have this feature enabled. # make clean From 7325384a68f7bfc321740acd662ffa8b43ffeaa7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 11 Jul 2025 10:29:07 -0700 Subject: [PATCH 136/245] removed VS2019 runners replaced by one vs2025 runner, which is badly named since it still running MSVC 2022, but it's a good test that shows that the matrix is able to handle multiple MSVC versions. --- .github/workflows/dev-short-tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 53f640dae..e8c663036 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -314,8 +314,7 @@ jobs: { name: "VS 2022 Win32 Debug", platform: Win32, configuration: Debug, toolset: v143, runner: "windows-2022", arch: "" }, { name: "VS 2022 x64 Release", platform: x64, configuration: Release, toolset: v143, runner: "windows-2022", arch: ""}, { name: "VS 2022 Win32 Release", platform: Win32, configuration: Release, toolset: v143, runner: "windows-2022", arch: ""}, - { name: "VS 2019 x64 Release", platform: Win32, configuration: Release, toolset: v142, runner: "windows-2019", arch: ""}, - { name: "VS 2019 Win32 Release", platform: x64, configuration: Release, toolset: v142, runner: "windows-2019", arch: ""}, + { name: "VS 2025 x64 Debug", platform: x64, configuration: Debug, toolset: v143, runner: "windows-2025", arch: ""}, { name: "VS 2022 x64 Release AVX2", platform: x64, configuration: Release, toolset: v143, runner: "windows-2022", arch: "AdvancedVectorExtensions2" }, ] runs-on: ${{matrix.runner}} From 534860c90b7e3bd605ea94bdde176baaaa3be9fb Mon Sep 17 00:00:00 2001 From: ZijianLi Date: Sun, 13 Jul 2025 10:46:00 +0800 Subject: [PATCH 137/245] add -DMEM_FORCE_MEMORY_ACCESS=0 in CI RVV test --- .github/workflows/dev-short-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index c954353e2..97fc3ffa6 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -461,9 +461,9 @@ jobs: if: ${{ matrix.name == 'RISC-V' }} run: | LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make clean check - CFLAGS="-march=rv64gcv -O3" LDFLAGS="-static" CC=$XCC QEMU_SYS="$XEMU -cpu rv64,v=true,vlen=128" make clean check - CFLAGS="-march=rv64gcv -O3" LDFLAGS="-static" CC=$XCC QEMU_SYS="$XEMU -cpu rv64,v=true,vlen=256" make clean check - CFLAGS="-march=rv64gcv -O3" LDFLAGS="-static" CC=$XCC QEMU_SYS="$XEMU -cpu rv64,v=true,vlen=512" make clean check + CFLAGS="-march=rv64gcv -O3" LDFLAGS="-static -DMEM_FORCE_MEMORY_ACCESS=0" CC=$XCC QEMU_SYS="$XEMU -cpu rv64,v=true,vlen=128" make clean check + CFLAGS="-march=rv64gcv -O3" LDFLAGS="-static -DMEM_FORCE_MEMORY_ACCESS=0" CC=$XCC QEMU_SYS="$XEMU -cpu rv64,v=true,vlen=256" make clean check + CFLAGS="-march=rv64gcv -O3" LDFLAGS="-static -DMEM_FORCE_MEMORY_ACCESS=0" CC=$XCC QEMU_SYS="$XEMU -cpu rv64,v=true,vlen=512" make clean check - name: M68K if: ${{ matrix.name == 'M68K' }} run: | From 3ce4d1cba3d61fa95099621a161cf8a5945cf19b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 06:27:46 +0000 Subject: [PATCH 138/245] Bump cygwin/cygwin-install-action from 5 to 6 Bumps [cygwin/cygwin-install-action](https://github.com/cygwin/cygwin-install-action) from 5 to 6. - [Release notes](https://github.com/cygwin/cygwin-install-action/releases) - [Commits](https://github.com/cygwin/cygwin-install-action/compare/f61179d72284ceddc397ed07ddb444d82bf9e559...f2009323764960f80959895c7bc3bb30210afe4d) --- updated-dependencies: - dependency-name: cygwin/cygwin-install-action dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/dev-short-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index e8c663036..1b524392a 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -541,7 +541,7 @@ jobs: steps: - run: git config --global core.autocrlf input - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 - - uses: cygwin/cygwin-install-action@f61179d72284ceddc397ed07ddb444d82bf9e559 # tag=v5 + - uses: cygwin/cygwin-install-action@f2009323764960f80959895c7bc3bb30210afe4d # tag=v6 with: platform: x86_64 packages: >- From 0055ce7a02cb39b55ffc6bc468641ecbb65e90a4 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 18 Jul 2025 21:21:47 -0700 Subject: [PATCH 139/245] simplify sequence resolution in zstd_opt initially hinted by @pitaj in #4442 --- lib/compress/zstd_opt.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/compress/zstd_opt.c b/lib/compress/zstd_opt.c index 3d7171b75..562a6b17b 100644 --- a/lib/compress/zstd_opt.c +++ b/lib/compress/zstd_opt.c @@ -1382,16 +1382,8 @@ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */ assert(storeEnd < ZSTD_OPT_SIZE); DEBUGLOG(6, "last stretch copied into pos=%u (llen=%u,mlen=%u,ofc=%u)", storeEnd, lastStretch.litlen, lastStretch.mlen, lastStretch.off); - if (lastStretch.litlen > 0) { - /* last "sequence" is unfinished: just a bunch of literals */ - opt[storeEnd].litlen = lastStretch.litlen; - opt[storeEnd].mlen = 0; - storeStart = storeEnd-1; - opt[storeStart] = lastStretch; - } { - opt[storeEnd] = lastStretch; /* note: litlen will be fixed */ - storeStart = storeEnd; - } + opt[storeEnd] = lastStretch; /* note: litlen will be fixed */ + storeStart = storeEnd; while (1) { ZSTD_optimal_t nextStretch = opt[stretchPos]; opt[storeStart].litlen = nextStretch.litlen; From 3b23f0c673ceb365fe2d28e00f40246fce5e0e8e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 23 Jul 2025 14:54:18 -0700 Subject: [PATCH 140/245] added android cmake build is expecte to fail, due to #4444 --- .github/workflows/android-ndk-build.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index 7ba3958b8..395359fda 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -37,3 +37,14 @@ jobs: RANLIB=llvm-ranlib \ STRIP=llvm-strip + - name: Build with CMake and NDK + run: | + mkdir -p build-android + cd build-android + cmake --version + cmake ../build/cmake \ + -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \ + -DANDROID_ABI=arm64-v8a \ + -DANDROID_PLATFORM=android-21 \ + -DCMAKE_BUILD_TYPE=Release + cmake --build . --parallel From 96f316a246b2274616e10c1e5e51256756a3d2f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 06:30:43 +0000 Subject: [PATCH 141/245] Bump github/codeql-action from 3.28.9 to 3.29.4 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.9 to 3.29.4. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0...4e828ff8d448a8a6e532957b1811f387a63867e8) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.29.4 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 47d528503..d49f3e836 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,6 +59,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # tag=v3.28.9 + uses: github/codeql-action/upload-sarif@4e828ff8d448a8a6e532957b1811f387a63867e8 # tag=v3.29.4 with: sarif_file: results.sarif From 8bca04ba9f2c3bc53b9bd4973875a55f8ed5583f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 23 Jul 2025 15:59:23 -0700 Subject: [PATCH 142/245] regroup list of OSes for install inside common variable within lib/install_oses.mk. fixes #4445 --- Makefile | 5 ++++- lib/Makefile | 14 +++++++------- lib/install_oses.mk | 17 +++++++++++++++++ lib/libzstd.mk | 5 ++++- programs/Makefile | 16 ++++++++-------- 5 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 lib/install_oses.mk diff --git a/Makefile b/Makefile index c9a640cba..b726f7970 100644 --- a/Makefile +++ b/Makefile @@ -144,10 +144,13 @@ clean: $(Q)$(RM) -r lz4 cmakebuild mesonbuild install @echo Cleaning completed +LIBZSTD_MK_DIR = $(ZSTDDIR) +include $(LIBZSTD_MK_DIR)/install_oses.mk # UNAME, INSTALL_OS_LIST + #------------------------------------------------------------------------------ # make install is validated only for Linux, macOS, Hurd and some BSD targets #------------------------------------------------------------------------------ -ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD DragonFly NetBSD MSYS_NT% CYGWIN_NT% Haiku AIX,$(shell sh -c 'MSYSTEM="MSYS" uname') )) +ifneq (,$(filter $(INSTALL_OS_LIST),$(UNAME))) HOST_OS = POSIX diff --git a/lib/Makefile b/lib/Makefile index e9a50a8f7..569bd6090 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -128,7 +128,7 @@ $(ZSTD_STATICLIB): $(ZSTD_STATICLIB_OBJ) $(AR) $(ARFLAGS) $@ $^ libzstd.a: $(ZSTD_STATICLIB) - cp -f $< $@ + $(CP) $< $@ endif @@ -168,11 +168,11 @@ $(ZSTD_DYNLIB): $(ZSTD_DYNLIB_OBJ) @echo compiling single-threaded dynamic library $(LIBVER)) $(CC) $(FLAGS) $^ $(SONAME_FLAGS) -o $@ @echo creating versioned links - ln -sf $@ libzstd.$(SHARED_EXT_MAJOR) - ln -sf $@ libzstd.$(SHARED_EXT) + $(LN) -sf $@ libzstd.$(SHARED_EXT_MAJOR) + $(LN) -sf $@ libzstd.$(SHARED_EXT) $(LIBZSTD): $(ZSTD_DYNLIB) - cp -f $< $@ + $(CP) $< $@ endif # ifndef BUILD_DIR endif # if windows @@ -268,7 +268,7 @@ clean: #----------------------------------------------------------------------------- # make install is validated only for below listed environments #----------------------------------------------------------------------------- -ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku AIX MSYS_NT% CYGWIN_NT%,$(UNAME))) +ifneq (,$(filter $(INSTALL_OS_LIST),$(UNAME))) lib: libzstd.pc @@ -363,8 +363,8 @@ install-shared: [ -e $(DESTDIR)$(LIBDIR) ] || $(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)/ @echo Installing shared library $(INSTALL_PROGRAM) $(LIBZSTD) $(DESTDIR)$(LIBDIR) - ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) - ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT) + $(LN) -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) + $(LN) -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT) .PHONY: install-includes install-includes: diff --git a/lib/install_oses.mk b/lib/install_oses.mk new file mode 100644 index 000000000..c2cdd1635 --- /dev/null +++ b/lib/install_oses.mk @@ -0,0 +1,17 @@ +# ################################################################ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under both the BSD-style license (found in the +# LICENSE file in the root directory of this source tree) and the GPLv2 (found +# in the COPYING file in the root directory of this source tree). +# You may select, at your option, one of the above-listed licenses. +# ################################################################ + +# This included Makefile provides the following variables : +# UNAME, INSTALL_OS_LIST + +UNAME := $(shell sh -c 'MSYSTEM="MSYS" uname') + +# List of OSes for which target install is supported +INSTALL_OS_LIST ?= Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku AIX MSYS_NT% CYGWIN_NT% diff --git a/lib/libzstd.mk b/lib/libzstd.mk index 91bd4caf3..d1744973e 100644 --- a/lib/libzstd.mk +++ b/lib/libzstd.mk @@ -206,7 +206,10 @@ endif endif CPPFLAGS += -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) -UNAME := $(shell sh -c 'MSYSTEM="MSYS" uname') +# Include install_oses.mk from the same directory +include $(dir $(lastword $(MAKEFILE_LIST)))/install_oses.mk +LN ?= ln +CP ?= cp -f ifndef BUILD_DIR ifeq ($(UNAME), Darwin) diff --git a/programs/Makefile b/programs/Makefile index f4af5e981..94f2179d0 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -170,7 +170,7 @@ endif zstd : $(BUILD_DIR)/zstd if [ $(BIN_ISDIFFERENT) -eq 1 ]; then \ - cp -f $<$(EXT) $@$(EXT); \ + $(CP) $<$(EXT) $@$(EXT); \ echo zstd build completed; \ else \ echo zstd already built; \ @@ -271,7 +271,7 @@ zstd-dictBuilder: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_COMPRESS_SRC) $(ZDICT_SRC) zst CLEAN += zstdmt zstdmt: zstd - ln -sf zstd zstdmt + $(LN) -sf zstd zstdmt .PHONY: generate_res generate_res: $(RES64_FILE) $(RES32_FILE) @@ -345,7 +345,7 @@ include $(wildcard $(DEPFILES)) #----------------------------------------------------------------------------- # make install is validated only for Linux, macOS, BSD, Hurd and Solaris targets #----------------------------------------------------------------------------- -ifneq (,$(filter Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku AIX MSYS_NT% CYGWIN_NT%,$(UNAME))) +ifneq (,$(filter $(INSTALL_OS_LIST),$(UNAME))) HAVE_COLORNEVER = $(shell echo a | egrep --color=never a > /dev/null 2> /dev/null && echo 1 || echo 0) EGREP_OPTIONS ?= @@ -414,15 +414,15 @@ install: [ -e $(DESTDIR)$(MAN1DIR) ] || $(INSTALL) -d -m 755 $(DESTDIR)$(MAN1DIR)/ @echo Installing binaries $(INSTALL_PROGRAM) zstd$(EXT) $(DESTDIR)$(BINDIR)/zstd$(EXT) - ln -sf zstd$(EXT) $(DESTDIR)$(BINDIR)/zstdcat$(EXT) - ln -sf zstd$(EXT) $(DESTDIR)$(BINDIR)/unzstd$(EXT) - ln -sf zstd$(EXT) $(DESTDIR)$(BINDIR)/zstdmt$(EXT) + $(LN) -sf zstd$(EXT) $(DESTDIR)$(BINDIR)/zstdcat$(EXT) + $(LN) -sf zstd$(EXT) $(DESTDIR)$(BINDIR)/unzstd$(EXT) + $(LN) -sf zstd$(EXT) $(DESTDIR)$(BINDIR)/zstdmt$(EXT) $(INSTALL_SCRIPT) zstdless $(DESTDIR)$(BINDIR)/zstdless $(INSTALL_SCRIPT) zstdgrep $(DESTDIR)$(BINDIR)/zstdgrep @echo Installing man pages $(INSTALL_MAN) zstd.1 $(DESTDIR)$(MAN1DIR)/zstd.1 - ln -sf zstd.1 $(DESTDIR)$(MAN1DIR)/zstdcat.1 - ln -sf zstd.1 $(DESTDIR)$(MAN1DIR)/unzstd.1 + $(LN) -sf zstd.1 $(DESTDIR)$(MAN1DIR)/zstdcat.1 + $(LN) -sf zstd.1 $(DESTDIR)$(MAN1DIR)/unzstd.1 $(INSTALL_MAN) zstdgrep.1 $(DESTDIR)$(MAN1DIR)/zstdgrep.1 $(INSTALL_MAN) zstdless.1 $(DESTDIR)$(MAN1DIR)/zstdless.1 @echo zstd installation completed From 1e1db4732380530c01868837436f77defe49b7cb Mon Sep 17 00:00:00 2001 From: Margen67 Date: Sun, 17 Aug 2025 00:44:39 -0700 Subject: [PATCH 143/245] Remove need for trailing forward slash in dir --- contrib/premake/zstd.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/premake/zstd.lua b/contrib/premake/zstd.lua index df1ace3ee..f3fd5b293 100644 --- a/contrib/premake/zstd.lua +++ b/contrib/premake/zstd.lua @@ -2,6 +2,7 @@ -- Basic usage: project_zstd(ZSTD_DIR) function project_zstd(dir, compression, decompression, deprecated, dictbuilder, legacy) + if string.sub(dir, -1, 1) ~= '/' then dir = dir .. '/' end if compression == nil then compression = true end if decompression == nil then decompression = true end if deprecated == nil then deprecated = false end From 0e69452a30c9fa51282baaf8050197bda070aab1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 08:13:07 +0000 Subject: [PATCH 144/245] Bump actions/checkout from 4 to 5 Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/android-ndk-build.yml | 2 +- .github/workflows/cmake-tests.yml | 8 +- .github/workflows/commit.yml | 6 +- .github/workflows/dev-long-tests.yml | 54 ++++++------- .github/workflows/dev-short-tests.yml | 76 +++++++++---------- .github/workflows/nightly.yml | 2 +- .../workflows/publish-release-artifacts.yml | 2 +- .github/workflows/release_check.yml | 4 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 10 files changed, 79 insertions(+), 79 deletions(-) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index 395359fda..330d58ffe 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: Set up JDK 17 uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index b02385708..0ce2a7d8f 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -28,7 +28,7 @@ jobs: name: "CMake Ubuntu Basic Build" runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: Install dependencies run: | sudo apt install liblzma-dev # Required for compression algorithms @@ -58,7 +58,7 @@ jobs: env: SRC_DIR: "source directory with spaces" steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 with: path: "${{ env.SRC_DIR }}" - uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 @@ -116,7 +116,7 @@ jobs: runner: "windows-2022" cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON" steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: Add MSBuild to PATH uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0 - name: "Configure CMake (${{ matrix.name }})" @@ -141,7 +141,7 @@ jobs: name: "CMake macOS ARM64 (Apple Silicon)" runs-on: macos-14 # ARM64 runner steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: "CMake build and test (ARM64)" run: | # Configure and build with ARM64-specific optimizations diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 659072861..fe91f2fcc 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -17,7 +17,7 @@ jobs: image: fbopensource/zstd-circleci-primary:0.0.1 options: --entrypoint /bin/bash steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install Dependencies run: | sudo apt-get update @@ -40,7 +40,7 @@ jobs: image: fbopensource/zstd-circleci-primary:0.0.1 options: --entrypoint /bin/bash steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install Dependencies run: | sudo apt-get update @@ -73,7 +73,7 @@ jobs: env: CIRCLE_ARTIFACTS: "/tmp/circleci-artifacts" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: restore_cache uses: actions/cache@v4 with: diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 3fa971a34..caf86a11f 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -16,7 +16,7 @@ jobs: make-all: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: make all run: make all @@ -27,7 +27,7 @@ jobs: DEVNULLRIGHTS: 1 READFROMBLOCKDEVICE: 1 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: make test run: | make test @@ -38,7 +38,7 @@ jobs: make-test-macos: runs-on: macos-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: make test on macos run: make test @@ -49,7 +49,7 @@ jobs: DEVNULLRIGHTS: 1 READFROMBLOCKDEVICE: 1 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: make test # note: `make -j test success` seems to require a clean state run: | sudo apt-get -qqq update @@ -61,7 +61,7 @@ jobs: test-largeDictionary: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: largeDictionary run: | CFLAGS="-Werror -O3" make -j -C tests test-largeDictionary @@ -70,7 +70,7 @@ jobs: no-intrinsics-fuzztest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: no intrinsics fuzztest run: MOREFLAGS="-DZSTD_NO_INTRINSICS" make -C tests fuzztest @@ -78,14 +78,14 @@ jobs: tsan-zstreamtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: thread sanitizer zstreamtest run: CC=clang ZSTREAM_TESTTIME=-T3mn make tsan-test-zstream uasan-zstreamtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: ub + address sanitizer on zstreamtest run: CC=clang make uasan-test-zstream @@ -93,14 +93,14 @@ jobs: tsan-fuzztest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: thread sanitizer fuzztest run: CC=clang make tsan-fuzztest big-tests-zstreamtest32: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: zstream tests in 32bit mode, with big tests run: | sudo apt-get -qqq update @@ -111,7 +111,7 @@ jobs: gcc-8-asan-ubsan-testzstd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: gcc-8 + ASan + UBSan + Test Zstd # See https://askubuntu.com/a/1428822 run: | @@ -123,14 +123,14 @@ jobs: clang-asan-ubsan-testzstd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: clang + ASan + UBSan + Test Zstd run: CC=clang make -j uasan-test-zstd Date: Tue, 19 Aug 2025 09:23:38 -0400 Subject: [PATCH 145/245] Check for build environment instead of just _GNU_SOURCE Fixes the build on OpenBSD and NetBSD. It is too easy for _GNU_SOURCE to be defined even on non-Linux systems. Found via py-zstandard with the embedded copy of zstandard and Python defines _GNU_SOURCE. Also simplify the Linux checking, there is no need to check the rest of the symbol names. --- lib/dictBuilder/cover.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/dictBuilder/cover.c b/lib/dictBuilder/cover.c index 92c22a96c..06d1cb93a 100644 --- a/lib/dictBuilder/cover.c +++ b/lib/dictBuilder/cover.c @@ -21,10 +21,12 @@ /*-************************************* * Dependencies ***************************************/ -/* qsort_r is an extension. */ -#if defined(__linux) || defined(__linux__) || defined(linux) || defined(__gnu_linux__) || \ - defined(__CYGWIN__) || defined(__MSYS__) -# if !defined(_GNU_SOURCE) && !defined(__ANDROID__) /* NDK doesn't ship qsort_r(). */ +/* qsort_r is an extension. + * + * Android NDK does not ship qsort_r(). + */ +#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__CYGWIN__) || defined(__MSYS__) +# ifndef _GNU_SOURCE # define _GNU_SOURCE # endif #endif @@ -77,7 +79,7 @@ #ifndef ZDICT_QSORT # if defined(__APPLE__) # define ZDICT_QSORT ZDICT_QSORT_APPLE /* uses qsort_r() with a different order for parameters */ -# elif defined(_GNU_SOURCE) +# elif (defined(__linux__) && !defined(__ANDROID__)) || defined(__CYGWIN__) || defined(__MSYS__) # define ZDICT_QSORT ZDICT_QSORT_GNU /* uses qsort_r() */ # elif defined(_WIN32) && defined(_MSC_VER) # define ZDICT_QSORT ZDICT_QSORT_MSVC /* uses qsort_s() with a different order for parameters */ From ae64545c6b6257c226dca6240be7b2d345d9bee5 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 19 Aug 2025 17:13:15 -0700 Subject: [PATCH 146/245] fixed a potential division by 0 in the cli trace unit --- programs/zstdcli_trace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/programs/zstdcli_trace.c b/programs/zstdcli_trace.c index 35075a52c..f73071a5c 100644 --- a/programs/zstdcli_trace.c +++ b/programs/zstdcli_trace.c @@ -81,8 +81,9 @@ static void TRACE_log(char const* method, PTime duration, ZSTD_Trace const* trac { int level = 0; int workers = 0; + double const durationAsDouble = duration ? (double)duration : .1; double const ratio = (double)trace->uncompressedSize / (double)trace->compressedSize; - double const speed = ((double)trace->uncompressedSize * 1000) / (double)duration; + double const speed = ((double)trace->uncompressedSize * 1000) / durationAsDouble; if (trace->params) { ZSTD_CCtxParams_getParameter(trace->params, ZSTD_c_compressionLevel, &level); ZSTD_CCtxParams_getParameter(trace->params, ZSTD_c_nbWorkers, &workers); From 42243c3d465e5f8930a0938f5c5dbb260c3da800 Mon Sep 17 00:00:00 2001 From: Thirumalai Nagalingam Date: Wed, 20 Aug 2025 17:12:05 +0530 Subject: [PATCH 147/245] CI: Update build_package.bat for CMake builds --- lib/dll/example/build_package.bat | 33 ++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/dll/example/build_package.bat b/lib/dll/example/build_package.bat index 5a03bdf25..bd3103de5 100644 --- a/lib/dll/example/build_package.bat +++ b/lib/dll/example/build_package.bat @@ -1,10 +1,16 @@ @echo off setlocal -rem Create required directories. +rem Detect build type based on available files +set BUILD_TYPE=make +if exist "build\cmake\build\lib\Release\zstd_static.lib" set BUILD_TYPE=cmake + +echo Detected build type: %BUILD_TYPE% + +rem Create required directories mkdir bin\dll bin\static bin\example bin\include -rem Copy files using a subroutine. Exits immediately on failure. +rem Copy common files using a subroutine. Exits immediately on failure. call :copyFile "tests\fullbench.c" "bin\example\" call :copyFile "programs\datagen.c" "bin\example\" call :copyFile "programs\datagen.h" "bin\example\" @@ -14,16 +20,29 @@ call :copyFile "lib\common\mem.h" "bin\example\" call :copyFile "lib\common\zstd_internal.h" "bin\example\" call :copyFile "lib\common\error_private.h" "bin\example\" call :copyFile "lib\common\xxhash.h" "bin\example\" -call :copyFile "lib\libzstd.a" "bin\static\libzstd_static.lib" -call :copyFile "lib\dll\libzstd.*" "bin\dll\" call :copyFile "lib\dll\example\Makefile" "bin\example\" call :copyFile "lib\dll\example\fullbench-dll.*" "bin\example\" -call :copyFile "lib\dll\example\README.md" "bin\" call :copyFile "lib\zstd.h" "bin\include\" call :copyFile "lib\zstd_errors.h" "bin\include\" call :copyFile "lib\zdict.h" "bin\include\" -call :copyFile "programs\zstd.exe" "bin\zstd.exe" +rem Copy build-specific files +if "%BUILD_TYPE%"=="cmake" ( + echo Copying CMake build artifacts... + call :copyFile "build\cmake\build\lib\Release\zstd_static.lib" "bin\static\libzstd_static.lib" + call :copyFile "build\cmake\build\lib\Release\zstd.dll" "bin\dll\libzstd.dll" + call :copyFile "build\cmake\build\lib\Release\zstd.lib" "bin\dll\zstd.lib" + call :copyFile "build\cmake\build\programs\Release\zstd.exe" "bin\zstd.exe" + call :copyFile "lib\dll\example\README.md" "bin\README.md" +) else ( + echo Copying Make build artifacts... + call :copyFile "lib\libzstd.a" "bin\static\libzstd_static.lib" + call :copyFile "lib\dll\libzstd.*" "bin\dll\" + call :copyFile "programs\zstd.exe" "bin\zstd.exe" + call :copyFile "lib\dll\example\README.md" "bin\" +) + +echo Build package created successfully for %BUILD_TYPE% build! endlocal exit /b 0 @@ -33,4 +52,4 @@ if errorlevel 1 ( echo Failed to copy "%~1" exit 1 ) -exit /b +exit /b \ No newline at end of file From 002c227596c3f14ffc4e10d0851e021c6bef2324 Mon Sep 17 00:00:00 2001 From: Thirumalai Nagalingam Date: Wed, 20 Aug 2025 17:12:21 +0530 Subject: [PATCH 148/245] CI: Add CI setup for packaging Win-ARM64 artifacts --- .github/workflows/windows-artifacts.yml | 138 +++++++++++++++--------- 1 file changed, 88 insertions(+), 50 deletions(-) diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 2a599d447..d097acf96 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -13,69 +13,107 @@ jobs: windows-artifacts: permissions: contents: write # to fetch code and upload artifacts - # see https://ariya.io/2020/07/on-github-actions-with-msys2 - runs-on: windows-latest - # see https://github.com/msys2/setup-msys2 + # For msys2, see https://ariya.io/2020/07/on-github-actions-with-msys2 + runs-on: ${{ matrix.shell == 'cmake' && 'windows-11-arm' || 'windows-latest' }} strategy: + # For msys2, see https://github.com/msys2/setup-msys2 matrix: include: - - { msystem: mingw64, env: x86_64, ziparch: win64 } - - { msystem: mingw32, env: i686, ziparch: win32 } + - { msystem: mingw64, env: x86_64, ziparch: win64, shell: msys2 } + - { msystem: mingw32, env: i686, ziparch: win32, shell: msys2 } + - { msystem: null, env: arm64, ziparch: win-arm64, shell: cmake } + defaults: run: - shell: msys2 {0} + shell: ${{ matrix.shell == 'cmake' && 'pwsh' || 'msys2 {0}' }} + steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - - uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # tag=v2.28.0 - with: - msystem: ${{ matrix.msystem }} - install: make p7zip git mingw-w64-${{matrix.env}}-gcc - update: true + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - - name: display versions - run: | - make -v - cc -v + # MSYS2 setup + - uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # tag=v2.28.0 + if: matrix.shell == 'msys2' + with: + msystem: ${{ matrix.msystem }} + install: make p7zip git mingw-w64-${{matrix.env}}-gcc + update: true - - name: Building zlib to static link - run: | - git clone --depth 1 --branch v1.3.1 https://github.com/madler/zlib - make -C zlib -f win32/Makefile.gcc libz.a + - name: display versions (MSYS2) + if: matrix.shell == 'msys2' + run: | + make -v + cc -v - - name: Building lz4 to static link - run: | - git clone --depth 1 --branch v1.10.0 https://github.com/lz4/lz4 - # ensure both libraries use the same version of libxxhash - cp lib/common/xxhash.* lz4/lib - CPPFLAGS=-DXXH_NAMESPACE=LZ4_ make -C lz4/lib liblz4.a V=1 + - name: display versions (CMake) + if: matrix.shell == 'cmake' + run: | + cmake --version - - name: Building zstd programs - run: | - CPPFLAGS="-I../zlib -I../lz4/lib" LDFLAGS=-static make -j allzstd V=1 HAVE_ZLIB=1 HAVE_LZ4=1 HAVE_LZMA=0 LDLIBS="../zlib/libz.a ../lz4/lib/liblz4.a" + # Build dependencies (MSYS2 only) + - name: Building zlib to static link + if: matrix.shell == 'msys2' + run: | + git clone --depth 1 --branch v1.3.1 https://github.com/madler/zlib + make -C zlib -f win32/Makefile.gcc libz.a - - name: Create artifacts - run: | - ./lib/dll/example/build_package.bat || exit 1 - mv bin/ zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ + - name: Building lz4 to static link + if: matrix.shell == 'msys2' + run: | + git clone --depth 1 --branch v1.10.0 https://github.com/lz4/lz4 + # ensure both libraries use the same version of libxxhash + cp lib/common/xxhash.* lz4/lib + CPPFLAGS=-DXXH_NAMESPACE=LZ4_ make -C lz4/lib liblz4.a V=1 - - name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip for manual inspection - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1 - with: - compression-level: 9 # maximum compression - if-no-files-found: error # defaults to `warn` - path: ${{ github.workspace }}/zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ - name: zstd-${{ github.ref_name }}-${{matrix.ziparch}} + # Build zstd + - name: Building zstd programs + if: matrix.shell == 'msys2' + run: | + CPPFLAGS="-I../zlib -I../lz4/lib" LDFLAGS=-static make -j allzstd V=1 HAVE_ZLIB=1 HAVE_LZ4=1 HAVE_LZMA=0 LDLIBS="../zlib/libz.a ../lz4/lib/liblz4.a" - - name: Package artifact for upload - run: | - 7z a -tzip -mx9 "$(cygpath -u '${{ github.workspace }}/zstd-${{ github.ref_name }}-${{ matrix.ziparch }}.zip')" "$(cygpath -u '${{ github.workspace }}/zstd-${{ github.ref_name }}-${{ matrix.ziparch }}')" + - name: Build zstd (CMake ARM64) + if: matrix.shell == 'cmake' + run: | + cd build\cmake + mkdir build + cd build + cmake.exe -G "Visual Studio 17 2022" -A ARM64 -DCMAKE_BUILD_TYPE=Release -DZSTD_BUILD_PROGRAMS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=ON .. + cmake.exe --build . --config Release --parallel - - name: Upload release asset - if: github.event_name == 'release' - shell: pwsh - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh release upload "${{ github.ref_name }}" "$env:GITHUB_WORKSPACE/zstd-${{ github.ref_name }}-${{ matrix.ziparch }}.zip" --clobber + - name: Create artifacts (MSYS2) + if: matrix.shell == 'msys2' + run: | + ./lib/dll/example/build_package.bat || exit 1 + mv bin/ zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ + - name: Create artifacts (CMake) + if: matrix.shell == 'cmake' + run: | + .\lib\dll\example\build_package.bat + if ($LASTEXITCODE -ne 0) { exit 1 } + mv bin/ zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ + - name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip for manual inspection + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1 + with: + compression-level: 9 # maximum compression + if-no-files-found: error # defaults to `warn` + path: ${{ github.workspace }}/zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ + name: zstd-${{ github.ref_name }}-${{matrix.ziparch}} + + - name: Package artifact for upload (MSYS2) + if: matrix.shell == 'msys2' + run: | + 7z a -tzip -mx9 "$(cygpath -u '${{ github.workspace }}/zstd-${{ github.ref_name }}-${{ matrix.ziparch }}.zip')" "$(cygpath -u '${{ github.workspace }}/zstd-${{ github.ref_name }}-${{ matrix.ziparch }}')" + + - name: Package artifact for upload (CMake) + if: matrix.shell == 'cmake' + run: | + Compress-Archive -Path "zstd-${{ github.ref_name }}-${{ matrix.ziparch }}" -DestinationPath "zstd-${{ github.ref_name }}-${{ matrix.ziparch }}.zip" -CompressionLevel Optimal + + - name: Upload release asset + if: github.event_name == 'release' + shell: pwsh + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload "${{ github.ref_name }}" "$env:GITHUB_WORKSPACE/zstd-${{ github.ref_name }}-${{ matrix.ziparch }}.zip" --clobber \ No newline at end of file From 076283fa8870224876df0b5098a241f57c507453 Mon Sep 17 00:00:00 2001 From: Thirumalai Nagalingam Date: Wed, 20 Aug 2025 17:19:48 +0530 Subject: [PATCH 149/245] CI: Enable MSVC ARM64 job using Github WOA runner - Reintroduce the MSVC ARM64 build configuration with "Visual Studio 17 2022" - Update runner to `windows-11-arm` (GitHub-hosted Windows on ARM) --- .github/workflows/cmake-tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index 0ce2a7d8f..f1ed1f850 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -96,10 +96,10 @@ jobs: runner: "windows-2022" # Intentionally omit ZSTD_BUILD_TESTS to reproduce the CXX language configuration bug cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON" - # - generator: "Visual Studio 17 2022" - # flags: "-A ARM64" - # name: "MSVC ARM64" - # runner: "windows-2022-arm64" # Disabled due to very long queue times + - generator: "Visual Studio 17 2022" + flags: "-A ARM64" + name: "MSVC ARM64" + runner: "windows-11-arm" # githuh runner for WOA instance - generator: "MinGW Makefiles" flags: "" name: "MinGW" From 2849f3a5d1497a0b84d613f03949315a5b430153 Mon Sep 17 00:00:00 2001 From: Arpad Panyik Date: Thu, 17 Jul 2025 07:46:01 +0000 Subject: [PATCH 150/245] AArch64: Add SVE2 path for convertSequences_noRepcodes Add an 8-way vector length agnostic (VLA) SVE2 code path for convertSequences_noRepcodes. It works with any SVE vector length. Relative performance to GCC-13 using: `./fullbench -b18 -l5 enwik5` Neon SVE2 Neoverse-V2 before after uplift GCC-13: 100.000% 103.209% 1.032x GCC-14: 100.309% 134.872% 1.344x GCC-15: 100.355% 134.827% 1.343x Clang-18: 123.614% 128.565% 1.040x Clang-19: 123.587% 132.984% 1.076x Clang-20: 123.629% 133.023% 1.075x Neon SVE2 Cortex-A720 before after uplift GCC-13: 100.000% 116.032% 1.160x GCC-14: 99.700% 116.648% 1.169x GCC-15: 100.354% 117.047% 1.166x Clang-18: 100.447% 116.762% 1.162x Clang-19: 100.454% 116.627% 1.160x Clang-20: 100.452% 116.649% 1.161x --- lib/compress/zstd_compress.c | 149 +++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 008eaba35..71884278d 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -7383,6 +7383,155 @@ size_t convertSequences_noRepcodes(SeqDef* dstSeqs, const ZSTD_Sequence* inSeqs, * but since this implementation is targeting modern systems (>= Sapphire Rapid), * it's not useful to develop and maintain code for older pre-AVX2 platforms */ +#elif defined(ZSTD_ARCH_ARM_SVE2) + +/* + * Checks if any active element in a signed 8-bit integer vector is greater + * than zero. + * + * @param g Governing predicate selecting active lanes. + * @param a Input vector of signed 8-bit integers. + * + * @return True if any active element in `a` is > 0, false otherwise. + */ +FORCE_INLINE_TEMPLATE int cmpgtz_any_s8(svbool_t g, svint8_t a) +{ + svbool_t ptest = svcmpgt_n_s8(g, a, 0); + return svptest_any(ptest, ptest); +} + +size_t convertSequences_noRepcodes( + SeqDef* dstSeqs, + const ZSTD_Sequence* inSeqs, + size_t nbSequences) +{ + /* Process the input with `8 * VL / element` lanes. */ + const size_t lanes = 8 * svcntb() / sizeof(ZSTD_Sequence); + size_t longLen = 0; + size_t n = 0; + + /* SVE permutation depends on the specific definition of target structures. */ + ZSTD_STATIC_ASSERT(sizeof(ZSTD_Sequence) == 16); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, offset) == 0); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, litLength) == 4); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_Sequence, matchLength) == 8); + ZSTD_STATIC_ASSERT(sizeof(SeqDef) == 8); + ZSTD_STATIC_ASSERT(offsetof(SeqDef, offBase) == 0); + ZSTD_STATIC_ASSERT(offsetof(SeqDef, litLength) == 4); + ZSTD_STATIC_ASSERT(offsetof(SeqDef, mlBase) == 6); + + if (nbSequences >= lanes) { + const svbool_t ptrue = svptrue_b8(); + /* 16-bit of {ZSTD_REP_NUM, 0, -MINMATCH, 0} extended to 32-bit lanes. */ + const svuint32_t vaddition = svreinterpret_u32( + svunpklo_s32(svreinterpret_s16(svdup_n_u64(ZSTD_REP_NUM | (((U64)(U16)-MINMATCH) << 32))))); + /* For permutation of 16-bit units: 0, 1, 2, 4, 8, 9, 10, 12, ... */ + const svuint16_t vmask = svreinterpret_u16( + svindex_u64(0x0004000200010000, 0x0008000800080008)); + /* Upper bytes of `litLength` and `matchLength` will be packed into the + * middle of overflow check vector. */ + const svbool_t pmid = svcmpne_n_u8( + ptrue, svreinterpret_u8(svdup_n_u64(0x0000FFFFFFFF0000)), 0); + + do { + /* Load `lanes` number of `ZSTD_Sequence` into 8 vectors. */ + const svuint32_t vin0 = svld1_vnum_u32(ptrue, &inSeqs[n].offset, 0); + const svuint32_t vin1 = svld1_vnum_u32(ptrue, &inSeqs[n].offset, 1); + const svuint32_t vin2 = svld1_vnum_u32(ptrue, &inSeqs[n].offset, 2); + const svuint32_t vin3 = svld1_vnum_u32(ptrue, &inSeqs[n].offset, 3); + const svuint32_t vin4 = svld1_vnum_u32(ptrue, &inSeqs[n].offset, 4); + const svuint32_t vin5 = svld1_vnum_u32(ptrue, &inSeqs[n].offset, 5); + const svuint32_t vin6 = svld1_vnum_u32(ptrue, &inSeqs[n].offset, 6); + const svuint32_t vin7 = svld1_vnum_u32(ptrue, &inSeqs[n].offset, 7); + + /* Add {ZSTD_REP_NUM, 0, -MINMATCH, 0} to each structures. */ + const svuint16x2_t vadd01 = svcreate2_u16( + svreinterpret_u16(svadd_u32_x(ptrue, vin0, vaddition)), + svreinterpret_u16(svadd_u32_x(ptrue, vin1, vaddition))); + const svuint16x2_t vadd23 = svcreate2_u16( + svreinterpret_u16(svadd_u32_x(ptrue, vin2, vaddition)), + svreinterpret_u16(svadd_u32_x(ptrue, vin3, vaddition))); + const svuint16x2_t vadd45 = svcreate2_u16( + svreinterpret_u16(svadd_u32_x(ptrue, vin4, vaddition)), + svreinterpret_u16(svadd_u32_x(ptrue, vin5, vaddition))); + const svuint16x2_t vadd67 = svcreate2_u16( + svreinterpret_u16(svadd_u32_x(ptrue, vin6, vaddition)), + svreinterpret_u16(svadd_u32_x(ptrue, vin7, vaddition))); + + /* Shuffle and pack bytes so each vector contains SeqDef structures. */ + const svuint16_t vout01 = svtbl2_u16(vadd01, vmask); + const svuint16_t vout23 = svtbl2_u16(vadd23, vmask); + const svuint16_t vout45 = svtbl2_u16(vadd45, vmask); + const svuint16_t vout67 = svtbl2_u16(vadd67, vmask); + + /* Pack the upper 16-bits of 32-bit lanes for overflow check. */ + const svuint16_t voverflow01 = svuzp2_u16(svget2_u16(vadd01, 0), + svget2_u16(vadd01, 1)); + const svuint16_t voverflow23 = svuzp2_u16(svget2_u16(vadd23, 0), + svget2_u16(vadd23, 1)); + const svuint16_t voverflow45 = svuzp2_u16(svget2_u16(vadd45, 0), + svget2_u16(vadd45, 1)); + const svuint16_t voverflow67 = svuzp2_u16(svget2_u16(vadd67, 0), + svget2_u16(vadd67, 1)); + + /* We don't need the whole 16 bits of the overflow part. Only 1 bit + * is needed, so we pack tightly and merge multiple vectors to be + * able to use a single comparison to handle the overflow case. + * However, we also need to handle the possible negative values of + * matchLength parts, so we use signed comparison later. */ + const svint8_t voverflow = + svmax_s8_x(pmid, + svtrn1_s8(svreinterpret_s8(voverflow01), + svreinterpret_s8(voverflow23)), + svtrn1_s8(svreinterpret_s8(voverflow45), + svreinterpret_s8(voverflow67))); + + /* Store `lanes` number of `SeqDef` structures from 4 vectors. */ + svst1_vnum_u32(ptrue, &dstSeqs[n].offBase, 0, svreinterpret_u32(vout01)); + svst1_vnum_u32(ptrue, &dstSeqs[n].offBase, 1, svreinterpret_u32(vout23)); + svst1_vnum_u32(ptrue, &dstSeqs[n].offBase, 2, svreinterpret_u32(vout45)); + svst1_vnum_u32(ptrue, &dstSeqs[n].offBase, 3, svreinterpret_u32(vout67)); + + /* Check if any enabled lanes of the overflow vector is larger than + * zero, only one such may happen. */ + if (UNLIKELY(cmpgtz_any_s8(pmid, voverflow))) { + /* Scalar search for long match is needed because we merged + * multiple overflow bytes with `max`. */ + size_t i; + for (i = n; i < n + lanes; i++) { + if (inSeqs[i].matchLength > 65535 + MINMATCH) { + assert(longLen == 0); + longLen = i + 1; + } + if (inSeqs[i].litLength > 65535) { + assert(longLen == 0); + longLen = i + nbSequences + 1; + } + } + } + + n += lanes; + } while(n <= nbSequences - lanes); + } + + /* Handle remaining elements. */ + for (; n < nbSequences; n++) { + dstSeqs[n].offBase = OFFSET_TO_OFFBASE(inSeqs[n].offset); + dstSeqs[n].litLength = (U16)inSeqs[n].litLength; + dstSeqs[n].mlBase = (U16)(inSeqs[n].matchLength - MINMATCH); + /* Check for long length > 65535. */ + if (UNLIKELY(inSeqs[n].matchLength > 65535 + MINMATCH)) { + assert(longLen == 0); + longLen = n + 1; + } + if (UNLIKELY(inSeqs[n].litLength > 65535)) { + assert(longLen == 0); + longLen = n + nbSequences + 1; + } + } + return longLen; +} + #elif defined(ZSTD_ARCH_ARM_NEON) && (defined(__aarch64__) || defined(_M_ARM64)) size_t convertSequences_noRepcodes( From 0ee187c540653da0ca39aebc9e934fbef702b82b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 09:00:57 +0000 Subject: [PATCH 151/245] Bump actions/setup-java from 4.7.1 to 5.0.0 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4.7.1 to 5.0.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/c5195efecf7bdfc987ee8bae7a71cb8b11521c00...dded0888837ed1f317902acf8a20df0ad188d165) --- updated-dependencies: - dependency-name: actions/setup-java dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/android-ndk-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index 330d58ffe..99183049c 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - name: Set up JDK 17 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: java-version: '17' distribution: 'temurin' From ba59aeb67408c5ca6979e6d971915c86cfbcee90 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Thu, 28 Aug 2025 18:50:34 -0500 Subject: [PATCH 152/245] meson: Call meson.override_dependency() if Meson is new enough This tells Meson that we intend libzstd_dep to be used by a parent project if the parent looks for a dependency named "libzstd". Without this, the mapping from "libzstd" to our variable libzstd_dep must be encoded in the Meson wrap file or in the parent's meson.build. --- build/meson/lib/meson.build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/meson/lib/meson.build b/build/meson/lib/meson.build index d086fc2d7..81fc313f9 100644 --- a/build/meson/lib/meson.build +++ b/build/meson/lib/meson.build @@ -127,6 +127,10 @@ libzstd = library('zstd', libzstd_dep = declare_dependency(link_with: libzstd, include_directories: join_paths(zstd_rootdir,'lib')) # Do not expose private headers +if meson.version().version_compare('>=0.54.0') + meson.override_dependency('libzstd', libzstd_dep) +endif + # we link to both: # - the shared library (for public symbols) # - the static library (for private symbols) From 64c4288e9272c7b65f381d456e70eec35fc3cfd3 Mon Sep 17 00:00:00 2001 From: Jamie Lokier Date: Tue, 2 Sep 2025 16:44:09 +0100 Subject: [PATCH 153/245] Update manual about the default value of `-T#`/`--threads=#` The section about `ZSTD_NBTHREADS` already explains the default number of threads, since it changed from 1 (commit 17beeb5). But the option description for `-T#`/`--threads=#` incorrectly said the default was still 1. I noticed this when I found compression slower with `-T1` than without it. --- programs/zstd.1 | 2 +- programs/zstd.1.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/zstd.1 b/programs/zstd.1 index 5503a5b86..e49a182d5 100644 --- a/programs/zstd.1 +++ b/programs/zstd.1 @@ -108,7 +108,7 @@ Display information related to a zstd compressed file, such as size, ratio, and \fB\-\-fast[=#]\fR: switch to ultra\-fast compression levels\. If \fB=#\fR is not present, it defaults to \fB1\fR\. The higher the value, the faster the compression speed, at the cost of some compression ratio\. This setting overwrites compression level if one was set previously\. Similarly, if a compression level is set after \fB\-\-fast\fR, it overrides it\. . .IP "\(bu" 4 -\fB\-T#\fR, \fB\-\-threads=#\fR: Compress using \fB#\fR working threads (default: 1)\. If \fB#\fR is 0, attempt to detect and use the number of physical CPU cores\. In all cases, the nb of threads is capped to \fBZSTDMT_NBWORKERS_MAX\fR, which is either 64 in 32\-bit mode, or 256 for 64\-bit environments\. This modifier does nothing if \fBzstd\fR is compiled without multithread support\. +\fB\-T#\fR, \fB\-\-threads=#\fR: Compress using \fB#\fR working threads (default: between 1 and 4 depending on physical CPU cores; see \fBZSTD_NBTHREADS\fR below)\. If \fB#\fR is 0, attempt to detect and use the number of physical CPU cores\. In all cases, the nb of threads is capped to \fBZSTDMT_NBWORKERS_MAX\fR, which is either 64 in 32\-bit mode, or 256 for 64\-bit environments\. This modifier does nothing if \fBzstd\fR is compiled without multithread support\. . .IP "\(bu" 4 \fB\-\-single\-thread\fR: Use a single thread for both I/O and compression\. As compression is serialized with I/O, this can be slightly slower\. Single\-thread mode features significantly lower memory usage, which can be useful for systems with limited amount of memory, such as 32\-bit systems\. diff --git a/programs/zstd.1.md b/programs/zstd.1.md index cf1810d59..bb9258d57 100644 --- a/programs/zstd.1.md +++ b/programs/zstd.1.md @@ -126,7 +126,7 @@ the last one takes effect. This setting overwrites compression level if one was set previously. Similarly, if a compression level is set after `--fast`, it overrides it. * `-T#`, `--threads=#`: - Compress using `#` working threads (default: 1). + Compress using `#` working threads (default: between 1 and 4 depending on physical CPU cores; see `ZSTD_NBTHREADS` below). If `#` is 0, attempt to detect and use the number of physical CPU cores. In all cases, the nb of threads is capped to `ZSTDMT_NBWORKERS_MAX`, which is either 64 in 32-bit mode, or 256 for 64-bit environments. From 1c5d45fc11529e72c78a8108bddeb794cca905b7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 2 Sep 2025 15:46:51 -0700 Subject: [PATCH 154/245] fixed -T# documentation in zstd -H provide the local value for default nbThreads which is dynamic and depends on local nb of cores. --- programs/zstdcli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 124ea47aa..142fc4c53 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -233,7 +233,7 @@ static void usageAdvanced(const char* programName) DISPLAYOUT(" --patch-from=REF Use REF as the reference point for Zstandard's diff engine. \n"); DISPLAYOUT(" --patch-apply Equivalent for `-d --patch-from` \n\n"); # ifdef ZSTD_MULTITHREAD - DISPLAYOUT(" -T# Spawn # compression threads. [Default: 1; pass 0 for core count.]\n"); + DISPLAYOUT(" -T# Spawn # compression threads. [Default: %i; pass 0 for core count.]\n", ZSTDCLI_NBTHREADS_DEFAULT); DISPLAYOUT(" --single-thread Share a single thread for I/O and compression (slightly different than `-T1`).\n"); DISPLAYOUT(" --auto-threads={physical|logical}\n"); DISPLAYOUT(" Use physical/logical cores when using `-T0`. [Default: Physical]\n\n"); From 6551db345922c9b40aa48a8a57c9bfb48fd1855b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 2 Sep 2025 15:53:45 -0700 Subject: [PATCH 155/245] specify nb of threads used during benchmarking used to require `-v` (verbose) modifier --- programs/zstdcli.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 142fc4c53..e44384ea1 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1435,7 +1435,7 @@ int main(int argCount, const char* argv[]) if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel(); if (cLevelLast > ZSTD_maxCLevel()) cLevelLast = ZSTD_maxCLevel(); if (cLevelLast < cLevel) cLevelLast = cLevel; - DISPLAYLEVEL(3, "Benchmarking "); + DISPLAYLEVEL(2, "Benchmarking "); if (filenames->tableSize > 1) DISPLAYLEVEL(3, "%u files ", (unsigned)filenames->tableSize); if (cLevelLast > cLevel) { @@ -1443,7 +1443,7 @@ int main(int argCount, const char* argv[]) } else { DISPLAYLEVEL(3, "at level %d ", cLevel); } - DISPLAYLEVEL(3, "using %i threads \n", nbWorkers); + DISPLAYLEVEL(2, "using %i threads \n", nbWorkers); if (filenames->tableSize > 0) { if(separateFiles) { unsigned i; From c41fc1aa01a4bbc4ccd6877f4d198e0c76eb122d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 2 Sep 2025 16:05:35 -0700 Subject: [PATCH 156/245] only display nbThread Msg in nbThreads > 1 --- programs/zstdcli.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index e44384ea1..cb87604b1 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1410,6 +1410,7 @@ int main(int argCount, const char* argv[]) /* Check if benchmark is selected */ if (operation==zom_bench) { #ifndef ZSTD_NOBENCH + int const benchThreadsMsgLevel = 2 + (nbWorkers <= 1); if (cType != FIO_zstdCompression) { DISPLAYLEVEL(1, "benchmark mode is only compatible with zstd format \n"); CLEAN_RETURN(1); @@ -1435,7 +1436,7 @@ int main(int argCount, const char* argv[]) if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel(); if (cLevelLast > ZSTD_maxCLevel()) cLevelLast = ZSTD_maxCLevel(); if (cLevelLast < cLevel) cLevelLast = cLevel; - DISPLAYLEVEL(2, "Benchmarking "); + DISPLAYLEVEL(benchThreadsMsgLevel, "Benchmarking "); if (filenames->tableSize > 1) DISPLAYLEVEL(3, "%u files ", (unsigned)filenames->tableSize); if (cLevelLast > cLevel) { @@ -1443,7 +1444,7 @@ int main(int argCount, const char* argv[]) } else { DISPLAYLEVEL(3, "at level %d ", cLevel); } - DISPLAYLEVEL(2, "using %i threads \n", nbWorkers); + DISPLAYLEVEL(benchThreadsMsgLevel, "using %i threads \n", nbWorkers); if (filenames->tableSize > 0) { if(separateFiles) { unsigned i; From 725a152c7bf91244b0e16eabc312762a39dad583 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 2 Sep 2025 16:21:48 -0700 Subject: [PATCH 157/245] benchmark uses 1 thread by default --- programs/zstdcli.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index cb87604b1..696e4a1ba 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -47,7 +47,7 @@ #define ZSTDCLI_NBTHREADS_DEFAULT (unsigned)(MAX(1, MIN(4, UTIL_countLogicalCores() / 4))) #endif - +static unsigned init_nbWorkers(unsigned defaultNbWorkers); /*-************************************ * Constants @@ -95,6 +95,7 @@ static U32 g_ldmBucketSizeLog = LDM_PARAM_DEFAULT; #define DEFAULT_ACCEL 1 #define NBWORKERS_AUTOCPU 0 +#define NBWORKERS_UNSET UINT_MAX typedef enum { cover, fastCover, legacy } dictType; @@ -233,7 +234,7 @@ static void usageAdvanced(const char* programName) DISPLAYOUT(" --patch-from=REF Use REF as the reference point for Zstandard's diff engine. \n"); DISPLAYOUT(" --patch-apply Equivalent for `-d --patch-from` \n\n"); # ifdef ZSTD_MULTITHREAD - DISPLAYOUT(" -T# Spawn # compression threads. [Default: %i; pass 0 for core count.]\n", ZSTDCLI_NBTHREADS_DEFAULT); + DISPLAYOUT(" -T# Spawn # compression threads. [Default: %u; pass 0 for core count.]\n", init_nbWorkers(ZSTDCLI_NBTHREADS_DEFAULT)); DISPLAYOUT(" --single-thread Share a single thread for I/O and compression (slightly different than `-T1`).\n"); DISPLAYOUT(" --auto-threads={physical|logical}\n"); DISPLAYOUT(" Use physical/logical cores when using `-T0`. [Default: Physical]\n\n"); @@ -783,7 +784,7 @@ static int init_cLevel(void) { return ZSTDCLI_CLEVEL_DEFAULT; } -static unsigned init_nbWorkers(void) { +static unsigned init_nbWorkers(unsigned defaultNbWorkers) { #ifdef ZSTD_MULTITHREAD const char* const env = getenv(ENV_NBWORKERS); if (env != NULL) { @@ -792,7 +793,7 @@ static unsigned init_nbWorkers(void) { unsigned nbThreads; if (readU32FromCharChecked(&ptr, &nbThreads)) { DISPLAYLEVEL(2, "Ignore environment variable setting %s=%s: numeric value too large \n", ENV_NBWORKERS, env); - return ZSTDCLI_NBTHREADS_DEFAULT; + return defaultNbWorkers; } else if (*ptr == 0) { return nbThreads; } @@ -800,7 +801,7 @@ static unsigned init_nbWorkers(void) { DISPLAYLEVEL(2, "Ignore environment variable setting %s=%s: not a valid unsigned value \n", ENV_NBWORKERS, env); } - return ZSTDCLI_NBTHREADS_DEFAULT; + return defaultNbWorkers; #else return 1; #endif @@ -881,7 +882,7 @@ int main(int argCount, const char* argv[]) ultra = 0, cLevelLast = MINCLEVEL - 1, /* for benchmark range */ setThreads_non1 = 0; - unsigned nbWorkers = init_nbWorkers(); + unsigned nbWorkers = init_nbWorkers(NBWORKERS_UNSET); ZSTD_ParamSwitch_e mmapDict = ZSTD_ps_auto; ZSTD_ParamSwitch_e useRowMatchFinder = ZSTD_ps_auto; FIO_compressionType_t cType = FIO_zstdCompression; @@ -1410,7 +1411,9 @@ int main(int argCount, const char* argv[]) /* Check if benchmark is selected */ if (operation==zom_bench) { #ifndef ZSTD_NOBENCH - int const benchThreadsMsgLevel = 2 + (nbWorkers <= 1); + int benchThreadsMsgLevel = 2; + if (nbWorkers == NBWORKERS_UNSET) nbWorkers = 1; + if (nbWorkers <= 1) benchThreadsMsgLevel = 3; if (cType != FIO_zstdCompression) { DISPLAYLEVEL(1, "benchmark mode is only compatible with zstd format \n"); CLEAN_RETURN(1); @@ -1471,6 +1474,7 @@ int main(int argCount, const char* argv[]) zParams.compressionLevel = dictCLevel; zParams.notificationLevel = (unsigned)g_displayLevel; zParams.dictID = dictID; + if (nbWorkers == NBWORKERS_UNSET) nbWorkers = init_nbWorkers(ZSTDCLI_NBTHREADS_DEFAULT); if (dict == cover) { int const optimize = !coverParams.k || !coverParams.d; coverParams.nbThreads = (unsigned)nbWorkers; @@ -1593,6 +1597,7 @@ int main(int argCount, const char* argv[]) #ifndef ZSTD_NOCOMPRESS FIO_setCompressionType(prefs, cType); FIO_setContentSize(prefs, contentSize); + if (nbWorkers == NBWORKERS_UNSET) nbWorkers = init_nbWorkers(ZSTDCLI_NBTHREADS_DEFAULT); FIO_setNbWorkers(prefs, (int)nbWorkers); FIO_setJobSize(prefs, (int)chunkSize); if (g_overlapLog!=OVERLAP_LOG_DEFAULT) FIO_setOverlapLog(prefs, (int)g_overlapLog); From 249e4a07d53415a8161ce5ad65a725ffd99060ac Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 2 Sep 2025 16:36:44 -0700 Subject: [PATCH 158/245] fixed minor unused variable warning in certain compilation modes --- programs/zstdcli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 696e4a1ba..01760ff8c 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -803,6 +803,7 @@ static unsigned init_nbWorkers(unsigned defaultNbWorkers) { return defaultNbWorkers; #else + (void)defaultNbWorkers; return 1; #endif } From d3536643a91c6de403cf9913d85abc896e94cd11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 05:06:40 +0000 Subject: [PATCH 159/245] Bump msys2/setup-msys2 from 2.28.0 to 2.29.0 Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.28.0 to 2.29.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/40677d36a502eb2cf0fb808cc9dec31bf6152638...fb197b72ce45fb24f17bf3f807a388985654d1f2) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.29.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dev-long-tests.yml | 2 +- .github/workflows/dev-short-tests.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index caf86a11f..0450324ee 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -274,7 +274,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - - uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # tag=v2.28.0 + - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # tag=v2.29.0 with: msystem: MINGW64 install: make diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 4b06d5e3b..59f4c1b77 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -487,7 +487,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 - - uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # tag=v2.28.0 + - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # tag=v2.29.0 with: msystem: ${{ matrix.msystem }} install: make diffutils diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index d097acf96..fcc81c395 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 # MSYS2 setup - - uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # tag=v2.28.0 + - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # tag=v2.29.0 if: matrix.shell == 'msys2' with: msystem: ${{ matrix.msystem }} From ef4bab9079c2b1ac745d650efe546756faba27e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 05:06:48 +0000 Subject: [PATCH 160/245] Bump github/codeql-action from 3.29.4 to 3.30.1 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.4 to 3.30.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/4e828ff8d448a8a6e532957b1811f387a63867e8...f1f6e5f6af878fb37288ce1c627459e94dbf7d01) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.30.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index e34ebfa7b..be14cb5d5 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,6 +59,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@4e828ff8d448a8a6e532957b1811f387a63867e8 # tag=v3.29.4 + uses: github/codeql-action/upload-sarif@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # tag=v3.30.1 with: sarif_file: results.sarif From c9d2cbd5bacf493362aa9a81057938a11961369a Mon Sep 17 00:00:00 2001 From: w1m024 Date: Tue, 9 Sep 2025 06:20:55 +0000 Subject: [PATCH 161/245] add RVV optimization for ZSTD_row_getMatchMask Co-authored-by: gong-flying --- lib/compress/zstd_lazy.c | 42 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c index 272ebe0ec..ca8fb4194 100644 --- a/lib/compress/zstd_lazy.c +++ b/lib/compress/zstd_lazy.c @@ -1050,6 +1050,36 @@ ZSTD_row_getNEONMask(const U32 rowEntries, const BYTE* const src, const BYTE tag } } #endif +#if defined(ZSTD_ARCH_RISCV_RVV) && (__riscv_xlen == 64) +FORCE_INLINE_TEMPLATE ZSTD_VecMask +ZSTD_row_getRVVMask(int nbChunks, const BYTE* const src, const BYTE tag, const U32 head) +{ + U16 matches[4] = {0}; + int i; + assert(nbChunks == 1 || nbChunks == 2 || nbChunks == 4); + + size_t vl = __riscv_vsetvl_e8m1(16); + + for (i = 0; i < nbChunks; i++) { + vuint8m1_t chunk = __riscv_vle8_v_u8m1((const uint8_t*)(src + 16 * i), vl); + vbool8_t equalMask = __riscv_vmseq_vx_u8m1_b8(chunk, tag, vl); + + size_t vl_w = __riscv_vsetvl_e16m2(16); + vuint16m2_t one = __riscv_vmv_v_x_u16m2(1, vl_w); + vuint16m2_t indices = __riscv_vid_v_u16m2(vl_w); + vuint16m2_t powers_of_2 = __riscv_vsll_vv_u16m2(one, indices, vl_w); + vuint16m2_t zero = __riscv_vmv_v_x_u16m2(0, vl_w); + vuint16m2_t selected_bits = __riscv_vmerge_vvm_u16m2(zero, powers_of_2, equalMask, vl_w); + vuint16m1_t reduction = __riscv_vredor_vs_u16m2_u16m1(selected_bits, __riscv_vmv_s_x_u16m1(0, vl_w), vl_w); + matches[i] = __riscv_vmv_x_s_u16m1_u16(reduction); + } + + if (nbChunks == 1) return ZSTD_rotateRight_U16(matches[0], head); + if (nbChunks == 2) return ZSTD_rotateRight_U32((U32)matches[1] << 16 | (U32)matches[0], head); + assert(nbChunks == 4); + return ZSTD_rotateRight_U64((U64)matches[3] << 48 | (U64)matches[2] << 32 | (U64)matches[1] << 16 | (U64)matches[0], head); +} +#endif /* Returns a ZSTD_VecMask (U64) that has the nth group (determined by * ZSTD_row_matchMaskGroupWidth) of bits set to 1 if the newly-computed "tag" @@ -1069,14 +1099,20 @@ ZSTD_row_getMatchMask(const BYTE* const tagRow, const BYTE tag, const U32 headGr return ZSTD_row_getSSEMask(rowEntries / 16, src, tag, headGrouped); -#else /* SW or NEON-LE */ +#elif defined(ZSTD_ARCH_RISCV_RVV) && (__riscv_xlen == 64) -# if defined(ZSTD_ARCH_ARM_NEON) + return ZSTD_row_getRVVMask(rowEntries, src, tag, headGrouped); + +#else + +#if defined(ZSTD_ARCH_ARM_NEON) /* This NEON path only works for little endian - otherwise use SWAR below */ if (MEM_isLittleEndian()) { return ZSTD_row_getNEONMask(rowEntries, src, tag, headGrouped); } -# endif /* ZSTD_ARCH_ARM_NEON */ + + +#endif /* SWAR */ { const int chunkSize = sizeof(size_t); const size_t shiftAmount = ((chunkSize * 8) - chunkSize); From fb7a86f20f7b3825ccf2a77153d4fb104733b2f4 Mon Sep 17 00:00:00 2001 From: w1m024 Date: Thu, 11 Sep 2025 20:42:40 +0000 Subject: [PATCH 162/245] Refactor ZSTD_row_getMatchMask for RVV optimization Performance (vs. SWAR) - 16-byte data: 5.87x speedup - 32-byte data: 9.63x speedup - 64-byte data: 17.98x speedup Co-authored-by: gong-flying --- lib/compress/zstd_lazy.c | 44 +++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c index ca8fb4194..f5efa8d8a 100644 --- a/lib/compress/zstd_lazy.c +++ b/lib/compress/zstd_lazy.c @@ -1054,30 +1054,32 @@ ZSTD_row_getNEONMask(const U32 rowEntries, const BYTE* const src, const BYTE tag FORCE_INLINE_TEMPLATE ZSTD_VecMask ZSTD_row_getRVVMask(int nbChunks, const BYTE* const src, const BYTE tag, const U32 head) { - U16 matches[4] = {0}; - int i; - assert(nbChunks == 1 || nbChunks == 2 || nbChunks == 4); + ZSTD_VecMask matches; + size_t vl; - size_t vl = __riscv_vsetvl_e8m1(16); + if (rowEntries == 16) { + vl = __riscv_vsetvl_e8m1(16); + vuint8m1_t chunk = __riscv_vle8_v_u8m1(src, vl); + vbool8_t mask = __riscv_vmseq_vx_u8m1_b8(chunk, tag, vl); + vuint16m1_t mask_u16 = __riscv_vreinterpret_v_b8_u16m1(mask); + matches = __riscv_vmv_x_s_u16m1_u16(mask_u16); + return ZSTD_rotateRight_U16((U16)matches, head); - for (i = 0; i < nbChunks; i++) { - vuint8m1_t chunk = __riscv_vle8_v_u8m1((const uint8_t*)(src + 16 * i), vl); - vbool8_t equalMask = __riscv_vmseq_vx_u8m1_b8(chunk, tag, vl); - - size_t vl_w = __riscv_vsetvl_e16m2(16); - vuint16m2_t one = __riscv_vmv_v_x_u16m2(1, vl_w); - vuint16m2_t indices = __riscv_vid_v_u16m2(vl_w); - vuint16m2_t powers_of_2 = __riscv_vsll_vv_u16m2(one, indices, vl_w); - vuint16m2_t zero = __riscv_vmv_v_x_u16m2(0, vl_w); - vuint16m2_t selected_bits = __riscv_vmerge_vvm_u16m2(zero, powers_of_2, equalMask, vl_w); - vuint16m1_t reduction = __riscv_vredor_vs_u16m2_u16m1(selected_bits, __riscv_vmv_s_x_u16m1(0, vl_w), vl_w); - matches[i] = __riscv_vmv_x_s_u16m1_u16(reduction); + } else if (rowEntries == 32) { + vl = __riscv_vsetvl_e8m2(32); + vuint8m2_t chunk = __riscv_vle8_v_u8m2(src, vl); + vbool4_t mask = __riscv_vmseq_vx_u8m2_b4(chunk, tag, vl); + vuint32m1_t mask_u32 = __riscv_vreinterpret_v_b4_u32m1(mask); + matches = __riscv_vmv_x_s_u32m1_u32(mask_u32); + return ZSTD_rotateRight_U32((U32)matches, head); + } else { // rowEntries = 64 + vl = __riscv_vsetvl_e8m4(64); + vuint8m4_t chunk = __riscv_vle8_v_u8m4(src, vl); + vbool2_t mask = __riscv_vmseq_vx_u8m4_b2(chunk, tag, vl); + vuint64m1_t mask_u64 = __riscv_vreinterpret_v_b2_u64m1(mask); + matches = __riscv_vmv_x_s_u64m1_u64(mask_u64); + return ZSTD_rotateRight_U64(matches, head); } - - if (nbChunks == 1) return ZSTD_rotateRight_U16(matches[0], head); - if (nbChunks == 2) return ZSTD_rotateRight_U32((U32)matches[1] << 16 | (U32)matches[0], head); - assert(nbChunks == 4); - return ZSTD_rotateRight_U64((U64)matches[3] << 48 | (U64)matches[2] << 32 | (U64)matches[1] << 16 | (U64)matches[0], head); } #endif From c59812e558dd6ba24f592c77662204b721bb1dbb Mon Sep 17 00:00:00 2001 From: Ryan Lefkowitz Date: Mon, 15 Sep 2025 18:20:01 -0400 Subject: [PATCH 163/245] =?UTF-8?q?=F0=9F=94=A7=20Fix=20memory=20leak=20in?= =?UTF-8?q?=20pthread=20init=20functions=20on=20failure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When pthread_mutex_init() or pthread_cond_init() fails in the debug implementation (DEBUGLEVEL >= 1), the previously allocated memory was not freed, causing a memory leak. This fix ensures that allocated memory is properly freed when pthread initialization functions fail, preventing resource leaks in error conditions. The issue affects: - ZSTD_pthread_mutex_init() at lib/common/threading.c:146 - ZSTD_pthread_cond_init() at lib/common/threading.c:167 This is particularly important for long-running applications or scenarios with resource constraints where pthread initialization might fail due to system limits. --- lib/common/threading.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/common/threading.c b/lib/common/threading.c index 25bb8b981..1d5c97d3c 100644 --- a/lib/common/threading.c +++ b/lib/common/threading.c @@ -143,7 +143,14 @@ int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t con *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t)); if (!*mutex) return 1; - return pthread_mutex_init(*mutex, attr); + { + int const ret = pthread_mutex_init(*mutex, attr); + if (ret != 0) { + ZSTD_free(*mutex); + *mutex = NULL; + } + return ret; + } } int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex) @@ -164,7 +171,14 @@ int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t)); if (!*cond) return 1; - return pthread_cond_init(*cond, attr); + { + int const ret = pthread_cond_init(*cond, attr); + if (ret != 0) { + ZSTD_free(*cond); + *cond = NULL; + } + return ret; + } } int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond) From 96fdb9bd1607d034d5ec5c824ad9e6a58a53efd9 Mon Sep 17 00:00:00 2001 From: Neil Johari Date: Mon, 15 Sep 2025 23:58:45 -0700 Subject: [PATCH 164/245] Add debug logging and simple repro --- programs/dibio.c | 20 +++++++++++++++++++ test_allocation_bug.sh | 44 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100755 test_allocation_bug.sh diff --git a/programs/dibio.c b/programs/dibio.c index 63c455a22..f5f33f1bd 100644 --- a/programs/dibio.c +++ b/programs/dibio.c @@ -279,10 +279,16 @@ static fileStats DiB_fileStats(const char** fileNamesTable, int nbFiles, size_t for (n=0; n alloc_test/good_$i.txt +done + +echo "Valid files created (about 6 bytes each = 30 bytes total)" +echo "" + +# We need enough bad files to make totalSizeToLoad negative +# 30 bytes positive, so we need at least 31 bad files +echo "Adding 1000 non-existent files to make totalSizeToLoad very negative..." +echo "Expected: totalSizeToLoad = 30 + (1000 * -1) = -970 bytes" +echo "" + +# Build command +CMD="./zstd --train alloc_test/good_*.txt" +for i in {1..1000}; do + CMD="$CMD alloc_test/BAD_$i" +done +CMD="$CMD -o alloc_test/dict.zst --maxdict=65536 2>&1" + +echo "Running command..." +echo "=================" + +# Run and capture ALL debug output related to our issue +eval $CMD | grep -E "\[DEBUG FINAL\]|\[DEBUG\] Memory calc|\[BUG\]|About to malloc|Error|not enough memory" + +echo "" +echo "Output should show something like the following:" +echo "1. [DEBUG FINAL] fileStats: totalSizeToLoad=-970 (NEGATIVE!)" +echo "2. [BUG] totalSizeToLoad is NEGATIVE!" +echo "3. [DEBUG] Memory calc: showing huge loadedSize value" +echo "4. Error about memory allocation" From 85f4a7e84e266d9545a309ff3f25e71345d8be62 Mon Sep 17 00:00:00 2001 From: Neil Johari Date: Tue, 16 Sep 2025 00:02:04 -0700 Subject: [PATCH 165/245] Fix bug --- programs/dibio.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/programs/dibio.c b/programs/dibio.c index f5f33f1bd..29a27d9db 100644 --- a/programs/dibio.c +++ b/programs/dibio.c @@ -282,13 +282,16 @@ static fileStats DiB_fileStats(const char** fileNamesTable, int nbFiles, size_t DISPLAYLEVEL(1, "[DEBUG] File '%s': size=%lld\n", fileNamesTable[n], (long long)fileSize); /* TODO: is there a minimum sample size? What if the file is 1-byte? */ - if (fileSize == 0) { - DISPLAYLEVEL(3, "Sample file '%s' has zero size, skipping...\n", fileNamesTable[n]); + /* Skip empty or invalid files */ + if (fileSize <= 0) { + if (fileSize < 0) { + DISPLAYLEVEL(3, "Sample file '%s' is unreadable or stat failed, skipping...\n", + fileNamesTable[n]); + } else { + DISPLAYLEVEL(3, "Sample file '%s' has zero size, skipping...\n", + fileNamesTable[n]); + } continue; - } else if (fileSize < 0) { - /* BUG: This path is NOT skipped but should be! */ - DISPLAYLEVEL(1, "[BUG] File '%s' has NEGATIVE size %lld but is NOT skipped!\n", - fileNamesTable[n], (long long)fileSize); } /* the case where we are breaking up files in sample chunks */ From 236e44f00fed5cbcd02b4936b765f3bb97ad0e98 Mon Sep 17 00:00:00 2001 From: Neil Johari Date: Tue, 16 Sep 2025 00:03:08 -0700 Subject: [PATCH 166/245] Remove debug logging --- programs/dibio.c | 16 --------------- test_allocation_bug.sh | 44 ------------------------------------------ 2 files changed, 60 deletions(-) delete mode 100755 test_allocation_bug.sh diff --git a/programs/dibio.c b/programs/dibio.c index 29a27d9db..dc629103b 100644 --- a/programs/dibio.c +++ b/programs/dibio.c @@ -279,8 +279,6 @@ static fileStats DiB_fileStats(const char** fileNamesTable, int nbFiles, size_t for (n=0; n alloc_test/good_$i.txt -done - -echo "Valid files created (about 6 bytes each = 30 bytes total)" -echo "" - -# We need enough bad files to make totalSizeToLoad negative -# 30 bytes positive, so we need at least 31 bad files -echo "Adding 1000 non-existent files to make totalSizeToLoad very negative..." -echo "Expected: totalSizeToLoad = 30 + (1000 * -1) = -970 bytes" -echo "" - -# Build command -CMD="./zstd --train alloc_test/good_*.txt" -for i in {1..1000}; do - CMD="$CMD alloc_test/BAD_$i" -done -CMD="$CMD -o alloc_test/dict.zst --maxdict=65536 2>&1" - -echo "Running command..." -echo "=================" - -# Run and capture ALL debug output related to our issue -eval $CMD | grep -E "\[DEBUG FINAL\]|\[DEBUG\] Memory calc|\[BUG\]|About to malloc|Error|not enough memory" - -echo "" -echo "Output should show something like the following:" -echo "1. [DEBUG FINAL] fileStats: totalSizeToLoad=-970 (NEGATIVE!)" -echo "2. [BUG] totalSizeToLoad is NEGATIVE!" -echo "3. [DEBUG] Memory calc: showing huge loadedSize value" -echo "4. Error about memory allocation" From be072c708ef35ccdef0683421dff3c6b00590b9b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 20 Sep 2025 16:33:41 +0000 Subject: [PATCH 167/245] Added documentation details for Makefile installation and pkg-config. --- README.md | 10 +++++----- lib/README.md | 22 ++++++++++++++++++---- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 3adacad51..5af79386f 100644 --- a/README.md +++ b/README.md @@ -127,19 +127,19 @@ When your system allows it, prefer using `make` to build `zstd` and `libzstd`. ### Makefile -If your system is compatible with standard `make` (or `gmake`), +Assuming your system supports standard `make` (or `gmake`), invoking `make` in root directory will generate `zstd` cli in root directory. It will also create `libzstd` into `lib/`. -Other available options include: +Other standard targets include: - `make install` : create and install zstd cli, library and man pages - `make check` : create and run `zstd`, test its behavior on local platform The `Makefile` follows the [GNU Standard Makefile conventions](https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html), -allowing staged install, standard flags, directory variables and command variables. +allowing staged install, standard compilation flags, directory variables and command variables. -For advanced use cases, specialized compilation flags which control binary generation -are documented in [`lib/README.md`](lib/README.md#modular-build) for the `libzstd` library +For advanced use cases, specialized flags which control binary generation and installation paths are documented +in [`lib/README.md`](lib/README.md#modular-build) for the `libzstd` library and in [`programs/README.md`](programs/README.md#compilation-variables) for the `zstd` CLI. ### cmake diff --git a/lib/README.md b/lib/README.md index 89e53e6c8..3974de160 100644 --- a/lib/README.md +++ b/lib/README.md @@ -7,15 +7,29 @@ in order to make it easier to select or exclude features. #### Building -`Makefile` script is provided, supporting [Makefile conventions](https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html#Makefile-Conventions), +A `Makefile` script is provided, supporting [Makefile conventions](https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html#Makefile-Conventions), including commands variables, staged install, directory variables and standard targets. - `make` : generates both static and dynamic libraries -- `make install` : install libraries and headers in target system directories +- `make install` : install libraries, headers and pkg-config in local system directories -`libzstd` default scope is pretty large, including compression, decompression, dictionary builder, -and support for decoding legacy formats >= v0.5.0. +`libzstd` default scope is extensive, including compression, decompression, dictionary builder, +and support for decoding legacy formats >= v0.5.0 by default. The scope can be reduced on demand (see paragraph _modular build_). +#### Multiarch Support + +For multiarch systems (like Debian/Ubuntu), libraries should be installed to architecture-specific directories. +When creating packages for such systems, use the `LIBDIR` variable to specify the correct multiarch path: + +```bash +# For x86_64 systems on Ubuntu/Debian: +make install PREFIX=/usr LIBDIR=/usr/lib/x86_64-linux-gnu + +# For ARM64 systems on Ubuntu/Debian: +make install PREFIX=/usr LIBDIR=/usr/lib/aarch64-linux-gnu +``` + +This will not only install the files in the correct directories, but also generate the correct paths for `pkg-config`. #### Multithreading support From 0c6d32df9a6f29e8b2b5d6232981e2606d35f8a3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 20 Sep 2025 22:13:49 -0700 Subject: [PATCH 168/245] added profiling notes for Visual Studio --- CONTRIBUTING.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 57be94bf5..a9ad99ebd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -373,7 +373,12 @@ counter `L1-dcache-load-misses` #### Visual Studio -TODO +Build Zstd with symbols first (for example `cmake -B build -S build/cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo && ninja -C build zstd`) so the profiler resolves call stacks. + +* Launch Visual Studio’s Performance Profiler (`Alt+F2`), enable CPU Usage (optionally Instrumentation), and point it at the `programs/zstd` benchmark you want to run. +* If you prefer to start the benchmark from a terminal, use “Attach to running process” to latch onto it mid-run; keep frame pointers (`-fno-omit-frame-pointer`) for clean stacks. +* When you stop the capture, review the call tree, hot path, and annotated source panes +* Microsoft’s [Performance Profiling docs](https://learn.microsoft.com/en-us/visualstudio/profiling/?view=vs-2022) cover deeper sampling, ETW, and collection options if required. ## Issues We use GitHub issues to track public bugs. Please ensure your description is From eb062bc339dc0e1f12da9b28213d0efd46127c21 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Tue, 23 Sep 2025 10:29:44 +0200 Subject: [PATCH 169/245] Split lib target types in their own export groups This allows for the non-primary library to be missing in the Config.cmake file, e.g. if the devel files have a separate static-devel package Signed-off-by: Cristian Le --- build/cmake/CMakeModules/ZstdPackage.cmake | 27 ++++++++++--------- build/cmake/lib/CMakeLists.txt | 31 ++++++++++------------ build/cmake/zstdConfig.cmake.in | 3 +++ 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/build/cmake/CMakeModules/ZstdPackage.cmake b/build/cmake/CMakeModules/ZstdPackage.cmake index 5e40dd2c1..ed20f3c97 100644 --- a/build/cmake/CMakeModules/ZstdPackage.cmake +++ b/build/cmake/CMakeModules/ZstdPackage.cmake @@ -11,21 +11,24 @@ write_basic_package_version_file( COMPATIBILITY SameMajorVersion ) -# Export targets for build directory -export(EXPORT zstdExports - FILE "${CMAKE_CURRENT_BINARY_DIR}/zstdTargets.cmake" - NAMESPACE zstd:: -) - # Configure package for installation set(ConfigPackageLocation ${CMAKE_INSTALL_LIBDIR}/cmake/zstd) -# Install exported targets -install(EXPORT zstdExports - FILE zstdTargets.cmake - NAMESPACE zstd:: - DESTINATION ${ConfigPackageLocation} -) +foreach(target_suffix IN ITEMS "_shared" "_static" "") + if(TARGET "libzstd${target_suffix}") + # Export targets for build directory + export(EXPORT "zstdExports${target_suffix}" + FILE "${CMAKE_CURRENT_BINARY_DIR}/zstdTargets${target_suffix}.cmake" + NAMESPACE zstd:: + ) + # Install exported targets + install(EXPORT "zstdExports${target_suffix}" + FILE "zstdTargets${target_suffix}.cmake" + NAMESPACE zstd:: + DESTINATION ${ConfigPackageLocation} + ) + endif() +endforeach() # Configure and install package config file configure_package_config_file( diff --git a/build/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt index a6b894c4d..04177925f 100644 --- a/build/cmake/lib/CMakeLists.txt +++ b/build/cmake/lib/CMakeLists.txt @@ -122,11 +122,9 @@ endmacro () set(PUBLIC_INCLUDE_DIRS ${LIBRARY_DIR}) set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} /I \"${LIBRARY_DIR}\"") # Split project to static and shared libraries build -set(library_targets) if (ZSTD_BUILD_SHARED) add_library(libzstd_shared SHARED ${Sources} ${Headers} ${PlatformDependResources}) target_include_directories(libzstd_shared INTERFACE $) - list(APPEND library_targets libzstd_shared) if (ZSTD_MULTITHREAD_SUPPORT) target_compile_definitions(libzstd_shared PUBLIC ZSTD_MULTITHREAD) if (UNIX) @@ -140,7 +138,6 @@ endif () if (ZSTD_BUILD_STATIC) add_library(libzstd_static STATIC ${Sources} ${Headers}) target_include_directories(libzstd_static INTERFACE $) - list(APPEND library_targets libzstd_static) if (ZSTD_MULTITHREAD_SUPPORT) target_compile_definitions(libzstd_static PUBLIC ZSTD_MULTITHREAD) if (UNIX) @@ -159,7 +156,6 @@ if (ZSTD_BUILD_SHARED AND NOT ZSTD_BUILD_STATIC) endif () add_library(libzstd INTERFACE) target_link_libraries(libzstd INTERFACE libzstd_shared) - list(APPEND library_targets libzstd) endif () if (ZSTD_BUILD_STATIC AND NOT ZSTD_BUILD_SHARED) if (BUILD_SHARED_LIBS) @@ -167,7 +163,6 @@ if (ZSTD_BUILD_STATIC AND NOT ZSTD_BUILD_SHARED) endif () add_library(libzstd INTERFACE) target_link_libraries(libzstd INTERFACE libzstd_static) - list(APPEND library_targets libzstd) endif () if (ZSTD_BUILD_SHARED AND ZSTD_BUILD_STATIC) # If both ZSTD_BUILD_SHARED and ZSTD_BUILD_STATIC are set, which is the @@ -176,11 +171,9 @@ if (ZSTD_BUILD_SHARED AND ZSTD_BUILD_STATIC) if (BUILD_SHARED_LIBS) add_library(libzstd INTERFACE) target_link_libraries(libzstd INTERFACE libzstd_shared) - list(APPEND library_targets libzstd) else () add_library(libzstd INTERFACE) target_link_libraries(libzstd INTERFACE libzstd_static) - list(APPEND library_targets libzstd) endif () endif () @@ -274,16 +267,20 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libzstd.pc" DESTINATION "${CMAKE_INST # install target install(FILES ${PublicHeaders} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") -install(TARGETS ${library_targets} - EXPORT zstdExports - INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" - BUNDLE DESTINATION "${CMAKE_INSTALL_BINDIR}" - FRAMEWORK DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT runtime OPTIONAL - PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" - ) +foreach(target_suffix IN ITEMS "_shared" "_static" "") + if(TARGET "libzstd${target_suffix}") + install(TARGETS "libzstd${target_suffix}" + EXPORT "zstdExports${target_suffix}" + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + BUNDLE DESTINATION "${CMAKE_INSTALL_BINDIR}" + FRAMEWORK DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT runtime OPTIONAL + PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + ) + endif() +endforeach() # uninstall target if (NOT TARGET uninstall) diff --git a/build/cmake/zstdConfig.cmake.in b/build/cmake/zstdConfig.cmake.in index f4190f989..a719d7899 100644 --- a/build/cmake/zstdConfig.cmake.in +++ b/build/cmake/zstdConfig.cmake.in @@ -5,6 +5,9 @@ if(@ZSTD_MULTITHREAD_SUPPORT@ AND "@UNIX@") find_dependency(Threads) endif() +foreach(lib_suffix IN ITEMS "_shared" "_static") + include("${CMAKE_CURRENT_LIST_DIR}/zstdTargets${lib_suffix}.cmake" OPTIONAL) +endforeach() include("${CMAKE_CURRENT_LIST_DIR}/zstdTargets.cmake") check_required_components("zstd") From 4c1f86c7773dca5233aa75cd33515504bc3fba96 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 23 Sep 2025 11:25:54 -0700 Subject: [PATCH 170/245] fix minor warning in legacy decoders for mingw + clang CI test --- lib/legacy/zstd_v01.c | 2 +- lib/legacy/zstd_v03.c | 2 +- lib/legacy/zstd_v04.c | 2 +- lib/legacy/zstd_v05.c | 2 +- lib/legacy/zstd_v06.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/legacy/zstd_v01.c b/lib/legacy/zstd_v01.c index ad3c9330e..29e875713 100644 --- a/lib/legacy/zstd_v01.c +++ b/lib/legacy/zstd_v01.c @@ -430,7 +430,7 @@ static unsigned FSE_isError(size_t code) { return (code > (size_t)(-FSE_ERROR_ma static short FSE_abs(short a) { - return a<0? -a : a; + return a<0? (short)-a : a; } diff --git a/lib/legacy/zstd_v03.c b/lib/legacy/zstd_v03.c index 7d82db666..50fa87cf3 100644 --- a/lib/legacy/zstd_v03.c +++ b/lib/legacy/zstd_v03.c @@ -1111,7 +1111,7 @@ static unsigned FSE_isError(size_t code) { return ERR_isError(code); } ****************************************************************/ static short FSE_abs(short a) { - return a<0 ? -a : a; + return a<0 ? (short)-a : a; } static size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, diff --git a/lib/legacy/zstd_v04.c b/lib/legacy/zstd_v04.c index 0da316c15..31c205258 100644 --- a/lib/legacy/zstd_v04.c +++ b/lib/legacy/zstd_v04.c @@ -1094,7 +1094,7 @@ static unsigned FSE_isError(size_t code) { return ERR_isError(code); } ****************************************************************/ static short FSE_abs(short a) { - return a<0 ? -a : a; + return a<0 ? (short)-a : a; } static size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, diff --git a/lib/legacy/zstd_v05.c b/lib/legacy/zstd_v05.c index 7a3af4214..e1efca597 100644 --- a/lib/legacy/zstd_v05.c +++ b/lib/legacy/zstd_v05.c @@ -1224,7 +1224,7 @@ const char* FSEv05_getErrorName(size_t code) { return ERR_getErrorName(code); } /*-************************************************************** * FSEv05 NCount encoding-decoding ****************************************************************/ -static short FSEv05_abs(short a) { return a<0 ? -a : a; } +static short FSEv05_abs(short a) { return a<0 ? (short)-a : a; } size_t FSEv05_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, diff --git a/lib/legacy/zstd_v06.c b/lib/legacy/zstd_v06.c index 88a39e2a0..fb8c14df9 100644 --- a/lib/legacy/zstd_v06.c +++ b/lib/legacy/zstd_v06.c @@ -1202,7 +1202,7 @@ static unsigned HUFv06_isError(size_t code) { return ERR_isError(code); } /*-************************************************************** * FSE NCount encoding-decoding ****************************************************************/ -static short FSEv06_abs(short a) { return a<0 ? -a : a; } +static short FSEv06_abs(short a) { return a<0 ? (short)-a : a; } size_t FSEv06_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, const void* headerBuffer, size_t hbSize) From c15fa3cd4038892bf3e9abe852abb950bb10deca Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 23 Sep 2025 23:17:11 -0700 Subject: [PATCH 171/245] update documentation of ZSTD_getFrameContentSize() hopefully answering #4495 --- lib/zstd.h | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index 850469490..415474d01 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -176,30 +176,30 @@ ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity, /*====== Decompression helper functions ======*/ -/*! ZSTD_getFrameContentSize() : requires v1.3.0+ - * `src` should point to the start of a ZSTD encoded frame. - * `srcSize` must be at least as large as the frame header. - * hint : any size >= `ZSTD_frameHeaderSize_max` is large enough. - * @return : - decompressed size of `src` frame content, if known - * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined - * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) - * note 1 : a 0 return value means the frame is valid but "empty". - * When invoking this method on a skippable frame, it will return 0. - * note 2 : decompressed size is an optional field, it may not be present (typically in streaming mode). - * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. - * In which case, it's necessary to use streaming mode to decompress data. - * Optionally, application can rely on some implicit limit, - * as ZSTD_decompress() only needs an upper bound of decompressed size. - * (For example, data could be necessarily cut into blocks <= 16 KB). - * note 3 : decompressed size is always present when compression is completed using single-pass functions, - * such as ZSTD_compress(), ZSTD_compressCCtx() ZSTD_compress_usingDict() or ZSTD_compress_usingCDict(). - * note 4 : decompressed size can be very large (64-bits value), - * potentially larger than what local system can handle as a single memory segment. - * In which case, it's necessary to use streaming mode to decompress data. - * note 5 : If source is untrusted, decompressed size could be wrong or intentionally modified. - * Always ensure return value fits within application's authorized limits. - * Each application can set its own limits. - * note 6 : This function replaces ZSTD_getDecompressedSize() */ +/*! @brief Returns the decompressed content size stored in a ZSTD frame header. + * + * @since v1.3.0 + * + * @param src Pointer to the beginning of a ZSTD encoded frame. + * @param srcSize Size of the buffer pointed to by @p src. It must be at least as large as the frame header. + * Any value greater than or equal to `ZSTD_frameHeaderSize_max` is sufficient. + * @return The decompressed size in bytes when the value is available in the frame header. + * @retval ZSTD_CONTENTSIZE_UNKNOWN The frame does not encode a decompressed size (typical for streaming). + * @retval ZSTD_CONTENTSIZE_ERROR An error occurred (e.g. invalid magic number, @p srcSize too small). + * + * @note The return value is not compatible with `ZSTD_isError()`. + * @note A return value of 0 denotes a valid but empty frame. Skippable frames also report 0. + * @note The decompressed size field is optional. When it is absent (the function returns @c ZSTD_CONTENTSIZE_UNKNOWN), + * the caller must rely on streaming decompression or an application-specific upper bound. `ZSTD_decompress()` + * only requires an upper bound, so applications may enforce their own block limits (for example 16 KB). + * @note The decompressed size is guaranteed to be present when compression was performed with single-pass APIs such as + * `ZSTD_compress()`, `ZSTD_compressCCtx()`, `ZSTD_compress_usingDict()`, or `ZSTD_compress_usingCDict()`. + * @note The decompressed size is a 64-bit value and may exceed the addressable space of the system. Use streaming + * decompression when the value is too large to materialize in contiguous memory. + * @warning When processing untrusted input, validate the returned size against the application's limits; attackers may + * forge an arbitrarily large value. + * @note This function replaces `ZSTD_getDecompressedSize()`. + */ #define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1) #define ZSTD_CONTENTSIZE_ERROR (0ULL - 2) ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize); From 17888b3fbeb04c0c518b9694a357818d736dab42 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 24 Sep 2025 22:08:03 -0700 Subject: [PATCH 172/245] fix minor initialization warnings --- lib/legacy/zstd_v01.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/legacy/zstd_v01.c b/lib/legacy/zstd_v01.c index 29e875713..d3322f93e 100644 --- a/lib/legacy/zstd_v01.c +++ b/lib/legacy/zstd_v01.c @@ -1823,11 +1823,12 @@ static size_t ZSTD_decompressSequences( BYTE* const ostart = (BYTE* const)dst; BYTE* op = ostart; BYTE* const oend = ostart + maxDstSize; - size_t errorCode, dumpsLength; + size_t errorCode = 0; + size_t dumpsLength = 0; const BYTE* litPtr = litStart; const BYTE* const litEnd = litStart + litSize; - int nbSeq; - const BYTE* dumps; + int nbSeq = 0; + const BYTE* dumps = NULL; U32* DTableLL = dctx->LLTable; U32* DTableML = dctx->MLTable; U32* DTableOffb = dctx->OffTable; @@ -1915,7 +1916,7 @@ size_t ZSTDv01_decompressDCtx(void* ctx, void* dst, size_t maxDstSize, const voi size_t remainingSize = srcSize; U32 magicNumber; size_t errorCode=0; - blockProperties_t blockProperties; + blockProperties_t blockProperties = { 0 }; /* Frame Header */ if (srcSize < ZSTD_frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); From c9d3af9ed0fa28b674270616c17e732e2ffcd8eb Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 20 Sep 2025 22:49:20 -0700 Subject: [PATCH 173/245] [cmake] root wrapper allow the existence of a `CMakeLists.txt` file at root, for easier integration with other projects expecting this file at root. Existing integration point, within `build/cmake/`, still works as expected. --- .gitignore | 21 +++++++++++---------- CMakeLists.txt | 11 +++++++++++ README.md | 43 +++++++++++++++++++++++++------------------ build/cmake/README.md | 9 +++++++++ 4 files changed, 56 insertions(+), 28 deletions(-) create mode 100644 CMakeLists.txt diff --git a/.gitignore b/.gitignore index 4b50bb186..03ecbde6a 100644 --- a/.gitignore +++ b/.gitignore @@ -22,16 +22,6 @@ zstdmt *.out *.app -# Test artefacts -tmp* -*.zst -*.zstd -dictionary. -dictionary -NUL -cmakebuild/ -install/ - # Build artefacts contrib/linux-kernel/linux/ projects/ @@ -40,6 +30,17 @@ bin/ buck-out/ build-* *.gcda +cmakebuild/ +cmake-build/ + +# Test artefacts +tmp* +*.zst +*.zstd +dictionary. +dictionary +NUL +install/ # IDE .clang_complete diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..10fef39b9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.10) + +# Thin wrapper so `cmake -S .` behaves like `cmake -S build/cmake`. +# Policy lives in build/cmake; keep parent project language-less. +project(zstd-superbuild LANGUAGES NONE) + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + message(FATAL_ERROR "In-source builds are not supported. Specify -B .") +endif() + +add_subdirectory(build/cmake) diff --git a/README.md b/README.md index 5af79386f..3aa01a0c1 100644 --- a/README.md +++ b/README.md @@ -120,20 +120,20 @@ Dictionary gains are mostly effective in the first few KB. Then, the compression ## Build instructions -`make` is the officially maintained build system of this project. -All other build systems are "compatible" and 3rd-party maintained, -they may feature small differences in advanced options. -When your system allows it, prefer using `make` to build `zstd` and `libzstd`. +`make` is the main build system of this project. +It is the reference, and other build systems are periodically updated to stay compatible. +However, small drifts and feature differences can be present, since perfect synchronization is difficult. +For this reason, when your build system allows it, prefer employing `make`. ### Makefile Assuming your system supports standard `make` (or `gmake`), -invoking `make` in root directory will generate `zstd` cli in root directory. -It will also create `libzstd` into `lib/`. +just invoking `make` in root directory generates `zstd` cli at root, +and also generates `libzstd` into `lib/`. Other standard targets include: -- `make install` : create and install zstd cli, library and man pages -- `make check` : create and run `zstd`, test its behavior on local platform +- `make install` : install zstd cli, library and man pages +- `make check` : run `zstd`, test its essential behavior on local platform The `Makefile` follows the [GNU Standard Makefile conventions](https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html), allowing staged install, standard compilation flags, directory variables and command variables. @@ -144,9 +144,16 @@ and in [`programs/README.md`](programs/README.md#compilation-variables) for the ### cmake -A `cmake` project generator is provided within `build/cmake`. -It can generate Makefiles or other build scripts -to create `zstd` binary, and `libzstd` dynamic and static libraries. +A `cmake` project generator is available for generating Makefiles or other build scripts +to create the `zstd` binary as well as `libzstd` dynamic and static libraries. +The repository root now contains a minimal `CMakeLists.txt` that forwards to `build/cmake`, +so you can configure the project with a standard `cmake -S .` invocation, +while the historical `cmake -S build/cmake` entry point remains fully supported. + +```bash +cmake -S . -B build-cmake +cmake --build build-cmake +``` By default, `CMAKE_BUILD_TYPE` is set to `Release`. @@ -156,7 +163,7 @@ By default, `CMAKE_BUILD_TYPE` is set to `Release`. To perform a Fat/Universal2 build and install use the following commands: ```bash -cmake -B build-cmake-debug -S build/cmake -G Ninja -DCMAKE_OSX_ARCHITECTURES="x86_64;x86_64h;arm64" +cmake -S . -B build-cmake-debug -G Ninja -DCMAKE_OSX_ARCHITECTURES="x86_64;x86_64h;arm64" cd build-cmake-debug ninja sudo ninja install @@ -198,10 +205,11 @@ If the version is out of date, please [create an issue or pull request](https:// ### Visual Studio (Windows) Going into `build` directory, you will find additional possibilities: -- Projects for Visual Studio 2005, 2008 and 2010. +- Projects for Visual Studio 2008 and 2010. + VS2010 project is compatible with VS2012, VS2013, VS2015 and VS2017. - Automated build scripts for Visual compiler by [@KrzysFR](https://github.com/KrzysFR), in `build/VS_scripts`, which will build `zstd` cli and `libzstd` library without any need to open Visual Studio solution. +- It is now recommended to generate Visual Studio solutions from `cmake` ### Buck @@ -210,7 +218,7 @@ The output binary will be in `buck-out/gen/programs/`. ### Bazel -You easily can integrate zstd into your Bazel project by using the module hosted on the [Bazel Central Repository](https://registry.bazel.build/modules/zstd). +You can integrate zstd into your Bazel project by using the module hosted on the [Bazel Central Repository](https://registry.bazel.build/modules/zstd). ## Testing @@ -221,9 +229,9 @@ For information on CI testing, please refer to `TESTING.md`. ## Status -Zstandard is currently deployed within Facebook and many other large cloud infrastructures. -It is run continuously to compress large amounts of data in multiple formats and use cases. -Zstandard is considered safe for production environments. +Zstandard is deployed within Meta and many other large cloud infrastructures, +to compress humongous amounts of data in various formats and use cases. +It is also continuously fuzzed for security issues by Google's [oss-fuzz](https://github.com/google/oss-fuzz/tree/master/projects/zstd) program. ## License @@ -232,6 +240,5 @@ Zstandard is dual-licensed under [BSD](LICENSE) OR [GPLv2](COPYING). ## Contributing The `dev` branch is the one where all contributions are merged before reaching `release`. -If you plan to propose a patch, please commit into the `dev` branch, or its own feature branch. Direct commit to `release` are not permitted. For more information, please read [CONTRIBUTING](CONTRIBUTING.md). diff --git a/build/cmake/README.md b/build/cmake/README.md index 6baa5974b..41c8bbb1a 100644 --- a/build/cmake/README.md +++ b/build/cmake/README.md @@ -7,6 +7,15 @@ variables. ## How to build +You can configure the project from the repository root thanks to the forwarding +`CMakeLists.txt`: +```sh +cmake -S . -B build-cmake +cmake --build build-cmake +``` +The historical workflow that starts configuration from `build/cmake` continues +to work as described below. + As cmake doesn't support command like `cmake clean`, it's recommended to perform an "out of source build". To do this, you can create a new directory and build in it: ```sh From 7758cc3e7a9821ab2a3870d47204246c90ac602f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 24 Sep 2025 21:55:31 -0700 Subject: [PATCH 174/245] [cmake] add minimal build test for CMakeLists.txt at root --- .github/workflows/cmake-tests.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index f1ed1f850..5534cdf89 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -21,11 +21,26 @@ env: COMMON_CMAKE_FLAGS: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON" jobs: + # Basic cmake build using the root CMakeLists.txt + # Provides a lightweight sanity check that the top-level project config builds + # with the default Unix Makefiles generator driven purely through cmake commands + cmake-root-basic: + name: "CMake Root Build" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - name: Configure (Root) + run: | + cmake -S . -B cmake-build -DCMAKE_BUILD_TYPE=Release ${{ env.COMMON_CMAKE_FLAGS }} + - name: Build (Root) + run: | + cmake --build cmake-build --config Release + # Ubuntu-based cmake build using make wrapper # This test uses the make-driven cmake build to ensure compatibility # with the existing build system integration cmake-ubuntu-basic: - name: "CMake Ubuntu Basic Build" + name: "CMake build using make wrapper" runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 From 87cc127705f4094e21d0428545d22ac651b80b24 Mon Sep 17 00:00:00 2001 From: ZijianLi Date: Fri, 26 Sep 2025 14:26:52 +0800 Subject: [PATCH 175/245] - Modify the GCC version used for CI testing of the RISCV architecture - Fix a bug in the ZSTD_row_getRVVMask function - Improve some performance for ZSTD_copy16() --- .github/workflows/dev-short-tests.yml | 2 +- lib/common/compiler.h | 15 ++++------- lib/common/zstd_internal.h | 2 ++ lib/compress/zstd_compress.c | 4 +-- lib/compress/zstd_lazy.c | 38 ++++++++++++++++----------- 5 files changed, 32 insertions(+), 29 deletions(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 59f4c1b77..20a11335f 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -403,7 +403,7 @@ jobs: { name: PPC64LE, xcc_pkg: gcc-powerpc64le-linux-gnu, xcc: powerpc64le-linux-gnu-gcc, xemu_pkg: qemu-system-ppc, xemu: qemu-ppc64le-static }, { name: S390X, xcc_pkg: gcc-s390x-linux-gnu, xcc: s390x-linux-gnu-gcc, xemu_pkg: qemu-system-s390x, xemu: qemu-s390x-static }, { name: MIPS, xcc_pkg: gcc-mips-linux-gnu, xcc: mips-linux-gnu-gcc, xemu_pkg: qemu-system-mips, xemu: qemu-mips-static }, - { name: RISC-V, xcc_pkg: gcc-riscv64-linux-gnu, xcc: riscv64-linux-gnu-gcc, xemu_pkg: qemu-system-riscv64,xemu: qemu-riscv64-static }, + { name: RISC-V, xcc_pkg: gcc-14-riscv64-linux-gnu, xcc: riscv64-linux-gnu-gcc-14, xemu_pkg: qemu-system-riscv64,xemu: qemu-riscv64-static }, { name: M68K, xcc_pkg: gcc-m68k-linux-gnu, xcc: m68k-linux-gnu-gcc, xemu_pkg: qemu-system-m68k, xemu: qemu-m68k-static }, { name: SPARC, xcc_pkg: gcc-sparc64-linux-gnu, xcc: sparc64-linux-gnu-gcc, xemu_pkg: qemu-system-sparc, xemu: qemu-sparc64-static }, ] diff --git a/lib/common/compiler.h b/lib/common/compiler.h index 410068de4..5e70570ec 100644 --- a/lib/common/compiler.h +++ b/lib/common/compiler.h @@ -224,16 +224,11 @@ # if defined(__ARM_FEATURE_SVE2) # define ZSTD_ARCH_ARM_SVE2 # endif -#if defined(__riscv) && defined(__riscv_vector) - #if defined(__GNUC__) - #if (__GNUC__ > 14 || (__GNUC__ == 14 && __GNUC_MINOR__ >= 1)) - #define ZSTD_ARCH_RISCV_RVV - #endif - #elif defined(__clang__) - #if __clang_major__ > 18 || (__clang_major__ == 18 && __clang_minor__ >= 1) - #define ZSTD_ARCH_RISCV_RVV - #endif - #endif +# if defined(__riscv) && defined(__riscv_vector) +# if ((defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 14) || \ + (defined(__clang__) && __clang_major__ >= 19)) + #define ZSTD_ARCH_RISCV_RVV +# endif #endif # # if defined(ZSTD_ARCH_X86_AVX2) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 791b6485d..86a0fc5c8 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -185,6 +185,8 @@ static void ZSTD_copy16(void* dst, const void* src) { vst1q_u8((uint8_t*)dst, vld1q_u8((const uint8_t*)src)); #elif defined(ZSTD_ARCH_X86_SSE2) _mm_storeu_si128((__m128i*)dst, _mm_loadu_si128((const __m128i*)src)); +#elif defined(ZSTD_ARCH_RISCV_RVV) + __riscv_vse8_v_u8m1((uint8_t*)dst, __riscv_vle8_v_u8m1((const uint8_t*)src, 16), 16); #elif defined(__clang__) ZSTD_memmove(dst, src, 16); #else diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index ce5891067..1d6f0fcae 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -7292,7 +7292,7 @@ size_t convertSequences_noRepcodes( return longLen; } -#elif defined ZSTD_ARCH_RISCV_RVV +#elif defined (ZSTD_ARCH_RISCV_RVV) #include /* * Convert `vl` sequences per iteration, using RVV intrinsics: @@ -7824,7 +7824,7 @@ BlockSummary ZSTD_get1BlockSummary(const ZSTD_Sequence* seqs, size_t nbSeqs) } } -#elif defined ZSTD_ARCH_RISCV_RVV +#elif defined (ZSTD_ARCH_RISCV_RVV) BlockSummary ZSTD_get1BlockSummary(const ZSTD_Sequence* seqs, size_t nbSeqs) { diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c index f5efa8d8a..18b7b4394 100644 --- a/lib/compress/zstd_lazy.c +++ b/lib/compress/zstd_lazy.c @@ -1052,33 +1052,39 @@ ZSTD_row_getNEONMask(const U32 rowEntries, const BYTE* const src, const BYTE tag #endif #if defined(ZSTD_ARCH_RISCV_RVV) && (__riscv_xlen == 64) FORCE_INLINE_TEMPLATE ZSTD_VecMask -ZSTD_row_getRVVMask(int nbChunks, const BYTE* const src, const BYTE tag, const U32 head) +ZSTD_row_getRVVMask(int rowEntries, const BYTE* const src, const BYTE tag, const U32 head) { ZSTD_VecMask matches; size_t vl; if (rowEntries == 16) { vl = __riscv_vsetvl_e8m1(16); - vuint8m1_t chunk = __riscv_vle8_v_u8m1(src, vl); - vbool8_t mask = __riscv_vmseq_vx_u8m1_b8(chunk, tag, vl); - vuint16m1_t mask_u16 = __riscv_vreinterpret_v_b8_u16m1(mask); - matches = __riscv_vmv_x_s_u16m1_u16(mask_u16); - return ZSTD_rotateRight_U16((U16)matches, head); + { + vuint8m1_t chunk = __riscv_vle8_v_u8m1(src, vl); + vbool8_t mask = __riscv_vmseq_vx_u8m1_b8(chunk, tag, vl); + vuint16m1_t mask_u16 = __riscv_vreinterpret_v_b8_u16m1(mask); + matches = __riscv_vmv_x_s_u16m1_u16(mask_u16); + return ZSTD_rotateRight_U16((U16)matches, head); + } } else if (rowEntries == 32) { vl = __riscv_vsetvl_e8m2(32); - vuint8m2_t chunk = __riscv_vle8_v_u8m2(src, vl); - vbool4_t mask = __riscv_vmseq_vx_u8m2_b4(chunk, tag, vl); - vuint32m1_t mask_u32 = __riscv_vreinterpret_v_b4_u32m1(mask); - matches = __riscv_vmv_x_s_u32m1_u32(mask_u32); - return ZSTD_rotateRight_U32((U32)matches, head); + { + vuint8m2_t chunk = __riscv_vle8_v_u8m2(src, vl); + vbool4_t mask = __riscv_vmseq_vx_u8m2_b4(chunk, tag, vl); + vuint32m1_t mask_u32 = __riscv_vreinterpret_v_b4_u32m1(mask); + matches = __riscv_vmv_x_s_u32m1_u32(mask_u32); + return ZSTD_rotateRight_U32((U32)matches, head); + } } else { // rowEntries = 64 vl = __riscv_vsetvl_e8m4(64); - vuint8m4_t chunk = __riscv_vle8_v_u8m4(src, vl); - vbool2_t mask = __riscv_vmseq_vx_u8m4_b2(chunk, tag, vl); - vuint64m1_t mask_u64 = __riscv_vreinterpret_v_b2_u64m1(mask); - matches = __riscv_vmv_x_s_u64m1_u64(mask_u64); - return ZSTD_rotateRight_U64(matches, head); + { + vuint8m4_t chunk = __riscv_vle8_v_u8m4(src, vl); + vbool2_t mask = __riscv_vmseq_vx_u8m4_b2(chunk, tag, vl); + vuint64m1_t mask_u64 = __riscv_vreinterpret_v_b2_u64m1(mask); + matches = __riscv_vmv_x_s_u64m1_u64(mask_u64); + return ZSTD_rotateRight_U64(matches, head); + } } } #endif From f94a01de746aacd16afe3ea84ddd671a6754de3b Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 2 Oct 2025 14:40:11 +0200 Subject: [PATCH 176/245] Enable ASM language during CMake configure time only when needed --- build/cmake/CMakeLists.txt | 2 +- build/cmake/lib/CMakeLists.txt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt index 753cf4a9e..7cb0b6843 100644 --- a/build/cmake/CMakeLists.txt +++ b/build/cmake/CMakeLists.txt @@ -29,7 +29,7 @@ include(ZstdVersion) #----------------------------------------------------------------------------- project(zstd VERSION "${ZSTD_FULL_VERSION}" - LANGUAGES C ASM # Main library is in C and ASM + LANGUAGES C # Main library is in C and ASM, ASM is enabled conditionally HOMEPAGE_URL "${zstd_HOMEPAGE_URL}" DESCRIPTION "${zstd_DESCRIPTION}" ) diff --git a/build/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt index a6b894c4d..0cd02d623 100644 --- a/build/cmake/lib/CMakeLists.txt +++ b/build/cmake/lib/CMakeLists.txt @@ -7,7 +7,7 @@ # in the COPYING file in the root directory of this source tree). # ################################################################ -project(libzstd C ASM) +project(libzstd C) # ASM language is conditionally enabled where supported set(CMAKE_INCLUDE_CURRENT_DIR TRUE) option(ZSTD_BUILD_STATIC "BUILD STATIC LIBRARIES" ON) @@ -40,6 +40,7 @@ if (MSVC) add_compile_options(-DZSTD_DISABLE_ASM) else () if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|AMD64.*|x86_64.*|X86_64.*" AND ${ZSTD_HAS_NOEXECSTACK}) + enable_language(ASM) set(DecompressSources ${DecompressSources} ${LIBRARY_DIR}/decompress/huf_decompress_amd64.S) else() add_compile_options(-DZSTD_DISABLE_ASM) From 33618c89e511637f8a6ef955b3501766d71feb53 Mon Sep 17 00:00:00 2001 From: Arpad Panyik Date: Wed, 8 Oct 2025 18:58:45 +0000 Subject: [PATCH 177/245] AArch64: Revert previous branch optimization Revert a branch optimization that was based on an incorrect assumption in the AArch64 part of ZSTD_decodeSequence. In extreme cases the existing implementation could lead to data corruption. Insert an UNLIKELY hint to guide the compilers toward generating more efficient machine code. --- lib/decompress/zstd_decompress_block.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/decompress/zstd_decompress_block.c b/lib/decompress/zstd_decompress_block.c index b2ccd92a1..b4cc731ac 100644 --- a/lib/decompress/zstd_decompress_block.c +++ b/lib/decompress/zstd_decompress_block.c @@ -1332,14 +1332,11 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c seq.offset = offset; } - if (mlBits > 0) { + if (mlBits > 0) seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/); - if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) - BIT_reloadDStream(&seqState->DStream); - if (MEM_64bits() && (totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) - BIT_reloadDStream(&seqState->DStream); - } + if (UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) + BIT_reloadDStream(&seqState->DStream); /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); From 0dffae42e3ba81d08e1bc387d3f6d9d2ea303026 Mon Sep 17 00:00:00 2001 From: Arpad Panyik Date: Wed, 8 Oct 2025 18:59:24 +0000 Subject: [PATCH 178/245] AArch64: Remove 32-bit code from ZSTD_decodeSequence Remove the 32-bit code paths from the AArch64 only sections of ZSTD_decodeSequence. --- lib/decompress/zstd_decompress_block.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/lib/decompress/zstd_decompress_block.c b/lib/decompress/zstd_decompress_block.c index b4cc731ac..56e1f9eda 100644 --- a/lib/decompress/zstd_decompress_block.c +++ b/lib/decompress/zstd_decompress_block.c @@ -1261,6 +1261,7 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c const ZSTD_seqSymbol* const mlDInfo = seqState->stateML.table + seqState->stateML.state; const ZSTD_seqSymbol* const ofDInfo = seqState->stateOffb.table + seqState->stateOffb.state; # endif + (void)longOffsets; seq.matchLength = mlDInfo->baseValue; seq.litLength = llDInfo->baseValue; { U32 const ofBase = ofDInfo->baseValue; @@ -1290,18 +1291,7 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 > LONG_OFFSETS_MAX_EXTRA_BITS_32); ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 - LONG_OFFSETS_MAX_EXTRA_BITS_32 >= MaxMLBits); - if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { - /* Always read extra bits, this keeps the logic simple, - * avoids branches, and avoids accidentally reading 0 bits. - */ - U32 const extraBits = LONG_OFFSETS_MAX_EXTRA_BITS_32; - offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); - BIT_reloadDStream(&seqState->DStream); - offset += BIT_readBitsFast(&seqState->DStream, extraBits); - } else { - offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); - } + offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ prevOffset2 = prevOffset1; prevOffset1 = prevOffset0; prevOffset0 = offset; @@ -1344,9 +1334,6 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c if (llBits > 0) seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/); - if (MEM_32bits()) - BIT_reloadDStream(&seqState->DStream); - DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); @@ -1354,7 +1341,6 @@ ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, c /* Don't update FSE state for last sequence. */ ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llNext, llnbBits); /* <= 9 bits */ ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlNext, mlnbBits); /* <= 9 bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofNext, ofnbBits); /* <= 8 bits */ BIT_reloadDStream(&seqState->DStream); } From 5539fcfb6afb6ac1acf223bcef7de71449572896 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 23 Oct 2025 07:01:01 -0700 Subject: [PATCH 179/245] minor: fix mingw warnings: calloc argument order --- tests/paramgrill.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/paramgrill.c b/tests/paramgrill.c index 869e966e0..718196c9b 100644 --- a/tests/paramgrill.c +++ b/tests/paramgrill.c @@ -1242,7 +1242,7 @@ static int createBuffers(buffers_t* buff, const char* const * const fileNamesTab size_t n; size_t totalSizeToLoad = (size_t)UTIL_getTotalFileSize(fileNamesTable, (U32)nbFiles); size_t benchedSize = MIN(BMK_findMaxMem(totalSizeToLoad * 3) / 3, totalSizeToLoad); - size_t* fileSizes = calloc(sizeof(size_t), nbFiles); + size_t* fileSizes = calloc(nbFiles, sizeof(size_t)); void* srcBuffer = NULL; int ret = 0; @@ -1457,7 +1457,7 @@ createMemoTableArray(const paramValues_t p, const size_t varyLen, const U32 memoTableLog) { - memoTable_t* const mtAll = (memoTable_t*)calloc(sizeof(memoTable_t),(ZSTD_STRATEGY_MAX + 1)); + memoTable_t* const mtAll = (memoTable_t*)calloc((ZSTD_STRATEGY_MAX + 1), sizeof(memoTable_t)); ZSTD_strategy i, stratMin = ZSTD_STRATEGY_MIN, stratMax = ZSTD_STRATEGY_MAX; if(mtAll == NULL) { @@ -1494,7 +1494,7 @@ createMemoTableArray(const paramValues_t p, mtl = ((size_t)1 << memoTableLog); } - mtAll[i].table = (BYTE*)calloc(sizeof(BYTE), mtl); + mtAll[i].table = (BYTE*)calloc(mtl, sizeof(BYTE)); mtAll[i].tableLen = mtl; if(mtAll[i].table == NULL) { From c72eea13bff1e3c1c68e9428a69b0399ff10e91d Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 23 Oct 2025 06:08:36 +0200 Subject: [PATCH 180/245] Fix undefined names in automated_benchmarking.py Fix variable name typos in automated_benchmarking.py % `ruff check` ``` Error: tests/automated_benchmarking.py:237:21: F821 Undefined name `baseline_label` Error: tests/automated_benchmarking.py:250:21: F821 Undefined name `baseline_label` Error: tests/automated_benchmarking.py:318:55: F821 Undefined name `frequenc` Error: Process completed with exit code 1. ``` % [`ruff rule F821`](https://docs.astral.sh/ruff/rules/undefined-name) --- tests/automated_benchmarking.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/automated_benchmarking.py b/tests/automated_benchmarking.py index 153e7db4c..0935d1db4 100644 --- a/tests/automated_benchmarking.py +++ b/tests/automated_benchmarking.py @@ -225,7 +225,7 @@ def get_regressions_dictionary(baseline_build, test_build, filenames_directory, for j, level in enumerate(levels): old_cspeed, old_dspeed = old[j] new_cspeed, new_dspeed = new[j] - cspeed_reg, dspeed_reg, baesline_label, test_label = parse_regressions_and_labels( + cspeed_reg, dspeed_reg, baseline_label, test_label = parse_regressions_and_labels( old_cspeed, new_cspeed, old_dspeed, new_dspeed, baseline_build, test_build ) if cspeed_reg > CSPEED_REGRESSION_TOLERANCE: @@ -315,7 +315,7 @@ if __name__ == "__main__": quit() if mode == "onetime": - main(filenames, levels, iterations, frequency=frequenc, dictionary_filename=dictionary_filename) + main(filenames, levels, iterations, frequency=frequency, dictionary_filename=dictionary_filename) elif mode == "current": builds = [{"user": None, "branch": "None", "hash": None}] main(filenames, levels, iterations, builds, frequency=frequency, dictionary_filename=dictionary_filename) From 44cd3c8451dbd64d40725655bebcb9b7d245e87d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 25 Oct 2025 00:50:55 -0700 Subject: [PATCH 181/245] disable asyncio during compression it's not helpful for performance, and can in some times be detrimental. the synchronous mode is also much easier to follow and debug. --- programs/fileio.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 77f3d35f9..fec0e2d66 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1147,8 +1147,14 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, dictBufferType = (useMMap && !forceNoUseMMap) ? FIO_mmapDict : FIO_mallocDict; FIO_initDict(&ress.dict, dictFileName, prefs, &ress.dictFileStat, dictBufferType); /* works with dictFileName==NULL */ - ress.writeCtx = AIO_WritePool_create(prefs, ZSTD_CStreamOutSize()); - ress.readCtx = AIO_ReadPool_create(prefs, ZSTD_CStreamInSize()); + { + /* Compression paths stay synchronous for now: lower overhead and easier upkeep. */ + int const savedAsyncIO = prefs->asyncIO; + prefs->asyncIO = 0; + ress.writeCtx = AIO_WritePool_create(prefs, ZSTD_CStreamOutSize()); + ress.readCtx = AIO_ReadPool_create(prefs, ZSTD_CStreamInSize()); + prefs->asyncIO = savedAsyncIO; + } /* Advanced parameters, including dictionary */ if (dictFileName && (ress.dict.dictBuffer==NULL)) @@ -2070,16 +2076,12 @@ FIO_compressFilename_srcFile(FIO_ctx_t* const fCtx, srcFile = FIO_openSrcFile(prefs, srcFileName, &srcFileStat); if (srcFile == NULL) return 1; /* srcFile could not be opened */ - /* Don't use AsyncIO for small files */ + /* AsyncIO is disabled for compression to favor predictable performance and simpler upkeep. */ if (strcmp(srcFileName, stdinmark)) /* Stdin doesn't have stats */ fileSize = UTIL_getFileSizeStat(&srcFileStat); - if(fileSize != UTIL_FILESIZE_UNKNOWN && fileSize < ZSTD_BLOCKSIZE_MAX * 3) { - AIO_ReadPool_setAsync(ress.readCtx, 0); - AIO_WritePool_setAsync(ress.writeCtx, 0); - } else { - AIO_ReadPool_setAsync(ress.readCtx, 1); - AIO_WritePool_setAsync(ress.writeCtx, 1); - } + (void)fileSize; + AIO_ReadPool_setAsync(ress.readCtx, 0); + AIO_WritePool_setAsync(ress.writeCtx, 0); AIO_ReadPool_setFile(ress.readCtx, srcFile); result = FIO_compressFilename_dstFile( From d1dd7e1481d76db7f0c94f90ba57a607c4e5df9e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 25 Oct 2025 11:02:51 -0700 Subject: [PATCH 182/245] removed asyncio completely for compression path this does not provide speed benefits, since most of the leverage happens internally within the library, and can even become detrimental in certain scenario, due to complex and wasteful memory management. At a minimum, it makes the logic simpler, easier to debug, at essentially the same performance. --- programs/fileio.c | 498 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 366 insertions(+), 132 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index fec0e2d66..1e767ee64 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -48,6 +48,36 @@ FIO_display_prefs_t g_display_prefs = {2, FIO_ps_auto}; UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER; +/* ************************************* +* Synchronous compression IO helpers +***************************************/ +typedef struct { + const FIO_prefs_t* prefs; + FILE* srcFile; + FILE* dstFile; + unsigned storedSkips; + U8* inBuffer; + size_t inCapacity; + U8* srcBuffer; + size_t srcBufferLoaded; + U8* outBuffer; + size_t outCapacity; +} FIO_SyncCompressIO; + +static void FIO_SyncCompressIO_init(FIO_SyncCompressIO* io, + const FIO_prefs_t* prefs, + size_t inCapacity, + size_t outCapacity); +static void FIO_SyncCompressIO_free(FIO_SyncCompressIO* io); +static void FIO_SyncCompressIO_setSrc(FIO_SyncCompressIO* io, FILE* file); +static void FIO_SyncCompressIO_clearSrc(FIO_SyncCompressIO* io); +static void FIO_SyncCompressIO_setDst(FIO_SyncCompressIO* io, FILE* file); +static int FIO_SyncCompressIO_closeDst(FIO_SyncCompressIO* io); +static size_t FIO_SyncCompressIO_fillBuffer(FIO_SyncCompressIO* io, size_t minToHave); +static void FIO_SyncCompressIO_consumeBytes(FIO_SyncCompressIO* io, size_t n); +static void FIO_SyncCompressIO_commitOut(FIO_SyncCompressIO* io, const void* buffer, size_t size); +static void FIO_SyncCompressIO_finish(FIO_SyncCompressIO* io); + #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */ #include "../lib/zstd.h" #include "../lib/zstd_errors.h" /* ZSTD_error_frameParameter_windowTooLarge */ @@ -125,6 +155,233 @@ char const* FIO_lzmaVersion(void) #define TEMPORARY_FILE_PERMISSIONS (0600) #endif +static unsigned FIO_sparseWrite(FILE* file, + const void* buffer, size_t bufferSize, + const FIO_prefs_t* const prefs, + unsigned storedSkips) +{ + const size_t* const bufferT = (const size_t*)buffer; /* Buffer is supposed malloc'ed, hence aligned on size_t */ + size_t bufferSizeT = bufferSize / sizeof(size_t); + const size_t* const bufferTEnd = bufferT + bufferSizeT; + const size_t* ptrT = bufferT; + static const size_t segmentSizeT = (32 KB) / sizeof(size_t); /* check every 32 KB */ + + if (prefs->testMode) return 0; /* do not output anything in test mode */ + + if (!prefs->sparseFileSupport) { /* normal write */ + size_t const sizeCheck = fwrite(buffer, 1, bufferSize, file); + if (sizeCheck != bufferSize) + EXM_THROW(70, "Write error : cannot write block : %s", + strerror(errno)); + return 0; + } + + /* avoid int overflow */ + if (storedSkips > 1 GB) { + if (LONG_SEEK(file, 1 GB, SEEK_CUR) != 0) + EXM_THROW(91, "1 GB skip error (sparse file support)"); + storedSkips -= 1 GB; + } + + while (ptrT < bufferTEnd) { + size_t nb0T; + + /* adjust last segment if < 32 KB */ + size_t seg0SizeT = segmentSizeT; + if (seg0SizeT > bufferSizeT) seg0SizeT = bufferSizeT; + bufferSizeT -= seg0SizeT; + + /* count leading zeroes */ + for (nb0T=0; (nb0T < seg0SizeT) && (ptrT[nb0T] == 0); nb0T++) ; + storedSkips += (unsigned)(nb0T * sizeof(size_t)); + + if (nb0T != seg0SizeT) { /* not all 0s */ + size_t const nbNon0ST = seg0SizeT - nb0T; + /* skip leading zeros */ + if (LONG_SEEK(file, storedSkips, SEEK_CUR) != 0) + EXM_THROW(92, "Sparse skip error ; try --no-sparse"); + storedSkips = 0; + /* write the rest */ + if (fwrite(ptrT + nb0T, sizeof(size_t), nbNon0ST, file) != nbNon0ST) + EXM_THROW(93, "Write error : cannot write block : %s", + strerror(errno)); + } + ptrT += seg0SizeT; + } + + { static size_t const maskT = sizeof(size_t)-1; + if (bufferSize & maskT) { + /* size not multiple of sizeof(size_t) : implies end of block */ + const char* const restStart = (const char*)bufferTEnd; + const char* restPtr = restStart; + const char* const restEnd = (const char*)buffer + bufferSize; + assert(restEnd > restStart && restEnd < restStart + sizeof(size_t)); + for ( ; (restPtr < restEnd) && (*restPtr == 0); restPtr++) ; + storedSkips += (unsigned) (restPtr - restStart); + if (restPtr != restEnd) { + /* not all remaining bytes are 0 */ + size_t const restSize = (size_t)(restEnd - restPtr); + if (LONG_SEEK(file, storedSkips, SEEK_CUR) != 0) + EXM_THROW(92, "Sparse skip error ; try --no-sparse"); + if (fwrite(restPtr, 1, restSize, file) != restSize) + EXM_THROW(95, "Write error : cannot write end of decoded block : %s", + strerror(errno)); + storedSkips = 0; + } } } + + return storedSkips; +} + +static void FIO_sparseWriteEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedSkips) +{ + if (file == NULL) return; + if (prefs->testMode) { + assert(storedSkips == 0); + return; + } + if (storedSkips>0) { + assert(prefs->sparseFileSupport > 0); /* storedSkips>0 implies sparse support is enabled */ + if (LONG_SEEK(file, storedSkips-1, SEEK_CUR) != 0) + EXM_THROW(69, "Final skip error (sparse file support)"); + /* last zero must be explicitly written, + * so that skipped ones get implicitly translated as zero by FS */ + { const char lastZeroByte[1] = { 0 }; + if (fwrite(lastZeroByte, 1, 1, file) != 1) + EXM_THROW(69, "Write error : cannot write last zero : %s", strerror(errno)); + } + } +} + +static void FIO_SyncCompressIO_init(FIO_SyncCompressIO* io, + const FIO_prefs_t* prefs, + size_t inCapacity, + size_t outCapacity) +{ + memset(io, 0, sizeof(*io)); + io->prefs = prefs; + io->inCapacity = inCapacity; + io->outCapacity = outCapacity; + io->inBuffer = (U8*)malloc(inCapacity); + if (!io->inBuffer) + EXM_THROW(101, "Allocation error : not enough memory"); + io->outBuffer = (U8*)malloc(outCapacity); + if (!io->outBuffer) { + free(io->inBuffer); + io->inBuffer = NULL; + EXM_THROW(101, "Allocation error : not enough memory"); + } + io->srcBuffer = io->inBuffer; + io->srcBufferLoaded = 0; +} + +static void FIO_SyncCompressIO_free(FIO_SyncCompressIO* io) +{ + if (!io) return; + free(io->inBuffer); + free(io->outBuffer); + io->inBuffer = NULL; + io->outBuffer = NULL; + io->srcBuffer = NULL; + io->srcBufferLoaded = 0; + io->srcFile = NULL; + io->dstFile = NULL; + io->storedSkips = 0; +} + +static void FIO_SyncCompressIO_setSrc(FIO_SyncCompressIO* io, FILE* file) +{ + io->srcFile = file; + io->srcBuffer = io->inBuffer; + io->srcBufferLoaded = 0; +} + +static void FIO_SyncCompressIO_clearSrc(FIO_SyncCompressIO* io) +{ + io->srcFile = NULL; + io->srcBuffer = io->inBuffer; + io->srcBufferLoaded = 0; +} + +static void FIO_SyncCompressIO_setDst(FIO_SyncCompressIO* io, FILE* file) +{ + io->dstFile = file; + io->storedSkips = 0; +} + +static int FIO_SyncCompressIO_closeDst(FIO_SyncCompressIO* io) +{ + int result = 0; + if (io->dstFile != NULL) { + FIO_SyncCompressIO_finish(io); + result = fclose(io->dstFile); + io->dstFile = NULL; + } + return result; +} + +static size_t FIO_SyncCompressIO_fillBuffer(FIO_SyncCompressIO* io, size_t minToHave) +{ + size_t added = 0; + if (io->srcFile == NULL) + return 0; + + if (minToHave > io->inCapacity) + minToHave = io->inCapacity; + + if (io->srcBufferLoaded >= minToHave) + return 0; + + if (io->srcBuffer != io->inBuffer) { + if (io->srcBufferLoaded > 0) + memmove(io->inBuffer, io->srcBuffer, io->srcBufferLoaded); + io->srcBuffer = io->inBuffer; + } + + while (io->srcBufferLoaded < minToHave) { + size_t const toRead = io->inCapacity - io->srcBufferLoaded; + size_t const readBytes = fread(io->inBuffer + io->srcBufferLoaded, 1, toRead, io->srcFile); + if (readBytes == 0) { + if (ferror(io->srcFile)) + EXM_THROW(37, "Read error"); + break; /* EOF */ + } + io->srcBufferLoaded += readBytes; + added += readBytes; + if (readBytes < toRead) + break; + } + + return added; +} + +static void FIO_SyncCompressIO_consumeBytes(FIO_SyncCompressIO* io, size_t n) +{ + assert(n <= io->srcBufferLoaded); + io->srcBuffer += n; + io->srcBufferLoaded -= n; + if (io->srcBufferLoaded == 0) + io->srcBuffer = io->inBuffer; +} + +static void FIO_SyncCompressIO_commitOut(FIO_SyncCompressIO* io, const void* buffer, size_t size) +{ + if (size == 0) + return; + if (io->dstFile == NULL) { + assert(io->prefs->testMode); + return; + } + io->storedSkips = FIO_sparseWrite(io->dstFile, buffer, size, io->prefs, io->storedSkips); +} + +static void FIO_SyncCompressIO_finish(FIO_SyncCompressIO* io) +{ + if (io->dstFile == NULL) + return; + FIO_sparseWriteEnd(io->prefs, io->dstFile, io->storedSkips); + io->storedSkips = 0; +} + /*-************************************ * Signal (Ctrl-C trapping) **************************************/ @@ -1078,8 +1335,7 @@ typedef struct { const char* dictFileName; stat_t dictFileStat; ZSTD_CStream* cctx; - WritePoolCtx_t *writeCtx; - ReadPoolCtx_t *readCtx; + FIO_SyncCompressIO io; } cRess_t; /** ZSTD_cycleLog() : @@ -1147,14 +1403,7 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, dictBufferType = (useMMap && !forceNoUseMMap) ? FIO_mmapDict : FIO_mallocDict; FIO_initDict(&ress.dict, dictFileName, prefs, &ress.dictFileStat, dictBufferType); /* works with dictFileName==NULL */ - { - /* Compression paths stay synchronous for now: lower overhead and easier upkeep. */ - int const savedAsyncIO = prefs->asyncIO; - prefs->asyncIO = 0; - ress.writeCtx = AIO_WritePool_create(prefs, ZSTD_CStreamOutSize()); - ress.readCtx = AIO_ReadPool_create(prefs, ZSTD_CStreamInSize()); - prefs->asyncIO = savedAsyncIO; - } + FIO_SyncCompressIO_init(&ress.io, prefs, ZSTD_CStreamInSize(), ZSTD_CStreamOutSize()); /* Advanced parameters, including dictionary */ if (dictFileName && (ress.dict.dictBuffer==NULL)) @@ -1218,21 +1467,20 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, static void FIO_freeCResources(cRess_t* const ress) { FIO_freeDict(&(ress->dict)); - AIO_WritePool_free(ress->writeCtx); - AIO_ReadPool_free(ress->readCtx); + FIO_SyncCompressIO_free(&ress->io); ZSTD_freeCStream(ress->cctx); /* never fails */ } #ifdef ZSTD_GZCOMPRESS static unsigned long long -FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but not changed */ +FIO_compressGzFrame(cRess_t* ress, const char* srcFileName, U64 const srcFileSize, int compressionLevel, U64* readsize) { + FIO_SyncCompressIO* const io = &ress->io; unsigned long long inFileSize = 0, outFileSize = 0; z_stream strm; - IOJob_t *writeJob = NULL; if (compressionLevel > Z_BEST_COMPRESSION) compressionLevel = Z_BEST_COMPRESSION; @@ -1248,37 +1496,36 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no EXM_THROW(71, "zstd: %s: deflateInit2 error %d \n", srcFileName, ret); } } - writeJob = AIO_WritePool_acquireJob(ress->writeCtx); strm.next_in = 0; strm.avail_in = 0; - strm.next_out = (Bytef*)writeJob->buffer; - strm.avail_out = (uInt)writeJob->bufferSize; + strm.next_out = (Bytef*)io->outBuffer; + strm.avail_out = (uInt)io->outCapacity; while (1) { int ret; if (strm.avail_in == 0) { - AIO_ReadPool_fillBuffer(ress->readCtx, ZSTD_CStreamInSize()); - if (ress->readCtx->srcBufferLoaded == 0) break; - inFileSize += ress->readCtx->srcBufferLoaded; - strm.next_in = (z_const unsigned char*)ress->readCtx->srcBuffer; - strm.avail_in = (uInt)ress->readCtx->srcBufferLoaded; + size_t const added = FIO_SyncCompressIO_fillBuffer(io, ZSTD_CStreamInSize()); + if (io->srcBufferLoaded == 0) break; + inFileSize += added; + *readsize += added; + strm.next_in = (z_const unsigned char*)io->srcBuffer; + strm.avail_in = (uInt)io->srcBufferLoaded; } { size_t const availBefore = strm.avail_in; ret = deflate(&strm, Z_NO_FLUSH); - AIO_ReadPool_consumeBytes(ress->readCtx, availBefore - strm.avail_in); + FIO_SyncCompressIO_consumeBytes(io, availBefore - strm.avail_in); } if (ret != Z_OK) EXM_THROW(72, "zstd: %s: deflate error %d \n", srcFileName, ret); - { size_t const cSize = writeJob->bufferSize - strm.avail_out; + { size_t const cSize = (size_t)((uInt)io->outCapacity - strm.avail_out); if (cSize) { - writeJob->usedBufferSize = cSize; - AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); + FIO_SyncCompressIO_commitOut(io, io->outBuffer, cSize); outFileSize += cSize; - strm.next_out = (Bytef*)writeJob->buffer; - strm.avail_out = (uInt)writeJob->bufferSize; + strm.next_out = (Bytef*)io->outBuffer; + strm.avail_out = (uInt)io->outCapacity; } } if (srcFileSize == UTIL_FILESIZE_UNKNOWN) { DISPLAYUPDATE_PROGRESS( @@ -1294,13 +1541,12 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no while (1) { int const ret = deflate(&strm, Z_FINISH); - { size_t const cSize = writeJob->bufferSize - strm.avail_out; + { size_t const cSize = (size_t)((uInt)io->outCapacity - strm.avail_out); if (cSize) { - writeJob->usedBufferSize = cSize; - AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); + FIO_SyncCompressIO_commitOut(io, io->outBuffer, cSize); outFileSize += cSize; - strm.next_out = (Bytef*)writeJob->buffer; - strm.avail_out = (uInt)writeJob->bufferSize; + strm.next_out = (Bytef*)io->outBuffer; + strm.avail_out = (uInt)io->outCapacity; } } if (ret == Z_STREAM_END) break; if (ret != Z_BUF_ERROR) @@ -1312,8 +1558,7 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no EXM_THROW(79, "zstd: %s: deflateEnd error %d \n", srcFileName, ret); } } *readsize = inFileSize; - AIO_WritePool_releaseIoJob(writeJob); - AIO_WritePool_sparseWriteEnd(ress->writeCtx); + FIO_SyncCompressIO_finish(io); return outFileSize; } #endif @@ -1325,11 +1570,11 @@ FIO_compressLzmaFrame(cRess_t* ress, const char* srcFileName, U64 const srcFileSize, int compressionLevel, U64* readsize, int plain_lzma) { + FIO_SyncCompressIO* const io = &ress->io; unsigned long long inFileSize = 0, outFileSize = 0; lzma_stream strm = LZMA_STREAM_INIT; lzma_action action = LZMA_RUN; lzma_ret ret; - IOJob_t *writeJob = NULL; if (compressionLevel < 0) compressionLevel = 0; if (compressionLevel > 9) compressionLevel = 9; @@ -1347,37 +1592,35 @@ FIO_compressLzmaFrame(cRess_t* ress, EXM_THROW(83, "zstd: %s: lzma_easy_encoder error %d", srcFileName, ret); } - writeJob =AIO_WritePool_acquireJob(ress->writeCtx); - strm.next_out = (BYTE*)writeJob->buffer; - strm.avail_out = writeJob->bufferSize; + strm.next_out = (BYTE*)io->outBuffer; + strm.avail_out = io->outCapacity; strm.next_in = 0; strm.avail_in = 0; while (1) { if (strm.avail_in == 0) { - size_t const inSize = AIO_ReadPool_fillBuffer(ress->readCtx, ZSTD_CStreamInSize()); - if (ress->readCtx->srcBufferLoaded == 0) action = LZMA_FINISH; - inFileSize += inSize; - strm.next_in = (BYTE const*)ress->readCtx->srcBuffer; - strm.avail_in = ress->readCtx->srcBufferLoaded; + size_t const added = FIO_SyncCompressIO_fillBuffer(io, ZSTD_CStreamInSize()); + if (io->srcBufferLoaded == 0) action = LZMA_FINISH; + inFileSize += added; + *readsize += added; + strm.next_in = (BYTE const*)io->srcBuffer; + strm.avail_in = io->srcBufferLoaded; } { size_t const availBefore = strm.avail_in; ret = lzma_code(&strm, action); - AIO_ReadPool_consumeBytes(ress->readCtx, availBefore - strm.avail_in); + FIO_SyncCompressIO_consumeBytes(io, availBefore - strm.avail_in); } - if (ret != LZMA_OK && ret != LZMA_STREAM_END) EXM_THROW(84, "zstd: %s: lzma_code encoding error %d", srcFileName, ret); - { size_t const compBytes = writeJob->bufferSize - strm.avail_out; + { size_t const compBytes = io->outCapacity - strm.avail_out; if (compBytes) { - writeJob->usedBufferSize = compBytes; - AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); + FIO_SyncCompressIO_commitOut(io, io->outBuffer, compBytes); outFileSize += compBytes; - strm.next_out = (BYTE*)writeJob->buffer; - strm.avail_out = writeJob->bufferSize; + strm.next_out = (BYTE*)io->outBuffer; + strm.avail_out = io->outCapacity; } } if (srcFileSize == UTIL_FILESIZE_UNKNOWN) DISPLAYUPDATE_PROGRESS("\rRead : %u MB ==> %.2f%%", @@ -1393,8 +1636,7 @@ FIO_compressLzmaFrame(cRess_t* ress, lzma_end(&strm); *readsize = inFileSize; - AIO_WritePool_releaseIoJob(writeJob); - AIO_WritePool_sparseWriteEnd(ress->writeCtx); + FIO_SyncCompressIO_finish(io); return outFileSize; } @@ -1415,21 +1657,20 @@ FIO_compressLz4Frame(cRess_t* ress, int compressionLevel, int checksumFlag, U64* readsize) { + FIO_SyncCompressIO* const io = &ress->io; const size_t blockSize = FIO_LZ4_GetBlockSize_FromBlockId(LZ4F_max64KB); unsigned long long inFileSize = 0, outFileSize = 0; LZ4F_preferences_t prefs; LZ4F_compressionContext_t ctx; - IOJob_t* writeJob = AIO_WritePool_acquireJob(ress->writeCtx); - LZ4F_errorCode_t const errorCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); if (LZ4F_isError(errorCode)) EXM_THROW(31, "zstd: failed to create lz4 compression context"); memset(&prefs, 0, sizeof(prefs)); - assert(blockSize <= ress->readCtx->base.jobBufferSize); + assert(blockSize <= io->inCapacity); /* autoflush off to mitigate a bug in lz4<=1.9.3 for compression level 12 */ prefs.autoFlush = 0; @@ -1440,25 +1681,26 @@ FIO_compressLz4Frame(cRess_t* ress, #if LZ4_VERSION_NUMBER >= 10600 prefs.frameInfo.contentSize = (srcFileSize==UTIL_FILESIZE_UNKNOWN) ? 0 : srcFileSize; #endif - assert(LZ4F_compressBound(blockSize, &prefs) <= writeJob->bufferSize); + assert(LZ4F_compressBound(blockSize, &prefs) <= io->outCapacity); { - size_t headerSize = LZ4F_compressBegin(ctx, writeJob->buffer, writeJob->bufferSize, &prefs); + size_t headerSize = LZ4F_compressBegin(ctx, io->outBuffer, io->outCapacity, &prefs); if (LZ4F_isError(headerSize)) EXM_THROW(33, "File header generation failed : %s", LZ4F_getErrorName(headerSize)); - writeJob->usedBufferSize = headerSize; - AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); + FIO_SyncCompressIO_commitOut(io, io->outBuffer, headerSize); outFileSize += headerSize; - /* Read first block */ - inFileSize += AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); + { + size_t const added = FIO_SyncCompressIO_fillBuffer(io, blockSize); + inFileSize += added; + *readsize += added; + } - /* Main Loop */ - while (ress->readCtx->srcBufferLoaded) { - size_t inSize = MIN(blockSize, ress->readCtx->srcBufferLoaded); - size_t const outSize = LZ4F_compressUpdate(ctx, writeJob->buffer, writeJob->bufferSize, - ress->readCtx->srcBuffer, inSize, NULL); + while (io->srcBufferLoaded) { + size_t const inSize = MIN(blockSize, io->srcBufferLoaded); + size_t const outSize = LZ4F_compressUpdate(ctx, io->outBuffer, io->outCapacity, + io->srcBuffer, inSize, NULL); if (LZ4F_isError(outSize)) EXM_THROW(35, "zstd: %s: lz4 compression failed : %s", srcFileName, LZ4F_getErrorName(outSize)); @@ -1473,30 +1715,27 @@ FIO_compressLz4Frame(cRess_t* ress, (double)outFileSize/(double)inFileSize*100); } - /* Write Block */ - writeJob->usedBufferSize = outSize; - AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); + FIO_SyncCompressIO_commitOut(io, io->outBuffer, outSize); - /* Read next block */ - AIO_ReadPool_consumeBytes(ress->readCtx, inSize); - inFileSize += AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); + FIO_SyncCompressIO_consumeBytes(io, inSize); + { + size_t const added = FIO_SyncCompressIO_fillBuffer(io, blockSize); + inFileSize += added; + *readsize += added; + } } - /* End of Stream mark */ - headerSize = LZ4F_compressEnd(ctx, writeJob->buffer, writeJob->bufferSize, NULL); + headerSize = LZ4F_compressEnd(ctx, io->outBuffer, io->outCapacity, NULL); if (LZ4F_isError(headerSize)) EXM_THROW(38, "zstd: %s: lz4 end of file generation failed : %s", srcFileName, LZ4F_getErrorName(headerSize)); - writeJob->usedBufferSize = headerSize; - AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); + FIO_SyncCompressIO_commitOut(io, io->outBuffer, headerSize); outFileSize += headerSize; } - *readsize = inFileSize; LZ4F_freeCompressionContext(ctx); - AIO_WritePool_releaseIoJob(writeJob); - AIO_WritePool_sparseWriteEnd(ress->writeCtx); + FIO_SyncCompressIO_finish(io); return outFileSize; } @@ -1505,12 +1744,11 @@ FIO_compressLz4Frame(cRess_t* ress, static unsigned long long FIO_compressZstdFrame(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs, - const cRess_t* ressPtr, + cRess_t* ress, const char* srcFileName, U64 fileSize, int compressionLevel, U64* readsize) { - cRess_t const ress = *ressPtr; - IOJob_t* writeJob = AIO_WritePool_acquireJob(ressPtr->writeCtx); + FIO_SyncCompressIO* const io = &ress->io; U64 compressedfilesize = 0; ZSTD_EndDirective directive = ZSTD_e_continue; @@ -1535,16 +1773,16 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, /* init */ if (fileSize != UTIL_FILESIZE_UNKNOWN) { pledgedSrcSize = fileSize; - CHECK(ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize)); + CHECK(ZSTD_CCtx_setPledgedSrcSize(ress->cctx, fileSize)); } else if (prefs->streamSrcSize > 0) { /* unknown source size; use the declared stream size */ pledgedSrcSize = prefs->streamSrcSize; - CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, prefs->streamSrcSize) ); + CHECK( ZSTD_CCtx_setPledgedSrcSize(ress->cctx, prefs->streamSrcSize) ); } { int windowLog; UTIL_HumanReadableSize_t windowSize; - CHECK(ZSTD_CCtx_getParameter(ress.cctx, ZSTD_c_windowLog, &windowLog)); + CHECK(ZSTD_CCtx_getParameter(ress->cctx, ZSTD_c_windowLog, &windowLog)); if (windowLog == 0) { if (prefs->ldmFlag) { /* If long mode is set without a window size libzstd will set this size internally */ @@ -1562,12 +1800,12 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, do { size_t stillToFlush; /* Fill input Buffer */ - size_t const inSize = AIO_ReadPool_fillBuffer(ress.readCtx, ZSTD_CStreamInSize()); - ZSTD_inBuffer inBuff = setInBuffer( ress.readCtx->srcBuffer, ress.readCtx->srcBufferLoaded, 0 ); + size_t const inSize = FIO_SyncCompressIO_fillBuffer(io, ZSTD_CStreamInSize()); + ZSTD_inBuffer inBuff = setInBuffer( io->srcBuffer, io->srcBufferLoaded, 0 ); DISPLAYLEVEL(6, "fread %u bytes from source \n", (unsigned)inSize); *readsize += inSize; - if ((ress.readCtx->srcBufferLoaded == 0) || (*readsize == fileSize)) + if ((io->srcBufferLoaded == 0) || (*readsize == fileSize)) directive = ZSTD_e_end; stillToFlush = 1; @@ -1575,10 +1813,10 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, || (directive == ZSTD_e_end && stillToFlush != 0) ) { size_t const oldIPos = inBuff.pos; - ZSTD_outBuffer outBuff = setOutBuffer( writeJob->buffer, writeJob->bufferSize, 0 ); - size_t const toFlushNow = ZSTD_toFlushNow(ress.cctx); - CHECK_V(stillToFlush, ZSTD_compressStream2(ress.cctx, &outBuff, &inBuff, directive)); - AIO_ReadPool_consumeBytes(ress.readCtx, inBuff.pos - oldIPos); + ZSTD_outBuffer outBuff = setOutBuffer( io->outBuffer, io->outCapacity, 0 ); + size_t const toFlushNow = ZSTD_toFlushNow(ress->cctx); + CHECK_V(stillToFlush, ZSTD_compressStream2(ress->cctx, &outBuff, &inBuff, directive)); + FIO_SyncCompressIO_consumeBytes(io, inBuff.pos - oldIPos); /* count stats */ inputPresented++; @@ -1589,14 +1827,13 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, DISPLAYLEVEL(6, "ZSTD_compress_generic(end:%u) => input pos(%u)<=(%u)size ; output generated %u bytes \n", (unsigned)directive, (unsigned)inBuff.pos, (unsigned)inBuff.size, (unsigned)outBuff.pos); if (outBuff.pos) { - writeJob->usedBufferSize = outBuff.pos; - AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); + FIO_SyncCompressIO_commitOut(io, io->outBuffer, outBuff.pos); compressedfilesize += outBuff.pos; } /* adaptive mode : statistics measurement and speed correction */ if (prefs->adaptiveMode && UTIL_clockSpanMicro(lastAdaptTime) > adaptEveryMicro) { - ZSTD_frameProgression const zfp = ZSTD_getFrameProgression(ress.cctx); + ZSTD_frameProgression const zfp = ZSTD_getFrameProgression(ress->cctx); lastAdaptTime = UTIL_getTime(); @@ -1669,14 +1906,14 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, if (compressionLevel > ZSTD_maxCLevel()) compressionLevel = ZSTD_maxCLevel(); if (compressionLevel > prefs->maxAdaptLevel) compressionLevel = prefs->maxAdaptLevel; compressionLevel += (compressionLevel == 0); /* skip 0 */ - ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_compressionLevel, compressionLevel); + ZSTD_CCtx_setParameter(ress->cctx, ZSTD_c_compressionLevel, compressionLevel); } if (speedChange == faster) { DISPLAYLEVEL(6, "faster speed , lighter compression \n") compressionLevel --; if (compressionLevel < prefs->minAdaptLevel) compressionLevel = prefs->minAdaptLevel; compressionLevel -= (compressionLevel == 0); /* skip 0 */ - ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_compressionLevel, compressionLevel); + ZSTD_CCtx_setParameter(ress->cctx, ZSTD_c_compressionLevel, compressionLevel); } speedChange = noChange; @@ -1686,7 +1923,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, /* display notification */ if (SHOULD_DISPLAY_PROGRESS() && READY_FOR_UPDATE()) { - ZSTD_frameProgression const zfp = ZSTD_getFrameProgression(ress.cctx); + ZSTD_frameProgression const zfp = ZSTD_getFrameProgression(ress->cctx); double const cShare = (double)zfp.produced / (double)(zfp.consumed + !zfp.consumed/*avoid div0*/) * 100; UTIL_HumanReadableSize_t const buffered_hrs = UTIL_makeHumanReadableSize(zfp.ingested - zfp.consumed); UTIL_HumanReadableSize_t const consumed_hrs = UTIL_makeHumanReadableSize(zfp.consumed); @@ -1733,8 +1970,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, (unsigned long long)*readsize, (unsigned long long)fileSize); } - AIO_WritePool_releaseIoJob(writeJob); - AIO_WritePool_sparseWriteEnd(ressPtr->writeCtx); + FIO_SyncCompressIO_finish(io); return compressedfilesize; } @@ -1747,7 +1983,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, static int FIO_compressFilename_internal(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs, - cRess_t ress, + cRess_t* ress, const char* dstFileName, const char* srcFileName, int compressionLevel) { @@ -1762,12 +1998,12 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, switch (prefs->compressionType) { default: case FIO_zstdCompression: - compressedfilesize = FIO_compressZstdFrame(fCtx, prefs, &ress, srcFileName, fileSize, compressionLevel, &readsize); + compressedfilesize = FIO_compressZstdFrame(fCtx, prefs, ress, srcFileName, fileSize, compressionLevel, &readsize); break; case FIO_gzipCompression: #ifdef ZSTD_GZCOMPRESS - compressedfilesize = FIO_compressGzFrame(&ress, srcFileName, fileSize, compressionLevel, &readsize); + compressedfilesize = FIO_compressGzFrame(ress, srcFileName, fileSize, compressionLevel, &readsize); #else (void)compressionLevel; EXM_THROW(20, "zstd: %s: file cannot be compressed as gzip (zstd compiled without ZSTD_GZCOMPRESS) -- ignored \n", @@ -1778,7 +2014,7 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, case FIO_xzCompression: case FIO_lzmaCompression: #ifdef ZSTD_LZMACOMPRESS - compressedfilesize = FIO_compressLzmaFrame(&ress, srcFileName, fileSize, compressionLevel, &readsize, prefs->compressionType==FIO_lzmaCompression); + compressedfilesize = FIO_compressLzmaFrame(ress, srcFileName, fileSize, compressionLevel, &readsize, prefs->compressionType==FIO_lzmaCompression); #else (void)compressionLevel; EXM_THROW(20, "zstd: %s: file cannot be compressed as xz/lzma (zstd compiled without ZSTD_LZMACOMPRESS) -- ignored \n", @@ -1788,7 +2024,7 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, case FIO_lz4Compression: #ifdef ZSTD_LZ4COMPRESS - compressedfilesize = FIO_compressLz4Frame(&ress, srcFileName, fileSize, compressionLevel, prefs->checksumFlag, &readsize); + compressedfilesize = FIO_compressLz4Frame(ress, srcFileName, fileSize, compressionLevel, prefs->checksumFlag, &readsize); #else (void)compressionLevel; EXM_THROW(20, "zstd: %s: file cannot be compressed as lz4 (zstd compiled without ZSTD_LZ4COMPRESS) -- ignored \n", @@ -1844,7 +2080,7 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, */ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs, - cRess_t ress, + cRess_t* ress, const char* dstFileName, const char* srcFileName, const stat_t* srcFileStat, @@ -1855,8 +2091,7 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, int transferStat = 0; int dstFd = -1; - assert(AIO_ReadPool_getFile(ress.readCtx) != NULL); - if (AIO_WritePool_getFile(ress.writeCtx) == NULL) { + if (ress->io.dstFile == NULL) { int dstFileInitialPermissions = DEFAULT_FILE_PERMISSIONS; if ( strcmp (srcFileName, stdinmark) && strcmp (dstFileName, stdoutmark) @@ -1867,15 +2102,13 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, closeDstFile = 1; DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: opening dst: %s \n", dstFileName); - { FILE *dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFileInitialPermissions); + { + FILE *dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFileInitialPermissions); if (dstFile==NULL) return 1; /* could not open dstFileName */ dstFd = fileno(dstFile); - AIO_WritePool_setFile(ress.writeCtx, dstFile); + FIO_SyncCompressIO_setDst(&ress->io, dstFile); } - /* Must only be added after FIO_openDstFile() succeeds. - * Otherwise we may delete the destination file if it already exists, - * and the user presses Ctrl-C when asked if they wish to overwrite. - */ + /* Must only be added after FIO_openDstFile() succeeds. */ addHandler(dstFileName); } @@ -1889,7 +2122,7 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, } DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: closing dst: %s \n", dstFileName); - if (AIO_WritePool_closeFile(ress.writeCtx)) { /* error closing file */ + if (FIO_SyncCompressIO_closeDst(&ress->io)) { /* error closing file */ DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno)); result=1; } @@ -1898,10 +2131,9 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, UTIL_utime(dstFileName, srcFileStat); } - if ( (result != 0) /* operation failure */ - && strcmp(dstFileName, stdoutmark) /* special case : don't remove() stdout */ - ) { - FIO_removeFile(dstFileName); /* remove compression artefact; note don't do anything special if remove() fails */ + if ( (result != 0) + && strcmp(dstFileName, stdoutmark) ) { + FIO_removeFile(dstFileName); } } @@ -2035,7 +2267,7 @@ static const char *compressedFileExtensions[] = { static int FIO_compressFilename_srcFile(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs, - cRess_t ress, + cRess_t* ress, const char* dstFileName, const char* srcFileName, int compressionLevel) @@ -2057,7 +2289,7 @@ FIO_compressFilename_srcFile(FIO_ctx_t* const fCtx, } /* ensure src is not the same as dict (if present) */ - if (ress.dictFileName != NULL && UTIL_isSameFileStat(srcFileName, ress.dictFileName, &srcFileStat, &ress.dictFileStat)) { + if (ress->dictFileName != NULL && UTIL_isSameFileStat(srcFileName, ress->dictFileName, &srcFileStat, &ress->dictFileStat)) { DISPLAYLEVEL(1, "zstd: cannot use %s as an input file and dictionary \n", srcFileName); return 1; } @@ -2076,19 +2308,21 @@ FIO_compressFilename_srcFile(FIO_ctx_t* const fCtx, srcFile = FIO_openSrcFile(prefs, srcFileName, &srcFileStat); if (srcFile == NULL) return 1; /* srcFile could not be opened */ - /* AsyncIO is disabled for compression to favor predictable performance and simpler upkeep. */ if (strcmp(srcFileName, stdinmark)) /* Stdin doesn't have stats */ fileSize = UTIL_getFileSizeStat(&srcFileStat); (void)fileSize; - AIO_ReadPool_setAsync(ress.readCtx, 0); - AIO_WritePool_setAsync(ress.writeCtx, 0); - AIO_ReadPool_setFile(ress.readCtx, srcFile); + FIO_SyncCompressIO_setSrc(&ress->io, srcFile); result = FIO_compressFilename_dstFile( fCtx, prefs, ress, dstFileName, srcFileName, &srcFileStat, compressionLevel); - AIO_ReadPool_closeFile(ress.readCtx); + FIO_SyncCompressIO_clearSrc(&ress->io); + + if (srcFile != NULL && fclose(srcFile)) { + DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno)); + return 1; + } if ( prefs->removeSrcFile /* --rm */ && result == 0 /* success */ @@ -2155,7 +2389,7 @@ int FIO_compressFilename(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs, const int compressionLevel, ZSTD_compressionParameters comprParams) { cRess_t ress = FIO_createCResources(prefs, dictFileName, UTIL_getFileSize(srcFileName), compressionLevel, comprParams); - int const result = FIO_compressFilename_srcFile(fCtx, prefs, ress, dstFileName, srcFileName, compressionLevel); + int const result = FIO_compressFilename_srcFile(fCtx, prefs, &ress, dstFileName, srcFileName, compressionLevel); #define DISPLAY_LEVEL_DEFAULT 2 @@ -2252,13 +2486,13 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx, if (dstFile == NULL) { /* could not open outFileName */ error = 1; } else { - AIO_WritePool_setFile(ress.writeCtx, dstFile); + FIO_SyncCompressIO_setDst(&ress.io, dstFile); for (; fCtx->currFileIdx < fCtx->nbFilesTotal; ++fCtx->currFileIdx) { - status = FIO_compressFilename_srcFile(fCtx, prefs, ress, outFileName, inFileNamesTable[fCtx->currFileIdx], compressionLevel); + status = FIO_compressFilename_srcFile(fCtx, prefs, &ress, outFileName, inFileNamesTable[fCtx->currFileIdx], compressionLevel); if (!status) fCtx->nbFilesProcessed++; error |= status; } - if (AIO_WritePool_closeFile(ress.writeCtx)) + if (FIO_SyncCompressIO_closeDst(&ress.io)) EXM_THROW(29, "Write error (%s) : cannot properly close %s", strerror(errno), outFileName); } @@ -2282,7 +2516,7 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx, } else { dstFileName = FIO_determineCompressedName(srcFileName, outDirName, suffix); /* cannot fail */ } - status = FIO_compressFilename_srcFile(fCtx, prefs, ress, dstFileName, srcFileName, compressionLevel); + status = FIO_compressFilename_srcFile(fCtx, prefs, &ress, dstFileName, srcFileName, compressionLevel); if (!status) fCtx->nbFilesProcessed++; error |= status; } From ccadc33a599d61f1a8cbeee7a96cd07a7cc8de24 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 25 Oct 2025 11:11:48 -0700 Subject: [PATCH 183/245] minor: use init/destroy pair naming convention --- programs/fileio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 1e767ee64..a6e361821 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -68,7 +68,7 @@ static void FIO_SyncCompressIO_init(FIO_SyncCompressIO* io, const FIO_prefs_t* prefs, size_t inCapacity, size_t outCapacity); -static void FIO_SyncCompressIO_free(FIO_SyncCompressIO* io); +static void FIO_SyncCompressIO_destroy(FIO_SyncCompressIO* io); static void FIO_SyncCompressIO_setSrc(FIO_SyncCompressIO* io, FILE* file); static void FIO_SyncCompressIO_clearSrc(FIO_SyncCompressIO* io); static void FIO_SyncCompressIO_setDst(FIO_SyncCompressIO* io, FILE* file); @@ -274,7 +274,7 @@ static void FIO_SyncCompressIO_init(FIO_SyncCompressIO* io, io->srcBufferLoaded = 0; } -static void FIO_SyncCompressIO_free(FIO_SyncCompressIO* io) +static void FIO_SyncCompressIO_destroy(FIO_SyncCompressIO* io) { if (!io) return; free(io->inBuffer); @@ -1467,7 +1467,7 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, static void FIO_freeCResources(cRess_t* const ress) { FIO_freeDict(&(ress->dict)); - FIO_SyncCompressIO_free(&ress->io); + FIO_SyncCompressIO_destroy(&ress->io); ZSTD_freeCStream(ress->cctx); /* never fails */ } From 41f2673acda6543c6e8f3780926733439030e797 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 25 Oct 2025 11:23:16 -0700 Subject: [PATCH 184/245] changed name to syncIO for clarity --- programs/fileio.c | 110 +++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index a6e361821..eb489d210 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -50,6 +50,8 @@ UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER; /* ************************************* * Synchronous compression IO helpers +* Lightweight wrapper used by compression paths to manage buffered +* reads/writes without the async job machinery. ***************************************/ typedef struct { const FIO_prefs_t* prefs; @@ -1478,7 +1480,7 @@ FIO_compressGzFrame(cRess_t* ress, const char* srcFileName, U64 const srcFileSize, int compressionLevel, U64* readsize) { - FIO_SyncCompressIO* const io = &ress->io; + FIO_SyncCompressIO* const syncIO = &ress->io; unsigned long long inFileSize = 0, outFileSize = 0; z_stream strm; @@ -1498,34 +1500,34 @@ FIO_compressGzFrame(cRess_t* ress, strm.next_in = 0; strm.avail_in = 0; - strm.next_out = (Bytef*)io->outBuffer; - strm.avail_out = (uInt)io->outCapacity; + strm.next_out = (Bytef*)syncIO->outBuffer; + strm.avail_out = (uInt)syncIO->outCapacity; while (1) { int ret; if (strm.avail_in == 0) { - size_t const added = FIO_SyncCompressIO_fillBuffer(io, ZSTD_CStreamInSize()); - if (io->srcBufferLoaded == 0) break; + size_t const added = FIO_SyncCompressIO_fillBuffer(syncIO, ZSTD_CStreamInSize()); + if (syncIO->srcBufferLoaded == 0) break; inFileSize += added; *readsize += added; - strm.next_in = (z_const unsigned char*)io->srcBuffer; - strm.avail_in = (uInt)io->srcBufferLoaded; + strm.next_in = (z_const unsigned char*)syncIO->srcBuffer; + strm.avail_in = (uInt)syncIO->srcBufferLoaded; } { size_t const availBefore = strm.avail_in; ret = deflate(&strm, Z_NO_FLUSH); - FIO_SyncCompressIO_consumeBytes(io, availBefore - strm.avail_in); + FIO_SyncCompressIO_consumeBytes(syncIO, availBefore - strm.avail_in); } if (ret != Z_OK) EXM_THROW(72, "zstd: %s: deflate error %d \n", srcFileName, ret); - { size_t const cSize = (size_t)((uInt)io->outCapacity - strm.avail_out); + { size_t const cSize = (size_t)((uInt)syncIO->outCapacity - strm.avail_out); if (cSize) { - FIO_SyncCompressIO_commitOut(io, io->outBuffer, cSize); + FIO_SyncCompressIO_commitOut(syncIO, syncIO->outBuffer, cSize); outFileSize += cSize; - strm.next_out = (Bytef*)io->outBuffer; - strm.avail_out = (uInt)io->outCapacity; + strm.next_out = (Bytef*)syncIO->outBuffer; + strm.avail_out = (uInt)syncIO->outCapacity; } } if (srcFileSize == UTIL_FILESIZE_UNKNOWN) { DISPLAYUPDATE_PROGRESS( @@ -1541,12 +1543,12 @@ FIO_compressGzFrame(cRess_t* ress, while (1) { int const ret = deflate(&strm, Z_FINISH); - { size_t const cSize = (size_t)((uInt)io->outCapacity - strm.avail_out); + { size_t const cSize = (size_t)((uInt)syncIO->outCapacity - strm.avail_out); if (cSize) { - FIO_SyncCompressIO_commitOut(io, io->outBuffer, cSize); + FIO_SyncCompressIO_commitOut(syncIO, syncIO->outBuffer, cSize); outFileSize += cSize; - strm.next_out = (Bytef*)io->outBuffer; - strm.avail_out = (uInt)io->outCapacity; + strm.next_out = (Bytef*)syncIO->outBuffer; + strm.avail_out = (uInt)syncIO->outCapacity; } } if (ret == Z_STREAM_END) break; if (ret != Z_BUF_ERROR) @@ -1558,7 +1560,7 @@ FIO_compressGzFrame(cRess_t* ress, EXM_THROW(79, "zstd: %s: deflateEnd error %d \n", srcFileName, ret); } } *readsize = inFileSize; - FIO_SyncCompressIO_finish(io); + FIO_SyncCompressIO_finish(syncIO); return outFileSize; } #endif @@ -1570,7 +1572,7 @@ FIO_compressLzmaFrame(cRess_t* ress, const char* srcFileName, U64 const srcFileSize, int compressionLevel, U64* readsize, int plain_lzma) { - FIO_SyncCompressIO* const io = &ress->io; + FIO_SyncCompressIO* const syncIO = &ress->io; unsigned long long inFileSize = 0, outFileSize = 0; lzma_stream strm = LZMA_STREAM_INIT; lzma_action action = LZMA_RUN; @@ -1592,35 +1594,35 @@ FIO_compressLzmaFrame(cRess_t* ress, EXM_THROW(83, "zstd: %s: lzma_easy_encoder error %d", srcFileName, ret); } - strm.next_out = (BYTE*)io->outBuffer; - strm.avail_out = io->outCapacity; + strm.next_out = (BYTE*)syncIO->outBuffer; + strm.avail_out = syncIO->outCapacity; strm.next_in = 0; strm.avail_in = 0; while (1) { if (strm.avail_in == 0) { - size_t const added = FIO_SyncCompressIO_fillBuffer(io, ZSTD_CStreamInSize()); - if (io->srcBufferLoaded == 0) action = LZMA_FINISH; + size_t const added = FIO_SyncCompressIO_fillBuffer(syncIO, ZSTD_CStreamInSize()); + if (syncIO->srcBufferLoaded == 0) action = LZMA_FINISH; inFileSize += added; *readsize += added; - strm.next_in = (BYTE const*)io->srcBuffer; - strm.avail_in = io->srcBufferLoaded; + strm.next_in = (BYTE const*)syncIO->srcBuffer; + strm.avail_in = syncIO->srcBufferLoaded; } { size_t const availBefore = strm.avail_in; ret = lzma_code(&strm, action); - FIO_SyncCompressIO_consumeBytes(io, availBefore - strm.avail_in); + FIO_SyncCompressIO_consumeBytes(syncIO, availBefore - strm.avail_in); } if (ret != LZMA_OK && ret != LZMA_STREAM_END) EXM_THROW(84, "zstd: %s: lzma_code encoding error %d", srcFileName, ret); - { size_t const compBytes = io->outCapacity - strm.avail_out; + { size_t const compBytes = syncIO->outCapacity - strm.avail_out; if (compBytes) { - FIO_SyncCompressIO_commitOut(io, io->outBuffer, compBytes); + FIO_SyncCompressIO_commitOut(syncIO, syncIO->outBuffer, compBytes); outFileSize += compBytes; - strm.next_out = (BYTE*)io->outBuffer; - strm.avail_out = io->outCapacity; + strm.next_out = (BYTE*)syncIO->outBuffer; + strm.avail_out = syncIO->outCapacity; } } if (srcFileSize == UTIL_FILESIZE_UNKNOWN) DISPLAYUPDATE_PROGRESS("\rRead : %u MB ==> %.2f%%", @@ -1636,7 +1638,7 @@ FIO_compressLzmaFrame(cRess_t* ress, lzma_end(&strm); *readsize = inFileSize; - FIO_SyncCompressIO_finish(io); + FIO_SyncCompressIO_finish(syncIO); return outFileSize; } @@ -1657,7 +1659,7 @@ FIO_compressLz4Frame(cRess_t* ress, int compressionLevel, int checksumFlag, U64* readsize) { - FIO_SyncCompressIO* const io = &ress->io; + FIO_SyncCompressIO* const syncIO = &ress->io; const size_t blockSize = FIO_LZ4_GetBlockSize_FromBlockId(LZ4F_max64KB); unsigned long long inFileSize = 0, outFileSize = 0; @@ -1670,7 +1672,7 @@ FIO_compressLz4Frame(cRess_t* ress, memset(&prefs, 0, sizeof(prefs)); - assert(blockSize <= io->inCapacity); + assert(blockSize <= syncIO->inCapacity); /* autoflush off to mitigate a bug in lz4<=1.9.3 for compression level 12 */ prefs.autoFlush = 0; @@ -1681,26 +1683,26 @@ FIO_compressLz4Frame(cRess_t* ress, #if LZ4_VERSION_NUMBER >= 10600 prefs.frameInfo.contentSize = (srcFileSize==UTIL_FILESIZE_UNKNOWN) ? 0 : srcFileSize; #endif - assert(LZ4F_compressBound(blockSize, &prefs) <= io->outCapacity); + assert(LZ4F_compressBound(blockSize, &prefs) <= syncIO->outCapacity); { - size_t headerSize = LZ4F_compressBegin(ctx, io->outBuffer, io->outCapacity, &prefs); + size_t headerSize = LZ4F_compressBegin(ctx, syncIO->outBuffer, syncIO->outCapacity, &prefs); if (LZ4F_isError(headerSize)) EXM_THROW(33, "File header generation failed : %s", LZ4F_getErrorName(headerSize)); - FIO_SyncCompressIO_commitOut(io, io->outBuffer, headerSize); + FIO_SyncCompressIO_commitOut(syncIO, syncIO->outBuffer, headerSize); outFileSize += headerSize; { - size_t const added = FIO_SyncCompressIO_fillBuffer(io, blockSize); + size_t const added = FIO_SyncCompressIO_fillBuffer(syncIO, blockSize); inFileSize += added; *readsize += added; } - while (io->srcBufferLoaded) { - size_t const inSize = MIN(blockSize, io->srcBufferLoaded); - size_t const outSize = LZ4F_compressUpdate(ctx, io->outBuffer, io->outCapacity, - io->srcBuffer, inSize, NULL); + while (syncIO->srcBufferLoaded) { + size_t const inSize = MIN(blockSize, syncIO->srcBufferLoaded); + size_t const outSize = LZ4F_compressUpdate(ctx, syncIO->outBuffer, syncIO->outCapacity, + syncIO->srcBuffer, inSize, NULL); if (LZ4F_isError(outSize)) EXM_THROW(35, "zstd: %s: lz4 compression failed : %s", srcFileName, LZ4F_getErrorName(outSize)); @@ -1715,27 +1717,27 @@ FIO_compressLz4Frame(cRess_t* ress, (double)outFileSize/(double)inFileSize*100); } - FIO_SyncCompressIO_commitOut(io, io->outBuffer, outSize); + FIO_SyncCompressIO_commitOut(syncIO, syncIO->outBuffer, outSize); - FIO_SyncCompressIO_consumeBytes(io, inSize); + FIO_SyncCompressIO_consumeBytes(syncIO, inSize); { - size_t const added = FIO_SyncCompressIO_fillBuffer(io, blockSize); + size_t const added = FIO_SyncCompressIO_fillBuffer(syncIO, blockSize); inFileSize += added; *readsize += added; } } - headerSize = LZ4F_compressEnd(ctx, io->outBuffer, io->outCapacity, NULL); + headerSize = LZ4F_compressEnd(ctx, syncIO->outBuffer, syncIO->outCapacity, NULL); if (LZ4F_isError(headerSize)) EXM_THROW(38, "zstd: %s: lz4 end of file generation failed : %s", srcFileName, LZ4F_getErrorName(headerSize)); - FIO_SyncCompressIO_commitOut(io, io->outBuffer, headerSize); + FIO_SyncCompressIO_commitOut(syncIO, syncIO->outBuffer, headerSize); outFileSize += headerSize; } LZ4F_freeCompressionContext(ctx); - FIO_SyncCompressIO_finish(io); + FIO_SyncCompressIO_finish(syncIO); return outFileSize; } @@ -1748,7 +1750,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, const char* srcFileName, U64 fileSize, int compressionLevel, U64* readsize) { - FIO_SyncCompressIO* const io = &ress->io; + FIO_SyncCompressIO* const syncIO = &ress->io; U64 compressedfilesize = 0; ZSTD_EndDirective directive = ZSTD_e_continue; @@ -1800,12 +1802,12 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, do { size_t stillToFlush; /* Fill input Buffer */ - size_t const inSize = FIO_SyncCompressIO_fillBuffer(io, ZSTD_CStreamInSize()); - ZSTD_inBuffer inBuff = setInBuffer( io->srcBuffer, io->srcBufferLoaded, 0 ); + size_t const inSize = FIO_SyncCompressIO_fillBuffer(syncIO, ZSTD_CStreamInSize()); + ZSTD_inBuffer inBuff = setInBuffer( syncIO->srcBuffer, syncIO->srcBufferLoaded, 0 ); DISPLAYLEVEL(6, "fread %u bytes from source \n", (unsigned)inSize); *readsize += inSize; - if ((io->srcBufferLoaded == 0) || (*readsize == fileSize)) + if ((syncIO->srcBufferLoaded == 0) || (*readsize == fileSize)) directive = ZSTD_e_end; stillToFlush = 1; @@ -1813,10 +1815,10 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, || (directive == ZSTD_e_end && stillToFlush != 0) ) { size_t const oldIPos = inBuff.pos; - ZSTD_outBuffer outBuff = setOutBuffer( io->outBuffer, io->outCapacity, 0 ); + ZSTD_outBuffer outBuff = setOutBuffer( syncIO->outBuffer, syncIO->outCapacity, 0 ); size_t const toFlushNow = ZSTD_toFlushNow(ress->cctx); CHECK_V(stillToFlush, ZSTD_compressStream2(ress->cctx, &outBuff, &inBuff, directive)); - FIO_SyncCompressIO_consumeBytes(io, inBuff.pos - oldIPos); + FIO_SyncCompressIO_consumeBytes(syncIO, inBuff.pos - oldIPos); /* count stats */ inputPresented++; @@ -1827,7 +1829,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, DISPLAYLEVEL(6, "ZSTD_compress_generic(end:%u) => input pos(%u)<=(%u)size ; output generated %u bytes \n", (unsigned)directive, (unsigned)inBuff.pos, (unsigned)inBuff.size, (unsigned)outBuff.pos); if (outBuff.pos) { - FIO_SyncCompressIO_commitOut(io, io->outBuffer, outBuff.pos); + FIO_SyncCompressIO_commitOut(syncIO, syncIO->outBuffer, outBuff.pos); compressedfilesize += outBuff.pos; } @@ -1970,7 +1972,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, (unsigned long long)*readsize, (unsigned long long)fileSize); } - FIO_SyncCompressIO_finish(io); + FIO_SyncCompressIO_finish(syncIO); return compressedfilesize; } From 7a3c940e7f6df29124f31f7e8c64d4f4dc59786e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 26 Oct 2025 09:48:45 -0700 Subject: [PATCH 185/245] syncio interface only enabled when compression is enabled --- programs/fileio.c | 70 +++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index eb489d210..4000c5b62 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -48,38 +48,6 @@ FIO_display_prefs_t g_display_prefs = {2, FIO_ps_auto}; UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER; -/* ************************************* -* Synchronous compression IO helpers -* Lightweight wrapper used by compression paths to manage buffered -* reads/writes without the async job machinery. -***************************************/ -typedef struct { - const FIO_prefs_t* prefs; - FILE* srcFile; - FILE* dstFile; - unsigned storedSkips; - U8* inBuffer; - size_t inCapacity; - U8* srcBuffer; - size_t srcBufferLoaded; - U8* outBuffer; - size_t outCapacity; -} FIO_SyncCompressIO; - -static void FIO_SyncCompressIO_init(FIO_SyncCompressIO* io, - const FIO_prefs_t* prefs, - size_t inCapacity, - size_t outCapacity); -static void FIO_SyncCompressIO_destroy(FIO_SyncCompressIO* io); -static void FIO_SyncCompressIO_setSrc(FIO_SyncCompressIO* io, FILE* file); -static void FIO_SyncCompressIO_clearSrc(FIO_SyncCompressIO* io); -static void FIO_SyncCompressIO_setDst(FIO_SyncCompressIO* io, FILE* file); -static int FIO_SyncCompressIO_closeDst(FIO_SyncCompressIO* io); -static size_t FIO_SyncCompressIO_fillBuffer(FIO_SyncCompressIO* io, size_t minToHave); -static void FIO_SyncCompressIO_consumeBytes(FIO_SyncCompressIO* io, size_t n); -static void FIO_SyncCompressIO_commitOut(FIO_SyncCompressIO* io, const void* buffer, size_t size); -static void FIO_SyncCompressIO_finish(FIO_SyncCompressIO* io); - #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */ #include "../lib/zstd.h" #include "../lib/zstd_errors.h" /* ZSTD_error_frameParameter_windowTooLarge */ @@ -157,6 +125,42 @@ char const* FIO_lzmaVersion(void) #define TEMPORARY_FILE_PERMISSIONS (0600) #endif + +#ifndef ZSTD_NOCOMPRESS + +/* ************************************* +* Synchronous compression IO helpers +* Lightweight wrapper used by compression paths to manage buffered +* reads/writes without the async job machinery. +***************************************/ +typedef struct { + const FIO_prefs_t* prefs; + FILE* srcFile; + FILE* dstFile; + unsigned storedSkips; + U8* inBuffer; + size_t inCapacity; + U8* srcBuffer; + size_t srcBufferLoaded; + U8* outBuffer; + size_t outCapacity; +} FIO_SyncCompressIO; + +static void FIO_SyncCompressIO_init(FIO_SyncCompressIO* io, + const FIO_prefs_t* prefs, + size_t inCapacity, + size_t outCapacity); +static void FIO_SyncCompressIO_destroy(FIO_SyncCompressIO* io); +static void FIO_SyncCompressIO_setSrc(FIO_SyncCompressIO* io, FILE* file); +static void FIO_SyncCompressIO_clearSrc(FIO_SyncCompressIO* io); +static void FIO_SyncCompressIO_setDst(FIO_SyncCompressIO* io, FILE* file); +static int FIO_SyncCompressIO_closeDst(FIO_SyncCompressIO* io); +static size_t FIO_SyncCompressIO_fillBuffer(FIO_SyncCompressIO* io, size_t minToHave); +static void FIO_SyncCompressIO_consumeBytes(FIO_SyncCompressIO* io, size_t n); +static void FIO_SyncCompressIO_commitOut(FIO_SyncCompressIO* io, const void* buffer, size_t size); +static void FIO_SyncCompressIO_finish(FIO_SyncCompressIO* io); + + static unsigned FIO_sparseWrite(FILE* file, const void* buffer, size_t bufferSize, const FIO_prefs_t* const prefs, @@ -384,6 +388,8 @@ static void FIO_SyncCompressIO_finish(FIO_SyncCompressIO* io) io->storedSkips = 0; } +#endif /* ZSTD_NOCOMPRESS */ + /*-************************************ * Signal (Ctrl-C trapping) **************************************/ From 129769d04c459866697391d0e21f0121a614052d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 05:18:47 +0000 Subject: [PATCH 186/245] Bump actions/upload-artifact from 4 to 5 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/commit.yml | 2 +- .github/workflows/dev-long-tests.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index fe91f2fcc..872e3b734 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -99,6 +99,6 @@ jobs: echo " are still good, copy it into the repo and commit it." echo "> diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv" diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v5 with: path: "/tmp/circleci-artifacts" diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 0450324ee..4b2d2b3f1 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -317,7 +317,7 @@ jobs: dry-run: false sanitizer: ${{ matrix.sanitizer }} - name: Upload Crash - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # tag=v5.0.0 if: failure() && steps.build.outcome == 'success' with: name: ${{ matrix.sanitizer }}-artifacts diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index be14cb5d5..f4d49c218 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -51,7 +51,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # tag=v5.0.0 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index fcc81c395..249ef28b2 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -93,7 +93,7 @@ jobs: mv bin/ zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ - name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip for manual inspection - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # tag=v5.0.0 with: compression-level: 9 # maximum compression if-no-files-found: error # defaults to `warn` From 273ab1bbdf479f68a25290d25e540cd41f9dacf5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 05:08:56 +0000 Subject: [PATCH 187/245] Bump github/codeql-action from 3.30.1 to 4.31.2 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.30.1 to 4.31.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f1f6e5f6af878fb37288ce1c627459e94dbf7d01...0499de31b99561a6d14a36a5f662c2a54f91beee) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.31.2 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index f4d49c218..5fd3b4870 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,6 +59,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # tag=v3.30.1 + uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # tag=v4.31.2 with: sarif_file: results.sarif From 71146f5b6d975d0b6d20426ee14ce28afbfb0d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=B0=9A=E8=AF=9A10330306?= Date: Mon, 3 Nov 2025 16:37:05 +0800 Subject: [PATCH 188/245] Add RISC-V 64-bit architecture detection --- programs/platform.h | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/platform.h b/programs/platform.h index e2cc1c3e6..9f1c968f4 100644 --- a/programs/platform.h +++ b/programs/platform.h @@ -35,6 +35,7 @@ || defined __x86_64__ || defined _M_X64 /* x86 64-bit */ \ || defined __arm64__ || defined __aarch64__ || defined __ARM64_ARCH_8__ /* ARM 64-bit */ \ || (defined __mips && (__mips == 64 || __mips == 4 || __mips == 3)) /* MIPS 64-bit */ \ + || (defined(__riscv) && __riscv_xlen == 64) /* RISC-V 64-bit */ \ || defined _LP64 || defined __LP64__ /* NetBSD, OpenBSD */ || defined __64BIT__ /* AIX */ || defined _ADDR64 /* Cray */ \ || (defined __SIZEOF_POINTER__ && __SIZEOF_POINTER__ == 8) /* gcc */ # if !defined(__64BIT__) From e23477ce3e387279339e68b91ec5feffe432eb3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 05:05:06 +0000 Subject: [PATCH 189/245] Bump actions/checkout from 5.0.0 to 6.0.0 Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.0 to 6.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/android-ndk-build.yml | 2 +- .github/workflows/cmake-tests.yml | 10 +-- .github/workflows/commit.yml | 6 +- .github/workflows/dev-long-tests.yml | 54 ++++++------- .github/workflows/dev-short-tests.yml | 76 +++++++++---------- .github/workflows/nightly.yml | 2 +- .../workflows/publish-release-artifacts.yml | 2 +- .github/workflows/release_check.yml | 4 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 10 files changed, 80 insertions(+), 80 deletions(-) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index 99183049c..23f5601fd 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: Set up JDK 17 uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index 5534cdf89..fd936c130 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -28,7 +28,7 @@ jobs: name: "CMake Root Build" runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: Configure (Root) run: | cmake -S . -B cmake-build -DCMAKE_BUILD_TYPE=Release ${{ env.COMMON_CMAKE_FLAGS }} @@ -43,7 +43,7 @@ jobs: name: "CMake build using make wrapper" runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: Install dependencies run: | sudo apt install liblzma-dev # Required for compression algorithms @@ -73,7 +73,7 @@ jobs: env: SRC_DIR: "source directory with spaces" steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 with: path: "${{ env.SRC_DIR }}" - uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 @@ -131,7 +131,7 @@ jobs: runner: "windows-2022" cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON" steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: Add MSBuild to PATH uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0 - name: "Configure CMake (${{ matrix.name }})" @@ -156,7 +156,7 @@ jobs: name: "CMake macOS ARM64 (Apple Silicon)" runs-on: macos-14 # ARM64 runner steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: "CMake build and test (ARM64)" run: | # Configure and build with ARM64-specific optimizations diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 872e3b734..071b8f94d 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -17,7 +17,7 @@ jobs: image: fbopensource/zstd-circleci-primary:0.0.1 options: --entrypoint /bin/bash steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6.0.0 - name: Install Dependencies run: | sudo apt-get update @@ -40,7 +40,7 @@ jobs: image: fbopensource/zstd-circleci-primary:0.0.1 options: --entrypoint /bin/bash steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6.0.0 - name: Install Dependencies run: | sudo apt-get update @@ -73,7 +73,7 @@ jobs: env: CIRCLE_ARTIFACTS: "/tmp/circleci-artifacts" steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6.0.0 - name: restore_cache uses: actions/cache@v4 with: diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 4b2d2b3f1..f9ad1d975 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -16,7 +16,7 @@ jobs: make-all: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: make all run: make all @@ -27,7 +27,7 @@ jobs: DEVNULLRIGHTS: 1 READFROMBLOCKDEVICE: 1 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: make test run: | make test @@ -38,7 +38,7 @@ jobs: make-test-macos: runs-on: macos-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: make test on macos run: make test @@ -49,7 +49,7 @@ jobs: DEVNULLRIGHTS: 1 READFROMBLOCKDEVICE: 1 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: make test # note: `make -j test success` seems to require a clean state run: | sudo apt-get -qqq update @@ -61,7 +61,7 @@ jobs: test-largeDictionary: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: largeDictionary run: | CFLAGS="-Werror -O3" make -j -C tests test-largeDictionary @@ -70,7 +70,7 @@ jobs: no-intrinsics-fuzztest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: no intrinsics fuzztest run: MOREFLAGS="-DZSTD_NO_INTRINSICS" make -C tests fuzztest @@ -78,14 +78,14 @@ jobs: tsan-zstreamtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: thread sanitizer zstreamtest run: CC=clang ZSTREAM_TESTTIME=-T3mn make tsan-test-zstream uasan-zstreamtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: ub + address sanitizer on zstreamtest run: CC=clang make uasan-test-zstream @@ -93,14 +93,14 @@ jobs: tsan-fuzztest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: thread sanitizer fuzztest run: CC=clang make tsan-fuzztest big-tests-zstreamtest32: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: zstream tests in 32bit mode, with big tests run: | sudo apt-get -qqq update @@ -111,7 +111,7 @@ jobs: gcc-8-asan-ubsan-testzstd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: gcc-8 + ASan + UBSan + Test Zstd # See https://askubuntu.com/a/1428822 run: | @@ -123,14 +123,14 @@ jobs: clang-asan-ubsan-testzstd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # tag=v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 - name: clang + ASan + UBSan + Test Zstd run: CC=clang make -j uasan-test-zstd Date: Tue, 25 Nov 2025 16:38:08 +0100 Subject: [PATCH 190/245] modulemap: remove `config_macros` --- lib/module.modulemap | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/lib/module.modulemap b/lib/module.modulemap index eff98dfac..e66a210d0 100644 --- a/lib/module.modulemap +++ b/lib/module.modulemap @@ -1,27 +1,6 @@ module libzstd [extern_c] { header "zstd.h" export * - config_macros [exhaustive] \ - /* zstd.h */ \ - ZSTD_STATIC_LINKING_ONLY, \ - ZSTDLIB_VISIBILITY, \ - ZSTDLIB_VISIBLE, \ - ZSTDLIB_HIDDEN, \ - ZSTD_DLL_EXPORT, \ - ZSTDLIB_STATIC_API, \ - ZSTD_DISABLE_DEPRECATE_WARNINGS, \ - ZSTD_CLEVEL_DEFAULT, \ - /* zdict.h */ \ - ZDICT_STATIC_LINKING_ONLY, \ - ZDICTLIB_VISIBLE, \ - ZDICTLIB_HIDDEN, \ - ZDICTLIB_VISIBILITY, \ - ZDICTLIB_STATIC_API, \ - ZDICT_DISABLE_DEPRECATE_WARNINGS, \ - /* zstd_errors.h */ \ - ZSTDERRORLIB_VISIBLE, \ - ZSTDERRORLIB_HIDDEN, \ - ZSTDERRORLIB_VISIBILITY module dictbuilder [extern_c] { header "zdict.h" From 757f1bf465ec80fff2b98ee68a63eda6cd4255a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 05:05:30 +0000 Subject: [PATCH 191/245] Bump actions/checkout from 6.0.0 to 6.0.1 Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v6...v6.0.1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/android-ndk-build.yml | 2 +- .github/workflows/cmake-tests.yml | 10 +-- .github/workflows/commit.yml | 6 +- .github/workflows/dev-long-tests.yml | 54 ++++++------- .github/workflows/dev-short-tests.yml | 76 +++++++++---------- .github/workflows/nightly.yml | 2 +- .../workflows/publish-release-artifacts.yml | 2 +- .github/workflows/release_check.yml | 4 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 10 files changed, 80 insertions(+), 80 deletions(-) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index 23f5601fd..826ca5553 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: Set up JDK 17 uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index fd936c130..a293e77cf 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -28,7 +28,7 @@ jobs: name: "CMake Root Build" runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: Configure (Root) run: | cmake -S . -B cmake-build -DCMAKE_BUILD_TYPE=Release ${{ env.COMMON_CMAKE_FLAGS }} @@ -43,7 +43,7 @@ jobs: name: "CMake build using make wrapper" runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: Install dependencies run: | sudo apt install liblzma-dev # Required for compression algorithms @@ -73,7 +73,7 @@ jobs: env: SRC_DIR: "source directory with spaces" steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 with: path: "${{ env.SRC_DIR }}" - uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 @@ -131,7 +131,7 @@ jobs: runner: "windows-2022" cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON" steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: Add MSBuild to PATH uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0 - name: "Configure CMake (${{ matrix.name }})" @@ -156,7 +156,7 @@ jobs: name: "CMake macOS ARM64 (Apple Silicon)" runs-on: macos-14 # ARM64 runner steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: "CMake build and test (ARM64)" run: | # Configure and build with ARM64-specific optimizations diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 071b8f94d..3aeffdf36 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -17,7 +17,7 @@ jobs: image: fbopensource/zstd-circleci-primary:0.0.1 options: --entrypoint /bin/bash steps: - - uses: actions/checkout@v6.0.0 + - uses: actions/checkout@v6.0.1 - name: Install Dependencies run: | sudo apt-get update @@ -40,7 +40,7 @@ jobs: image: fbopensource/zstd-circleci-primary:0.0.1 options: --entrypoint /bin/bash steps: - - uses: actions/checkout@v6.0.0 + - uses: actions/checkout@v6.0.1 - name: Install Dependencies run: | sudo apt-get update @@ -73,7 +73,7 @@ jobs: env: CIRCLE_ARTIFACTS: "/tmp/circleci-artifacts" steps: - - uses: actions/checkout@v6.0.0 + - uses: actions/checkout@v6.0.1 - name: restore_cache uses: actions/cache@v4 with: diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index f9ad1d975..56d42f503 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -16,7 +16,7 @@ jobs: make-all: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: make all run: make all @@ -27,7 +27,7 @@ jobs: DEVNULLRIGHTS: 1 READFROMBLOCKDEVICE: 1 steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: make test run: | make test @@ -38,7 +38,7 @@ jobs: make-test-macos: runs-on: macos-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: make test on macos run: make test @@ -49,7 +49,7 @@ jobs: DEVNULLRIGHTS: 1 READFROMBLOCKDEVICE: 1 steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: make test # note: `make -j test success` seems to require a clean state run: | sudo apt-get -qqq update @@ -61,7 +61,7 @@ jobs: test-largeDictionary: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: largeDictionary run: | CFLAGS="-Werror -O3" make -j -C tests test-largeDictionary @@ -70,7 +70,7 @@ jobs: no-intrinsics-fuzztest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: no intrinsics fuzztest run: MOREFLAGS="-DZSTD_NO_INTRINSICS" make -C tests fuzztest @@ -78,14 +78,14 @@ jobs: tsan-zstreamtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: thread sanitizer zstreamtest run: CC=clang ZSTREAM_TESTTIME=-T3mn make tsan-test-zstream uasan-zstreamtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: ub + address sanitizer on zstreamtest run: CC=clang make uasan-test-zstream @@ -93,14 +93,14 @@ jobs: tsan-fuzztest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: thread sanitizer fuzztest run: CC=clang make tsan-fuzztest big-tests-zstreamtest32: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: zstream tests in 32bit mode, with big tests run: | sudo apt-get -qqq update @@ -111,7 +111,7 @@ jobs: gcc-8-asan-ubsan-testzstd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: gcc-8 + ASan + UBSan + Test Zstd # See https://askubuntu.com/a/1428822 run: | @@ -123,14 +123,14 @@ jobs: clang-asan-ubsan-testzstd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # tag=v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: clang + ASan + UBSan + Test Zstd run: CC=clang make -j uasan-test-zstd Date: Mon, 8 Dec 2025 23:25:45 +0000 Subject: [PATCH 192/245] Bump actions/setup-java from 5.0.0 to 5.1.0 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 5.0.0 to 5.1.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/dded0888837ed1f317902acf8a20df0ad188d165...f2beeb24e141e01a676f977032f5a29d81c9e27e) --- updated-dependencies: - dependency-name: actions/setup-java dependency-version: 5.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/android-ndk-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index 826ca5553..3fc5cd317 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: Set up JDK 17 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 + uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: java-version: '17' distribution: 'temurin' From c7c29693c994114b69842314ef568d618a65aad7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 9 Dec 2025 08:30:24 +0900 Subject: [PATCH 193/245] [ci] update freebsd image --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 745024bc2..13258eded 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -2,7 +2,7 @@ task: name: FreeBSD (make check) freebsd_instance: matrix: - image_family: freebsd-14-2 + image_family: freebsd-16-0-snap install_script: pkg install -y gmake coreutils script: | MOREFLAGS="-Werror" gmake -j all From 1e06c42eece420f6659e635e9283b1419b277012 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 05:04:44 +0000 Subject: [PATCH 194/245] Bump msys2/setup-msys2 from 2.29.0 to 2.30.0 Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.29.0 to 2.30.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/fb197b72ce45fb24f17bf3f807a388985654d1f2...4f806de0a5a7294ffabaff804b38a9b435a73bda) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.30.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dev-long-tests.yml | 2 +- .github/workflows/dev-short-tests.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 56d42f503..ae9f5534e 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -274,7 +274,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # tag=v2.29.0 + - uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # tag=v2.30.0 with: msystem: MINGW64 install: make diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index e5e8d233f..33f7f3d67 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -487,7 +487,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # tag=v2.29.0 + - uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # tag=v2.30.0 with: msystem: ${{ matrix.msystem }} install: make diffutils diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 5f42b05cf..834b834ac 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 # MSYS2 setup - - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # tag=v2.29.0 + - uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # tag=v2.30.0 if: matrix.shell == 'msys2' with: msystem: ${{ matrix.msystem }} From c26db2d0e8fdfabc682241122e509a9be13c42cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 05:04:53 +0000 Subject: [PATCH 195/245] Bump actions/upload-artifact from 5.0.0 to 6.0.0 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5.0.0 to 6.0.0. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/commit.yml | 2 +- .github/workflows/dev-long-tests.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 3aeffdf36..6a278d6cd 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -99,6 +99,6 @@ jobs: echo " are still good, copy it into the repo and commit it." echo "> diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv" diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv - - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v6.0.0 with: path: "/tmp/circleci-artifacts" diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 56d42f503..478d09d8d 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -317,7 +317,7 @@ jobs: dry-run: false sanitizer: ${{ matrix.sanitizer }} - name: Upload Crash - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # tag=v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # tag=v6.0.0 if: failure() && steps.build.outcome == 'success' with: name: ${{ matrix.sanitizer }}-artifacts diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 22fbf0b21..0d635c38d 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -51,7 +51,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # tag=v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # tag=v6.0.0 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 5f42b05cf..cd13dc729 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -93,7 +93,7 @@ jobs: mv bin/ zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ - name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip for manual inspection - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # tag=v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # tag=v6.0.0 with: compression-level: 9 # maximum compression if-no-files-found: error # defaults to `warn` From de9b0810ec8612dac8f3027db6e8fddb1bc61c70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 05:04:57 +0000 Subject: [PATCH 196/245] Bump actions/cache from 4 to 5 Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/commit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 3aeffdf36..4bbfe6b9f 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -75,7 +75,7 @@ jobs: steps: - uses: actions/checkout@v6.0.1 - name: restore_cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: key: regression-cache-{{ checksum "tests/regression/data.c" }}-v0 path: tests/regression/cache From 85c5fa09fd3da5fde6ddd11d79ec8a1bdaeaf6cc Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Dec 2025 09:40:47 -0800 Subject: [PATCH 197/245] changed to freebsd 15 since the image 16 does not seem to work --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 13258eded..b8782ca48 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -2,7 +2,7 @@ task: name: FreeBSD (make check) freebsd_instance: matrix: - image_family: freebsd-16-0-snap + image_family: freebsd-15-0-amd64-zfs install_script: pkg install -y gmake coreutils script: | MOREFLAGS="-Werror" gmake -j all From 38cce02684b5628ff1e3da5e327e565f4293558b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Dec 2025 12:59:14 -0800 Subject: [PATCH 198/245] Makefile: remove support of legacy formats by default can still be changed manually by setting `ZSTD_LEGACY_SUPPORT` to a different value --- lib/libzstd.mk | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/libzstd.mk b/lib/libzstd.mk index d1744973e..60928b0ee 100644 --- a/lib/libzstd.mk +++ b/lib/libzstd.mk @@ -28,12 +28,8 @@ LIB_BINDIR ?= $(LIB_SRCDIR) # configures a bunch of other variables to space-optimized defaults. ZSTD_LIB_MINIFY ?= 0 -# Legacy support -ifneq ($(ZSTD_LIB_MINIFY), 0) - ZSTD_LEGACY_SUPPORT ?= 0 -else - ZSTD_LEGACY_SUPPORT ?= 5 -endif +# Legacy support disabled by default +ZSTD_LEGACY_SUPPORT ?= 0 ZSTD_LEGACY_MULTITHREADED_API ?= 0 # Build size optimizations From b79e86291b306d6372702ed725ac600e6c6e1923 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Dec 2025 13:11:37 -0800 Subject: [PATCH 199/245] [cmake] disable legacy support by default can still be explicitly enabled --- build/cmake/CMakeModules/ZstdOptions.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/cmake/CMakeModules/ZstdOptions.cmake b/build/cmake/CMakeModules/ZstdOptions.cmake index 3fca543a7..dc7813444 100644 --- a/build/cmake/CMakeModules/ZstdOptions.cmake +++ b/build/cmake/CMakeModules/ZstdOptions.cmake @@ -2,8 +2,8 @@ # ZSTD Build Options Configuration # ################################################################ -# Legacy support configuration -option(ZSTD_LEGACY_SUPPORT "Enable legacy format support" ON) +# Legacy support configuration (disabled by default) +option(ZSTD_LEGACY_SUPPORT "Enable legacy format support" OFF) if(ZSTD_LEGACY_SUPPORT) message(STATUS "ZSTD_LEGACY_SUPPORT enabled") From 073c7fb6eaf4d121d3757d83d2433d413fe789ef Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Dec 2025 13:13:56 -0800 Subject: [PATCH 200/245] update dev version number to v1.6.0 to reflect the relatively big scope change by removing support of legacy formats. --- lib/zstd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index 415474d01..97fef316f 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -110,8 +110,8 @@ extern "C" { /*------ Version ------*/ #define ZSTD_VERSION_MAJOR 1 -#define ZSTD_VERSION_MINOR 5 -#define ZSTD_VERSION_RELEASE 8 +#define ZSTD_VERSION_MINOR 6 +#define ZSTD_VERSION_RELEASE 0 #define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) /*! ZSTD_versionNumber() : From 6c3e805e5061b2f800b2664ce7b09d0a4cc34f6f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Dec 2025 13:19:11 -0800 Subject: [PATCH 201/245] doc: legacy support is now disabled by default --- CHANGELOG | 4 ++++ lib/README.md | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 92df0f462..eb46d7118 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +v1.6.0 (Dec 2025) +api: legacy format support is now disabled by default +build: `ZSTD_LEGACY_SUPPORT` defaults to `0` in Makefile and CMake + V1.5.7 (Feb 2025) fix: compression bug in 32-bit mode associated with long-lasting sessions api: new method `ZSTD_compressSequencesAndLiterals()` (#4217, #4232) diff --git a/lib/README.md b/lib/README.md index 3974de160..aa92bd659 100644 --- a/lib/README.md +++ b/lib/README.md @@ -12,8 +12,9 @@ including commands variables, staged install, directory variables and standard t - `make` : generates both static and dynamic libraries - `make install` : install libraries, headers and pkg-config in local system directories -`libzstd` default scope is extensive, including compression, decompression, dictionary builder, -and support for decoding legacy formats >= v0.5.0 by default. +`libzstd` default scope includes compression, decompression, and dictionary builder. +Note: starting v1.6.0, support for decoding legacy formats is disabled by default. +See _modular build_ below to learn how to enable it. The scope can be reduced on demand (see paragraph _modular build_). #### Multiarch Support @@ -99,7 +100,7 @@ The file structure is designed to make this selection manually achievable for an Specifying a number limits versions supported to that version onward. For example, `ZSTD_LEGACY_SUPPORT=2` means : "support legacy formats >= v0.2.0". Conversely, `ZSTD_LEGACY_SUPPORT=0` means "do __not__ support legacy formats". - By default, this build macro is set as `ZSTD_LEGACY_SUPPORT=5`. + By default, this build macro is set as `ZSTD_LEGACY_SUPPORT=0` (disabled). Decoding supported legacy format is a transparent capability triggered within decompression functions. It's also allowed to invoke legacy API directly, exposed in `lib/legacy/zstd_legacy.h`. Each version does also provide its own set of advanced API. From f818f97be64bdbd6989c80ea92b034c1965eadde Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Dec 2025 13:24:02 -0800 Subject: [PATCH 202/245] build: set ZSTD_LEGACY_SUPPORT=0 in remaining build systems Summary: Completes the transition to disabled legacy support by default across all build systems. This follows up on the previous Makefile and CMake changes to ensure consistent default behavior regardless of the build system used. Updated build configurations: Meson, tests/Makefile, Visual Studio 2008/2010 projects, and BUCK. Test Plan: Verified changes compile correctly via `make lib-release`. Build system configurations have been updated consistently across all platforms. --- build/VS2008/zstd/zstd.vcproj | 8 ++++---- build/VS2008/zstdlib/zstdlib.vcproj | 8 ++++---- build/VS2010/libzstd-dll/libzstd-dll.vcxproj | 8 ++++---- build/VS2010/libzstd/libzstd.vcxproj | 8 ++++---- build/VS2010/zstd/zstd.vcxproj | 8 ++++---- build/meson/meson_options.txt | 4 ++-- lib/BUCK | 2 +- tests/Makefile | 2 +- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/build/VS2008/zstd/zstd.vcproj b/build/VS2008/zstd/zstd.vcproj index de1501d20..fc87625a9 100644 --- a/build/VS2008/zstd/zstd.vcproj +++ b/build/VS2008/zstd/zstd.vcproj @@ -45,7 +45,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\lib\compress" - PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -122,7 +122,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\lib\compress" - PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" @@ -197,7 +197,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\lib\compress" - PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -275,7 +275,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\lib\compress" - PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" diff --git a/build/VS2008/zstdlib/zstdlib.vcproj b/build/VS2008/zstdlib/zstdlib.vcproj index 88c1aee26..61c88f5bc 100644 --- a/build/VS2008/zstdlib/zstdlib.vcproj +++ b/build/VS2008/zstdlib/zstdlib.vcproj @@ -45,7 +45,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -121,7 +121,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" @@ -195,7 +195,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -272,7 +272,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" diff --git a/build/VS2010/libzstd-dll/libzstd-dll.vcxproj b/build/VS2010/libzstd-dll/libzstd-dll.vcxproj index 6925e0f9e..ddb8e3216 100644 --- a/build/VS2010/libzstd-dll/libzstd-dll.vcxproj +++ b/build/VS2010/libzstd-dll/libzstd-dll.vcxproj @@ -169,7 +169,7 @@ Level4 Disabled - ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL EditAndContinue @@ -188,7 +188,7 @@ Level4 Disabled - ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL @@ -208,7 +208,7 @@ MaxSpeed true true - ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false MultiThreaded ProgramDatabase @@ -229,7 +229,7 @@ MaxSpeed true true - ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false false MultiThreaded diff --git a/build/VS2010/libzstd/libzstd.vcxproj b/build/VS2010/libzstd/libzstd.vcxproj index 82a2d8268..09ead245a 100644 --- a/build/VS2010/libzstd/libzstd.vcxproj +++ b/build/VS2010/libzstd/libzstd.vcxproj @@ -162,7 +162,7 @@ Level4 Disabled - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL EditAndContinue @@ -181,7 +181,7 @@ Level4 Disabled - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL @@ -201,7 +201,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false MultiThreaded ProgramDatabase @@ -222,7 +222,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false false MultiThreaded diff --git a/build/VS2010/zstd/zstd.vcxproj b/build/VS2010/zstd/zstd.vcxproj index 0558687f5..230fd7d09 100644 --- a/build/VS2010/zstd/zstd.vcxproj +++ b/build/VS2010/zstd/zstd.vcxproj @@ -187,7 +187,7 @@ Level4 Disabled - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true false $(InstructionSet) @@ -204,7 +204,7 @@ Level4 Disabled - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true false $(InstructionSet) @@ -223,7 +223,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) false false MultiThreaded @@ -245,7 +245,7 @@ MaxSpeed true true - ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) false false MultiThreaded diff --git a/build/meson/meson_options.txt b/build/meson/meson_options.txt index 470517827..8d7b8856e 100644 --- a/build/meson/meson_options.txt +++ b/build/meson/meson_options.txt @@ -10,8 +10,8 @@ # Read guidelines from https://wiki.gnome.org/Initiatives/GnomeGoals/MesonPorting -option('legacy_level', type: 'integer', min: 0, max: 7, value: 5, - description: 'Support any legacy format: 7 to 1 for v0.7+ to v0.1+') +option('legacy_level', type: 'integer', min: 0, max: 7, value: 0, + description: 'Support legacy format: 0=disabled, 1-7=support v0.1+ to v0.7+') option('debug_level', type: 'integer', min: 0, max: 9, value: 1, description: 'Enable run-time debug. See lib/common/debug.h') option('backtrace', type: 'feature', value: 'disabled', diff --git a/lib/BUCK b/lib/BUCK index 60c6bbb54..8c555a8be 100644 --- a/lib/BUCK +++ b/lib/BUCK @@ -57,7 +57,7 @@ cxx_library( srcs=glob(['legacy/*.c']), deps=[':common'], exported_preprocessor_flags=[ - '-DZSTD_LEGACY_SUPPORT=4', + '-DZSTD_LEGACY_SUPPORT=0', ], ) diff --git a/tests/Makefile b/tests/Makefile index 643f8cd61..c74c219dc 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -20,7 +20,7 @@ # zstreamtest32: Same as zstreamtest, but forced to compile in 32-bits mode # ########################################################################## -ZSTD_LEGACY_SUPPORT ?= 5 +ZSTD_LEGACY_SUPPORT ?= 0 export ZSTD_LEGACY_SUPPORT DEBUGLEVEL ?= 2 From 8ba2f20a905386bb3524edb95335d101de9f5f66 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Dec 2025 13:39:28 -0800 Subject: [PATCH 203/245] test: update libzstd_builds.sh for disabled legacy default Summary: Updates the library build tests to reflect that legacy format support is now disabled by default. Also adds a new test case to verify that legacy support can still be explicitly enabled via ZSTD_LEGACY_SUPPORT=5. Test Plan: Run `bash tests/libzstd_builds.sh` on a Linux environment. --- tests/libzstd_builds.sh | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/tests/libzstd_builds.sh b/tests/libzstd_builds.sh index f9e1e76c6..3b019c8b8 100755 --- a/tests/libzstd_builds.sh +++ b/tests/libzstd_builds.sh @@ -21,14 +21,14 @@ mustBeAbsent() { $ECHO "$@ correctly not present" # for some reason, this $ECHO must exist, otherwise mustBeAbsent() always fails (??) } -# default compilation : all features enabled - no zbuff +# default compilation : all features enabled - no zbuff, no legacy $ECHO "testing default library compilation" CFLAGS= make -C $DIR/../lib libzstd libzstd.a > $INTOVOID nm $DIR/../lib/libzstd.a | $GREP "\.o" > tmplog isPresent "zstd_compress.o" isPresent "zstd_decompress.o" isPresent "zdict.o" -isPresent "zstd_v07.o" +mustBeAbsent "zstd_v07.o" mustBeAbsent "zbuff_compress.o" $RM tmplog @@ -44,7 +44,7 @@ nm $DIR/../lib/libzstd.a | $GREP "\.o" > tmplog mustBeAbsent "zstd_compress.o" isPresent "zstd_decompress.o" mustBeAbsent "zdict.o" -isPresent "zstd_v07.o" +mustBeAbsent "zstd_v07.o" mustBeAbsent "zbuff_compress.o" $RM $DIR/../lib/libzstd.a tmplog @@ -66,7 +66,7 @@ nm $DIR/../lib/libzstd.a | $GREP "\.o" > tmplog isPresent "zstd_compress.o" isPresent "zstd_decompress.o" isPresent "zdict.o" -isPresent "zstd_v07.o" +mustBeAbsent "zstd_v07.o" mustBeAbsent "zbuff_compress.o" $RM $DIR/../lib/libzstd.a tmplog @@ -77,7 +77,7 @@ nm $DIR/../lib/libzstd.a | $GREP "\.o" > tmplog isPresent "zstd_compress.o" isPresent "zstd_decompress.o" isPresent "zdict.o" -isPresent "zstd_v07.o" +mustBeAbsent "zstd_v07.o" isPresent "zbuff_compress.o" $RM $DIR/../lib/libzstd.a tmplog @@ -88,7 +88,7 @@ nm $DIR/../lib/libzstd.a | $GREP "\.o" > tmplog isPresent "zstd_compress.o" isPresent "zstd_decompress.o" mustBeAbsent "zdict.o" -isPresent "zstd_v07.o" +mustBeAbsent "zstd_v07.o" mustBeAbsent "zbuff_compress.o" $RM $DIR/../lib/libzstd.a tmplog @@ -102,3 +102,14 @@ mustBeAbsent "zdict.o" mustBeAbsent "zstd_v07.o" mustBeAbsent "zbuff_compress.o" $RM $DIR/../lib/libzstd.a tmplog + +# legacy support explicitly enabled +$ECHO "testing with legacy support explicitly enabled" +ZSTD_LEGACY_SUPPORT=5 CFLAGS= make -C $DIR/../lib libzstd.a > $INTOVOID +nm $DIR/../lib/libzstd.a | $GREP "\.o" > tmplog +isPresent "zstd_compress.o" +isPresent "zstd_decompress.o" +isPresent "zdict.o" +isPresent "zstd_v07.o" +mustBeAbsent "zbuff_compress.o" +$RM $DIR/../lib/libzstd.a tmplog From a87d0cc476e4947ccaa5531734f7afd1c49ef766 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Dec 2025 13:50:56 -0800 Subject: [PATCH 204/245] test: enable legacy support in version compatibility test Summary: The version compatibility test needs to decode legacy frames (v0.5.x - v0.7.x) to verify cross-version interoperability. Since legacy support is now disabled by default (v1.6.0), head must be built with ZSTD_LEGACY_SUPPORT=5 for this test. Test Plan: Run `python3 tests/test-zstd-versions.py` to verify cross-version compatibility testing works correctly. --- tests/test-zstd-versions.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test-zstd-versions.py b/tests/test-zstd-versions.py index 1bcf39e2b..703faa478 100755 --- a/tests/test-zstd-versions.py +++ b/tests/test-zstd-versions.py @@ -259,13 +259,16 @@ if __name__ == '__main__': shutil.copy2('dictBuilder', '{}/dictBuilder.{}'.format(tmp_dir, tag)) os.chdir(r_dir + '/programs') # /path/to/zstd/tests/versionsTest//programs make(['clean'], False) # separate 'clean' target to allow parallel build - make(['zstd'], False) + # Enable legacy support for cross-version compatibility testing + make(['zstd', 'ZSTD_LEGACY_SUPPORT=5'], False) else: os.chdir(programs_dir) print('-----------------------------------------------') print('compiling head') print('-----------------------------------------------') - make(['zstd'], False) + # Enable legacy support for head to test cross-version compatibility + # (legacy support is disabled by default since v1.6.0) + make(['zstd', 'ZSTD_LEGACY_SUPPORT=5'], False) shutil.copy2('zstd', dst_zstd) # remove any remaining *.zst and *.dec from previous test From 3a3c506b5168966fb6b350073dbb1866d67cbf78 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Dec 2025 15:52:11 -0800 Subject: [PATCH 205/245] Fix #4553 This is a bug in the streaming implementation of the v0.5 decoder. The bug has always been there. It requires an uncommon block configuration, which wasn't tested at the time. v0.5 is deprecated now, latest version to produce such format is v0.5.1 from February 2016. It was superceded in April 2016. So it's both short lived and very old. Another PR will remove support of this format, but it will still be possible to explicitely request this support on demand, so better fix the issue. --- lib/legacy/zstd_v05.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/legacy/zstd_v05.c b/lib/legacy/zstd_v05.c index e1efca597..ee180487e 100644 --- a/lib/legacy/zstd_v05.c +++ b/lib/legacy/zstd_v05.c @@ -3972,8 +3972,15 @@ size_t ZBUFFv05_decompressContinue(ZBUFFv05_DCtx* zbc, void* dst, size_t* maxDst zbc->outStart += flushedSize; if (flushedSize == toFlushSize) { zbc->stage = ZBUFFv05ds_read; - if (zbc->outStart + BLOCKSIZE > zbc->outBuffSize) - zbc->outStart = zbc->outEnd = 0; + if (zbc->outStart + BLOCKSIZE > zbc->outBuffSize) { + /* Not enough room for next block - need to wrap buffer. + * Preserve history: copy the last windowSize bytes to the + * beginning so that back-references can still find valid data. */ + size_t const windowSize = (size_t)1 << zbc->params.windowLog; + size_t const preserveSize = MIN(zbc->outEnd, windowSize); + memmove(zbc->outBuff, zbc->outBuff + zbc->outEnd - preserveSize, preserveSize); + zbc->outStart = zbc->outEnd = preserveSize; + } break; } /* cannot flush everything */ From 1dae4f0188daff25cfef78de72627e7299a01b86 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 18 Dec 2025 15:36:07 -0800 Subject: [PATCH 206/245] test: fix versionsTest build for old zstd versions Summary: Some old zstd versions (notably v0.6.x) have a bug in fileio.c where header includes check for `ZSTD_LEGACY_SUPPORT==1` but code usage checks for `ZSTD_LEGACY_SUPPORT>=1`. Using value 5 causes compilation failure because headers aren't included but the code tries to use legacy functions. Changing to `ZSTD_LEGACY_SUPPORT=1` for old version builds fixes the compilation while still enabling legacy format support. Test Plan: Run `make versionsTest` or `python3 tests/test-zstd-versions.py` to verify all old versions compile and cross-version decompression works correctly. --- tests/test-zstd-versions.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/test-zstd-versions.py b/tests/test-zstd-versions.py index 703faa478..57131c243 100755 --- a/tests/test-zstd-versions.py +++ b/tests/test-zstd-versions.py @@ -259,8 +259,15 @@ if __name__ == '__main__': shutil.copy2('dictBuilder', '{}/dictBuilder.{}'.format(tmp_dir, tag)) os.chdir(r_dir + '/programs') # /path/to/zstd/tests/versionsTest//programs make(['clean'], False) # separate 'clean' target to allow parallel build - # Enable legacy support for cross-version compatibility testing - make(['zstd', 'ZSTD_LEGACY_SUPPORT=5'], False) + # Enable legacy support for cross-version compatibility testing. + # Use ZSTD_LEGACY_SUPPORT=1 for v0.6.x due to a bug where headers + # check for ==1 but code checks for >=1. + # Use ZSTD_LEGACY_SUPPORT=5 for v1.2.0+ because =1 includes old + # legacy files (v01-v04) that have missing includes in newer versions. + if tag < 'v1.2.0': + make(['zstd', 'ZSTD_LEGACY_SUPPORT=1'], False) + else: + make(['zstd', 'ZSTD_LEGACY_SUPPORT=5'], False) else: os.chdir(programs_dir) print('-----------------------------------------------') From a8319c39de9aa0ee945b866d0b77e8f5cadea81f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 05:50:49 +0000 Subject: [PATCH 207/245] Bump actions/setup-java from 5.1.0 to 5.2.0 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 5.1.0 to 5.2.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/f2beeb24e141e01a676f977032f5a29d81c9e27e...be666c2fcd27ec809703dec50e508c2fdc7f6654) --- updated-dependencies: - dependency-name: actions/setup-java dependency-version: 5.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/android-ndk-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index 3fc5cd317..c9d099126 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 - name: Set up JDK 17 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: java-version: '17' distribution: 'temurin' From a46bec0fbae26383f10ab564a09cbe4e23509f81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 05:51:10 +0000 Subject: [PATCH 208/245] Bump actions/checkout from 6.0.1 to 6.0.2 Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v6.0.1...v6.0.2) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/android-ndk-build.yml | 2 +- .github/workflows/cmake-tests.yml | 10 +-- .github/workflows/commit.yml | 6 +- .github/workflows/dev-long-tests.yml | 54 ++++++------- .github/workflows/dev-short-tests.yml | 76 +++++++++---------- .github/workflows/nightly.yml | 2 +- .../workflows/publish-release-artifacts.yml | 2 +- .github/workflows/release_check.yml | 4 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 10 files changed, 80 insertions(+), 80 deletions(-) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index 3fc5cd317..69dd551a5 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: Set up JDK 17 uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index a293e77cf..3660dcbcf 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -28,7 +28,7 @@ jobs: name: "CMake Root Build" runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: Configure (Root) run: | cmake -S . -B cmake-build -DCMAKE_BUILD_TYPE=Release ${{ env.COMMON_CMAKE_FLAGS }} @@ -43,7 +43,7 @@ jobs: name: "CMake build using make wrapper" runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: Install dependencies run: | sudo apt install liblzma-dev # Required for compression algorithms @@ -73,7 +73,7 @@ jobs: env: SRC_DIR: "source directory with spaces" steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 with: path: "${{ env.SRC_DIR }}" - uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 @@ -131,7 +131,7 @@ jobs: runner: "windows-2022" cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON" steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: Add MSBuild to PATH uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0 - name: "Configure CMake (${{ matrix.name }})" @@ -156,7 +156,7 @@ jobs: name: "CMake macOS ARM64 (Apple Silicon)" runs-on: macos-14 # ARM64 runner steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: "CMake build and test (ARM64)" run: | # Configure and build with ARM64-specific optimizations diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 98345206a..2dbbcc4a0 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -17,7 +17,7 @@ jobs: image: fbopensource/zstd-circleci-primary:0.0.1 options: --entrypoint /bin/bash steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v6.0.2 - name: Install Dependencies run: | sudo apt-get update @@ -40,7 +40,7 @@ jobs: image: fbopensource/zstd-circleci-primary:0.0.1 options: --entrypoint /bin/bash steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v6.0.2 - name: Install Dependencies run: | sudo apt-get update @@ -73,7 +73,7 @@ jobs: env: CIRCLE_ARTIFACTS: "/tmp/circleci-artifacts" steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v6.0.2 - name: restore_cache uses: actions/cache@v5 with: diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index c606b3d45..dc4155f5a 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -16,7 +16,7 @@ jobs: make-all: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: make all run: make all @@ -27,7 +27,7 @@ jobs: DEVNULLRIGHTS: 1 READFROMBLOCKDEVICE: 1 steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: make test run: | make test @@ -38,7 +38,7 @@ jobs: make-test-macos: runs-on: macos-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: make test on macos run: make test @@ -49,7 +49,7 @@ jobs: DEVNULLRIGHTS: 1 READFROMBLOCKDEVICE: 1 steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: make test # note: `make -j test success` seems to require a clean state run: | sudo apt-get -qqq update @@ -61,7 +61,7 @@ jobs: test-largeDictionary: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: largeDictionary run: | CFLAGS="-Werror -O3" make -j -C tests test-largeDictionary @@ -70,7 +70,7 @@ jobs: no-intrinsics-fuzztest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: no intrinsics fuzztest run: MOREFLAGS="-DZSTD_NO_INTRINSICS" make -C tests fuzztest @@ -78,14 +78,14 @@ jobs: tsan-zstreamtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: thread sanitizer zstreamtest run: CC=clang ZSTREAM_TESTTIME=-T3mn make tsan-test-zstream uasan-zstreamtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: ub + address sanitizer on zstreamtest run: CC=clang make uasan-test-zstream @@ -93,14 +93,14 @@ jobs: tsan-fuzztest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: thread sanitizer fuzztest run: CC=clang make tsan-fuzztest big-tests-zstreamtest32: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: zstream tests in 32bit mode, with big tests run: | sudo apt-get -qqq update @@ -111,7 +111,7 @@ jobs: gcc-8-asan-ubsan-testzstd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: gcc-8 + ASan + UBSan + Test Zstd # See https://askubuntu.com/a/1428822 run: | @@ -123,14 +123,14 @@ jobs: clang-asan-ubsan-testzstd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: clang + ASan + UBSan + Test Zstd run: CC=clang make -j uasan-test-zstd Date: Mon, 26 Jan 2026 09:01:27 -0800 Subject: [PATCH 209/245] extend dependabot period to monthly --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5ace4600a..8ac6b8c49 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,4 +3,4 @@ updates: - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "weekly" + interval: "monthly" From a90d7e7689a4468e36247c8afe7c2643ad5c57a2 Mon Sep 17 00:00:00 2001 From: Briar Campbell Date: Thu, 5 Feb 2026 18:26:50 -0600 Subject: [PATCH 210/245] Fix formatting of lz4 option in README --- programs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/README.md b/programs/README.md index 2c2e94dc6..2a6978ac4 100644 --- a/programs/README.md +++ b/programs/README.md @@ -224,7 +224,7 @@ Advanced compression options: --format=gzip Compress files to the `.gz` format. --format=xz Compress files to the `.xz` format. --format=lzma Compress files to the `.lzma` format. - --format=lz4 Compress files to the `.lz4` format. + --format=lz4 Compress files to the `.lz4` format. Advanced decompression options: -l Print information about Zstandard-compressed files. From 117b0edfaee4d1a4af98a3074ea3b23833d47877 Mon Sep 17 00:00:00 2001 From: Briar Campbell Date: Thu, 5 Feb 2026 18:29:07 -0600 Subject: [PATCH 211/245] Fix formatting of lz4 option in zstdcli.c --- programs/zstdcli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 01760ff8c..34db7bf51 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -264,7 +264,7 @@ static void usageAdvanced(const char* programName) DISPLAYOUT(" --format=lzma Compress files to the `.lzma` format.\n"); #endif #ifdef ZSTD_LZ4COMPRESS - DISPLAYOUT( " --format=lz4 Compress files to the `.lz4` format.\n"); + DISPLAYOUT( " --format=lz4 Compress files to the `.lz4` format.\n"); #endif #endif /* !ZSTD_NOCOMPRESS */ From 81cf153bce7c0ab41aeef574a70e32eaea7a8ba7 Mon Sep 17 00:00:00 2001 From: Cody <166262726+kowirth@users.noreply.github.com> Date: Thu, 19 Feb 2026 13:36:12 -0500 Subject: [PATCH 212/245] fix: adjust LDM params in estimate functions to prevent SIGFPE (issue #4590) --- lib/compress/zstd_compress.c | 12 ++++++++++-- tests/fuzzer.c | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 1d6f0fcae..c06f2e1bb 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -1771,15 +1771,19 @@ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) { ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + ldmParams_t ldmParams = params->ldmParams; ZSTD_ParamSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, &cParams); RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); + if (ldmParams.enableLdm == ZSTD_ps_enable) { + ZSTD_ldm_adjustParameters(&ldmParams, &cParams); + } /* estimateCCtxSize is for one-shot compression. So no buffers should * be needed. However, we still allocate two 0-sized buffers, which can * take space under ASAN. */ return ZSTD_estimateCCtxSize_usingCCtxParams_internal( - &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize); + &cParams, &ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize); } size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) @@ -1829,6 +1833,7 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); { ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + ldmParams_t ldmParams = params->ldmParams; size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(params->maxBlockSize), (size_t)1 << cParams.windowLog); size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered) ? ((size_t)1 << cParams.windowLog) + blockSize @@ -1838,8 +1843,11 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) : 0; ZSTD_ParamSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, ¶ms->cParams); + if (ldmParams.enableLdm == ZSTD_ps_enable) { + ZSTD_ldm_adjustParameters(&ldmParams, &cParams); + } return ZSTD_estimateCCtxSize_usingCCtxParams_internal( - &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize, + &cParams, &ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize, ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize); } } diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 0bc160efa..472f8c8b3 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -2515,6 +2515,25 @@ static int basicUnitTests(U32 const seed, double compressibility) } } DISPLAYLEVEL(3, "OK \n"); + + DISPLAYLEVEL(3, "test%3i : estimation functions with LDM enabled (issue #4590) : ", testNb++); + { + /* ZSTD_estimateCCtxSize_usingCCtxParams must adjust zeroed-out + * LDM parameters when LDM is enabled, to avoid division by zero + * in ZSTD_ldm_getMaxNbSeq. */ + ZSTD_CCtx_params* params = ZSTD_createCCtxParams(); + size_t cctxSize; + CHECK_Z(ZSTD_CCtxParams_setParameter(params, ZSTD_c_compressionLevel, 22)); + CHECK_Z(ZSTD_CCtxParams_setParameter(params, ZSTD_c_enableLongDistanceMatching, ZSTD_ps_enable)); + cctxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params); + if (ZSTD_isError(cctxSize)) goto _output_error; + if (cctxSize == 0) goto _output_error; + cctxSize = ZSTD_estimateCStreamSize_usingCCtxParams(params); + if (ZSTD_isError(cctxSize)) goto _output_error; + if (cctxSize == 0) goto _output_error; + ZSTD_freeCCtxParams(params); + } + DISPLAYLEVEL(3, "OK \n"); } free(staticCCtxBuffer); free(staticDCtxBuffer); From bce1ec6b0703c1b91c68daa13c763f46bf8d5199 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Fri, 16 Jan 2026 14:50:06 +0100 Subject: [PATCH 213/245] Make explicit ptrdiff_t to int casts in divsufsort.c to avoid compiler warnings. --- lib/dictBuilder/divsufsort.c | 154 +++++++++++++++++------------------ 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/lib/dictBuilder/divsufsort.c b/lib/dictBuilder/divsufsort.c index e5b117b29..b59781f01 100644 --- a/lib/dictBuilder/divsufsort.c +++ b/lib/dictBuilder/divsufsort.c @@ -25,23 +25,22 @@ */ /*- Compiler specifics -*/ -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wshorten-64-to-32" -#endif - #if defined(_MSC_VER) -# pragma warning(disable : 4244) # pragma warning(disable : 4127) /* C4127 : Condition expression is constant */ #endif /*- Dependencies -*/ #include +#include +#include #include #include #include "divsufsort.h" +#define PTRDIFF_TO_INT(x) (assert((x) <= INT_MAX && (x) >= INT_MIN), (int)(x)) + /*- Constants -*/ #if defined(INLINE) # undef INLINE @@ -354,7 +353,7 @@ ss_pivot(const unsigned char *Td, const int *PA, int *first, int *last) { int *middle; int t; - t = last - first; + t = PTRDIFF_TO_INT(last - first); middle = first + t / 2; if(t <= 512) { @@ -409,7 +408,7 @@ ss_mintrosort(const unsigned char *T, const int *PA, int limit; int v, x = 0; - for(ssize = 0, limit = ss_ilg(last - first);;) { + for(ssize = 0, limit = ss_ilg(PTRDIFF_TO_INT(last - first));;) { if((last - first) <= SS_INSERTIONSORT_THRESHOLD) { #if 1 < SS_INSERTIONSORT_THRESHOLD @@ -420,7 +419,7 @@ ss_mintrosort(const unsigned char *T, const int *PA, } Td = T + depth; - if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); } + if(limit-- == 0) { ss_heapsort(Td, PA, first, PTRDIFF_TO_INT(last - first)); } if(limit < 0) { for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) { if((x = Td[PA[*a]]) != v) { @@ -435,16 +434,16 @@ ss_mintrosort(const unsigned char *T, const int *PA, if((a - first) <= (last - a)) { if(1 < (a - first)) { STACK_PUSH(a, last, depth, -1); - last = a, depth += 1, limit = ss_ilg(a - first); + last = a, depth += 1, limit = ss_ilg(PTRDIFF_TO_INT(a - first)); } else { first = a, limit = -1; } } else { if(1 < (last - a)) { - STACK_PUSH(first, a, depth + 1, ss_ilg(a - first)); + STACK_PUSH(first, a, depth + 1, ss_ilg(PTRDIFF_TO_INT(a - first))); first = a, limit = -1; } else { - last = a, depth += 1, limit = ss_ilg(a - first); + last = a, depth += 1, limit = ss_ilg(PTRDIFF_TO_INT(a - first)); } } continue; @@ -481,9 +480,9 @@ ss_mintrosort(const unsigned char *T, const int *PA, if(a <= d) { c = b - 1; - if((s = a - first) > (t = b - a)) { s = t; } + if((s = PTRDIFF_TO_INT(a - first)) > (t = PTRDIFF_TO_INT(b - a))) { s = t; } for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } - if((s = d - c) > (t = last - d - 1)) { s = t; } + if((s = PTRDIFF_TO_INT(d - c)) > (t = PTRDIFF_TO_INT(last - d - 1))) { s = t; } for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } a = first + (b - a), c = last - (d - c); @@ -491,38 +490,38 @@ ss_mintrosort(const unsigned char *T, const int *PA, if((a - first) <= (last - c)) { if((last - c) <= (c - b)) { - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + STACK_PUSH(b, c, depth + 1, ss_ilg(PTRDIFF_TO_INT(c - b))); STACK_PUSH(c, last, depth, limit); last = a; } else if((a - first) <= (c - b)) { STACK_PUSH(c, last, depth, limit); - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + STACK_PUSH(b, c, depth + 1, ss_ilg(PTRDIFF_TO_INT(c - b))); last = a; } else { STACK_PUSH(c, last, depth, limit); STACK_PUSH(first, a, depth, limit); - first = b, last = c, depth += 1, limit = ss_ilg(c - b); + first = b, last = c, depth += 1, limit = ss_ilg(PTRDIFF_TO_INT(c - b)); } } else { if((a - first) <= (c - b)) { - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + STACK_PUSH(b, c, depth + 1, ss_ilg(PTRDIFF_TO_INT(c - b))); STACK_PUSH(first, a, depth, limit); first = c; } else if((last - c) <= (c - b)) { STACK_PUSH(first, a, depth, limit); - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + STACK_PUSH(b, c, depth + 1, ss_ilg(PTRDIFF_TO_INT(c - b))); first = c; } else { STACK_PUSH(first, a, depth, limit); STACK_PUSH(c, last, depth, limit); - first = b, last = c, depth += 1, limit = ss_ilg(c - b); + first = b, last = c, depth += 1, limit = ss_ilg(PTRDIFF_TO_INT(c - b)); } } } else { limit += 1; if(Td[PA[*first] - 1] < v) { first = ss_partition(PA, first, last, depth); - limit = ss_ilg(last - first); + limit = ss_ilg(PTRDIFF_TO_INT(last - first)); } depth += 1; } @@ -551,7 +550,8 @@ void ss_rotate(int *first, int *middle, int *last) { int *a, *b, t; int l, r; - l = middle - first, r = last - middle; + l = PTRDIFF_TO_INT(middle - first); + r = PTRDIFF_TO_INT(last - middle); for(; (0 < l) && (0 < r);) { if(l == r) { ss_blockswap(first, middle, l); break; } if(l < r) { @@ -601,7 +601,7 @@ ss_inplacemerge(const unsigned char *T, const int *PA, for(;;) { if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); } else { x = 0; p = PA + *(last - 1); } - for(a = first, len = middle - first, half = len >> 1, r = -1; + for(a = first, len = PTRDIFF_TO_INT(middle - first), half = len >> 1, r = -1; 0 < len; len = half, half >>= 1) { b = a + half; @@ -640,7 +640,7 @@ ss_mergeforward(const unsigned char *T, const int *PA, int r; bufend = buf + (middle - first) - 1; - ss_blockswap(buf, first, middle - first); + ss_blockswap(buf, first, PTRDIFF_TO_INT(middle - first)); for(t = *(a = first), b = buf, c = middle;;) { r = ss_compare(T, PA + *b, PA + *c, depth); @@ -692,7 +692,7 @@ ss_mergebackward(const unsigned char *T, const int *PA, int x; bufend = buf + (last - middle) - 1; - ss_blockswap(buf, middle, last - middle); + ss_blockswap(buf, middle, PTRDIFF_TO_INT(last - middle)); x = 0; if(*bufend < 0) { p1 = PA + ~*bufend; x |= 1; } @@ -781,7 +781,7 @@ ss_swapmerge(const unsigned char *T, const int *PA, continue; } - for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1; + for(m = 0, len = PTRDIFF_TO_INT(MIN(middle - first, last - middle)), half = len >> 1; 0 < len; len = half, half >>= 1) { if(ss_compare(T, PA + GETIDX(*(middle + m + half)), @@ -850,8 +850,8 @@ sssort(const unsigned char *T, const int *PA, ss_mintrosort(T, PA, first, last, depth); #else if((bufsize < SS_BLOCKSIZE) && - (bufsize < (last - first)) && - (bufsize < (limit = ss_isqrt(last - first)))) { + (bufsize < PTRDIFF_TO_INT(last - first)) && + (bufsize < (limit = ss_isqrt(PTRDIFF_TO_INT(last - first))))) { if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; } buf = middle = last - limit, bufsize = limit; } else { @@ -863,7 +863,7 @@ sssort(const unsigned char *T, const int *PA, #elif 1 < SS_BLOCKSIZE ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth); #endif - curbufsize = last - (a + SS_BLOCKSIZE); + curbufsize = PTRDIFF_TO_INT(last - (a + SS_BLOCKSIZE)); curbuf = a + SS_BLOCKSIZE; if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; } for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) { @@ -909,8 +909,8 @@ sssort(const unsigned char *T, const int *PA, static INLINE int tr_ilg(int n) { - return ((unsigned)n & 0xffff0000) ? - (((unsigned)n & 0xff000000) ? + return (n & 0xffff0000) ? + ((n & 0xff000000) ? 24 + lg_table[(n >> 24) & 0xff] : 16 + lg_table[(n >> 16) & 0xff]) : ((n & 0x0000ff00) ? @@ -1016,7 +1016,7 @@ tr_pivot(const int *ISAd, int *first, int *last) { int *middle; int t; - t = last - first; + t = PTRDIFF_TO_INT(last - first); middle = first + t / 2; if(t <= 512) { @@ -1098,9 +1098,9 @@ tr_partition(const int *ISAd, if(a <= d) { c = b - 1; - if((s = a - first) > (t = b - a)) { s = t; } + if((s = PTRDIFF_TO_INT(a - first)) > (t = PTRDIFF_TO_INT(b - a))) { s = t; } for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } - if((s = d - c) > (t = last - d - 1)) { s = t; } + if((s = PTRDIFF_TO_INT(d - c)) > (t = PTRDIFF_TO_INT(last - d - 1))) { s = t; } for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } first += (b - a), last -= (d - c); } @@ -1117,17 +1117,17 @@ tr_copy(int *ISA, const int *SA, int *c, *d, *e; int s, v; - v = b - SA - 1; + v = PTRDIFF_TO_INT(b - SA - 1); for(c = first, d = a - 1; c <= d; ++c) { if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *++d = s; - ISA[s] = d - SA; + ISA[s] = PTRDIFF_TO_INT(d - SA); } } for(c = last - 1, e = d + 1, d = b; e < d; --c) { if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *--d = s; - ISA[s] = d - SA; + ISA[s] = PTRDIFF_TO_INT(d - SA); } } } @@ -1141,13 +1141,13 @@ tr_partialcopy(int *ISA, const int *SA, int s, v; int rank, lastrank, newrank = -1; - v = b - SA - 1; + v = PTRDIFF_TO_INT(b - SA - 1); lastrank = -1; for(c = first, d = a - 1; c <= d; ++c) { if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *++d = s; rank = ISA[s + depth]; - if(lastrank != rank) { lastrank = rank; newrank = d - SA; } + if(lastrank != rank) { lastrank = rank; newrank = PTRDIFF_TO_INT(d - SA); } ISA[s] = newrank; } } @@ -1155,7 +1155,7 @@ tr_partialcopy(int *ISA, const int *SA, lastrank = -1; for(e = d; first <= e; --e) { rank = ISA[*e]; - if(lastrank != rank) { lastrank = rank; newrank = e - SA; } + if(lastrank != rank) { lastrank = rank; newrank = PTRDIFF_TO_INT(e - SA); } if(newrank != rank) { ISA[*e] = newrank; } } @@ -1164,7 +1164,7 @@ tr_partialcopy(int *ISA, const int *SA, if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *--d = s; rank = ISA[s + depth]; - if(lastrank != rank) { lastrank = rank; newrank = d - SA; } + if(lastrank != rank) { lastrank = rank; newrank = PTRDIFF_TO_INT(d - SA); } ISA[s] = newrank; } } @@ -1180,23 +1180,23 @@ tr_introsort(int *ISA, const int *ISAd, int *a, *b, *c; int t; int v, x = 0; - int incr = ISAd - ISA; + int incr = PTRDIFF_TO_INT(ISAd - ISA); int limit, next; int ssize, trlink = -1; - for(ssize = 0, limit = tr_ilg(last - first);;) { + for(ssize = 0, limit = tr_ilg(PTRDIFF_TO_INT(last - first));;) { if(limit < 0) { if(limit == -1) { /* tandem repeat partition */ - tr_partition(ISAd - incr, first, first, last, &a, &b, last - SA - 1); + tr_partition(ISAd - incr, first, first, last, &a, &b, PTRDIFF_TO_INT(last - SA - 1)); /* update ranks */ if(a < last) { - for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } + for(c = first, v = PTRDIFF_TO_INT(a - SA - 1); c < a; ++c) { ISA[*c] = v; } } if(b < last) { - for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } + for(c = a, v = PTRDIFF_TO_INT(b - SA - 1); c < b; ++c) { ISA[*c] = v; } } /* push */ @@ -1207,19 +1207,19 @@ tr_introsort(int *ISA, const int *ISAd, } if((a - first) <= (last - b)) { if(1 < (a - first)) { - STACK_PUSH5(ISAd, b, last, tr_ilg(last - b), trlink); - last = a, limit = tr_ilg(a - first); + STACK_PUSH5(ISAd, b, last, tr_ilg(PTRDIFF_TO_INT(last - b)), trlink); + last = a, limit = tr_ilg(PTRDIFF_TO_INT(a - first)); } else if(1 < (last - b)) { - first = b, limit = tr_ilg(last - b); + first = b, limit = tr_ilg(PTRDIFF_TO_INT(last - b)); } else { STACK_POP5(ISAd, first, last, limit, trlink); } } else { if(1 < (last - b)) { - STACK_PUSH5(ISAd, first, a, tr_ilg(a - first), trlink); - first = b, limit = tr_ilg(last - b); + STACK_PUSH5(ISAd, first, a, tr_ilg(PTRDIFF_TO_INT(a - first)), trlink); + first = b, limit = tr_ilg(PTRDIFF_TO_INT(last - b)); } else if(1 < (a - first)) { - last = a, limit = tr_ilg(a - first); + last = a, limit = tr_ilg(PTRDIFF_TO_INT(a - first)); } else { STACK_POP5(ISAd, first, last, limit, trlink); } @@ -1228,26 +1228,26 @@ tr_introsort(int *ISA, const int *ISAd, /* tandem repeat copy */ a = stack[--ssize].b, b = stack[ssize].c; if(stack[ssize].d == 0) { - tr_copy(ISA, SA, first, a, b, last, ISAd - ISA); + tr_copy(ISA, SA, first, a, b, last, PTRDIFF_TO_INT(ISAd - ISA)); } else { if(0 <= trlink) { stack[trlink].d = -1; } - tr_partialcopy(ISA, SA, first, a, b, last, ISAd - ISA); + tr_partialcopy(ISA, SA, first, a, b, last, PTRDIFF_TO_INT(ISAd - ISA)); } STACK_POP5(ISAd, first, last, limit, trlink); } else { /* sorted partition */ if(0 <= *first) { a = first; - do { ISA[*a] = a - SA; } while((++a < last) && (0 <= *a)); + do { ISA[*a] = PTRDIFF_TO_INT(a - SA); } while((++a < last) && (0 <= *a)); first = a; } if(first < last) { a = first; do { *a = ~*a; } while(*++a < 0); - next = (ISA[*a] != ISAd[*a]) ? tr_ilg(a - first + 1) : -1; - if(++a < last) { for(b = first, v = a - SA - 1; b < a; ++b) { ISA[*b] = v; } } + next = (ISA[*a] != ISAd[*a]) ? tr_ilg(PTRDIFF_TO_INT(a - first + 1)) : -1; + if(++a < last) { for(b = first, v = PTRDIFF_TO_INT(a - SA - 1); b < a; ++b) { ISA[*b] = v; } } /* push */ - if(trbudget_check(budget, a - first)) { + if(trbudget_check(budget, PTRDIFF_TO_INT(a - first))) { if((a - first) <= (last - a)) { STACK_PUSH5(ISAd, a, last, -3, trlink); ISAd += incr, last = a, limit = next; @@ -1281,7 +1281,7 @@ tr_introsort(int *ISA, const int *ISAd, } if(limit-- == 0) { - tr_heapsort(ISAd, first, last - first); + tr_heapsort(ISAd, first, PTRDIFF_TO_INT(last - first)); for(a = last - 1; first < a; a = b) { for(x = ISAd[*a], b = a - 1; (first <= b) && (ISAd[*b] == x); --b) { *b = ~*b; } } @@ -1297,14 +1297,14 @@ tr_introsort(int *ISA, const int *ISAd, /* partition */ tr_partition(ISAd, first, first + 1, last, &a, &b, v); if((last - first) != (b - a)) { - next = (ISA[*a] != v) ? tr_ilg(b - a) : -1; + next = (ISA[*a] != v) ? tr_ilg(PTRDIFF_TO_INT(b - a)) : -1; /* update ranks */ - for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } - if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } } + for(c = first, v = PTRDIFF_TO_INT(a - SA - 1); c < a; ++c) { ISA[*c] = v; } + if(b < last) { for(c = a, v = PTRDIFF_TO_INT(b - SA - 1); c < b; ++c) { ISA[*c] = v; } } /* push */ - if((1 < (b - a)) && (trbudget_check(budget, b - a))) { + if((1 < (b - a)) && (trbudget_check(budget, PTRDIFF_TO_INT(b - a)))) { if((a - first) <= (last - b)) { if((last - b) <= (b - a)) { if(1 < (a - first)) { @@ -1381,8 +1381,8 @@ tr_introsort(int *ISA, const int *ISAd, } } } else { - if(trbudget_check(budget, last - first)) { - limit = tr_ilg(last - first), ISAd += incr; + if(trbudget_check(budget, PTRDIFF_TO_INT(last - first))) { + limit = tr_ilg(PTRDIFF_TO_INT(last - first)), ISAd += incr; } else { if(0 <= trlink) { stack[trlink].d = -1; } STACK_POP5(ISAd, first, last, limit, trlink); @@ -1420,7 +1420,7 @@ trsort(int *ISA, int *SA, int n, int depth) { budget.count = 0; tr_introsort(ISA, ISAd, SA, first, last, &budget); if(budget.count != 0) { unsorted += budget.count; } - else { skip = first - last; } + else { skip = PTRDIFF_TO_INT(first - last); } } else if((last - first) == 1) { skip = -1; } @@ -1634,7 +1634,7 @@ construct_SA(const unsigned char *T, int *SA, c0 = T[--s]; if((0 < s) && (T[s - 1] > c0)) { s = ~s; } if(c0 != c2) { - if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } + if(0 <= c2) { BUCKET_B(c2, c1) = PTRDIFF_TO_INT(k - SA); } k = SA + BUCKET_B(c2 = c0, c1); } assert(k < j); assert(k != NULL); @@ -1658,7 +1658,7 @@ construct_SA(const unsigned char *T, int *SA, c0 = T[--s]; if((s == 0) || (T[s - 1] < c0)) { s = ~s; } if(c0 != c2) { - BUCKET_A(c2) = k - SA; + BUCKET_A(c2) = PTRDIFF_TO_INT(k - SA); k = SA + BUCKET_A(c2 = c0); } assert(i < k); @@ -1698,7 +1698,7 @@ construct_BWT(const unsigned char *T, int *SA, *j = ~((int)c0); if((0 < s) && (T[s - 1] > c0)) { s = ~s; } if(c0 != c2) { - if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } + if(0 <= c2) { BUCKET_B(c2, c1) = PTRDIFF_TO_INT(k - SA); } k = SA + BUCKET_B(c2 = c0, c1); } assert(k < j); assert(k != NULL); @@ -1726,7 +1726,7 @@ construct_BWT(const unsigned char *T, int *SA, *i = c0; if((0 < s) && (T[s - 1] < c0)) { s = ~((int)T[s - 1]); } if(c0 != c2) { - BUCKET_A(c2) = k - SA; + BUCKET_A(c2) = PTRDIFF_TO_INT(k - SA); k = SA + BUCKET_A(c2 = c0); } assert(i < k); @@ -1738,7 +1738,7 @@ construct_BWT(const unsigned char *T, int *SA, } } - return orig - SA; + return PTRDIFF_TO_INT(orig - SA); } /* Constructs the burrows-wheeler transformed string directly @@ -1776,13 +1776,13 @@ construct_BWT_indexes(const unsigned char *T, int *SA, assert(((s + 1) < n) && (T[s] <= T[s + 1])); assert(T[s - 1] <= T[s]); - if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = j - SA; + if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = PTRDIFF_TO_INT(j - SA); c0 = T[--s]; *j = ~((int)c0); if((0 < s) && (T[s - 1] > c0)) { s = ~s; } if(c0 != c2) { - if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } + if(0 <= c2) { BUCKET_B(c2, c1) = PTRDIFF_TO_INT(k - SA); } k = SA + BUCKET_B(c2 = c0, c1); } assert(k < j); assert(k != NULL); @@ -1802,7 +1802,7 @@ construct_BWT_indexes(const unsigned char *T, int *SA, the sorted order of type B suffixes. */ k = SA + BUCKET_A(c2 = T[n - 1]); if (T[n - 2] < c2) { - if (((n - 1) & mod) == 0) indexes[(n - 1) / (mod + 1) - 1] = k - SA; + if (((n - 1) & mod) == 0) indexes[(n - 1) / (mod + 1) - 1] = PTRDIFF_TO_INT(k - SA); *k++ = ~((int)T[n - 2]); } else { @@ -1814,17 +1814,17 @@ construct_BWT_indexes(const unsigned char *T, int *SA, if(0 < (s = *i)) { assert(T[s - 1] >= T[s]); - if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = i - SA; + if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = PTRDIFF_TO_INT(i - SA); c0 = T[--s]; *i = c0; if(c0 != c2) { - BUCKET_A(c2) = k - SA; + BUCKET_A(c2) = PTRDIFF_TO_INT(k - SA); k = SA + BUCKET_A(c2 = c0); } assert(i < k); if((0 < s) && (T[s - 1] < c0)) { - if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = k - SA; + if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = PTRDIFF_TO_INT(k - SA); *k++ = ~((int)T[s - 1]); } else *k++ = s; @@ -1835,7 +1835,7 @@ construct_BWT_indexes(const unsigned char *T, int *SA, } } - return orig - SA; + return PTRDIFF_TO_INT(orig - SA); } From 2107c8f189e8496b2c561cd15d3c90a7d1d82479 Mon Sep 17 00:00:00 2001 From: Alexander Moch Date: Thu, 1 Jan 2026 10:56:31 +0100 Subject: [PATCH 214/245] bitstream: fix `BIT_readBits` and `BIT_reloadDStream` prototypes Align the declarations of BIT_readBits() and BIT_reloadDStream() in bitstream.h with their FORCE_INLINE_TEMPLATE definitions. The previous MEM_STATIC declarations caused an attribute mismatch between the header and the definitions, which can lead to incorrect compiler assumptions under certain toolchains and optimization levels. Signed-off-by: Alexander Moch --- lib/common/bitstream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/common/bitstream.h b/lib/common/bitstream.h index 3b7ad483d..6ff482a83 100644 --- a/lib/common/bitstream.h +++ b/lib/common/bitstream.h @@ -102,8 +102,8 @@ typedef enum { BIT_DStream_unfinished = 0, /* fully refilled */ } BIT_DStream_status; /* result of BIT_reloadDStream() */ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize); -MEM_STATIC BitContainerType BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits); -MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD); +FORCE_INLINE_TEMPLATE BitContainerType BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits); +FORCE_INLINE_TEMPLATE BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD); MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); From bb1eedcf866e0abdd34b157d83e19d76eb82a6f7 Mon Sep 17 00:00:00 2001 From: richardsonnick Date: Tue, 23 Dec 2025 16:40:02 -0500 Subject: [PATCH 215/245] correct mmap error check Update mmap error validation to check for MAP_FAILED instead of NULL. POSIX specifies that mmap returns MAP_FAILED (-1) on failure. --- programs/fileio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/programs/fileio.c b/programs/fileio.c index 4000c5b62..a0dcad817 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1050,7 +1050,9 @@ static size_t FIO_setDictBufferMMap(FIO_Dict_t* dict, const char* fileName, FIO_ } *bufferPtr = mmap(NULL, (size_t)fileSize, PROT_READ, MAP_PRIVATE, fileHandle, 0); - if (*bufferPtr==NULL) EXM_THROW(34, "%s", strerror(errno)); + if (*bufferPtr == MAP_FAILED) { + EXM_THROW(34, "%s", strerror(errno)) + } close(fileHandle); return (size_t)fileSize; From d9b10820f8b573e5cdcb343ae4884b4ce70ca156 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Mar 2026 05:32:41 +0000 Subject: [PATCH 216/245] Bump actions/upload-artifact from 6.0.0 to 7.0.0 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6.0.0 to 7.0.0. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/commit.yml | 2 +- .github/workflows/dev-long-tests.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 2dbbcc4a0..af3028e3c 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -99,6 +99,6 @@ jobs: echo " are still good, copy it into the repo and commit it." echo "> diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv" diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv - - uses: actions/upload-artifact@v6.0.0 + - uses: actions/upload-artifact@v7.0.0 with: path: "/tmp/circleci-artifacts" diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index dc4155f5a..f72a99729 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -317,7 +317,7 @@ jobs: dry-run: false sanitizer: ${{ matrix.sanitizer }} - name: Upload Crash - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # tag=v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # tag=v7.0.0 if: failure() && steps.build.outcome == 'success' with: name: ${{ matrix.sanitizer }}-artifacts diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 8f808b745..31b3f731d 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -51,7 +51,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # tag=v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # tag=v7.0.0 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 9095cc602..401441d12 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -93,7 +93,7 @@ jobs: mv bin/ zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ - name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip for manual inspection - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # tag=v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # tag=v7.0.0 with: compression-level: 9 # maximum compression if-no-files-found: error # defaults to `warn` From 1c140a86a17957b37d14ce14b1c1ae909166b250 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Mar 2026 05:32:44 +0000 Subject: [PATCH 217/245] Bump cygwin/cygwin-install-action from 6.0 to 6.1 Bumps [cygwin/cygwin-install-action](https://github.com/cygwin/cygwin-install-action) from 6.0 to 6.1. - [Release notes](https://github.com/cygwin/cygwin-install-action/releases) - [Commits](https://github.com/cygwin/cygwin-install-action/compare/f2009323764960f80959895c7bc3bb30210afe4d...711d29f3da23c9f4a1798e369a6f01198c13b11a) --- updated-dependencies: - dependency-name: cygwin/cygwin-install-action dependency-version: '6.1' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dev-short-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 4423a6dca..aef73157e 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -544,7 +544,7 @@ jobs: steps: - run: git config --global core.autocrlf input - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - - uses: cygwin/cygwin-install-action@f2009323764960f80959895c7bc3bb30210afe4d # tag=v6 + - uses: cygwin/cygwin-install-action@711d29f3da23c9f4a1798e369a6f01198c13b11a # tag=v6 with: platform: x86_64 packages: >- From 6e1e545916eff6457e4b264f8813a7417510a57e Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester (sebres)" Date: Sun, 1 Mar 2026 21:00:18 +0100 Subject: [PATCH 218/245] avoid potential RC on ctx->threadLimit, code review; closes gh-4547; replaces gh-4558 --- lib/common/pool.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/lib/common/pool.c b/lib/common/pool.c index 3adcefc9a..dd5fb0c4d 100644 --- a/lib/common/pool.c +++ b/lib/common/pool.c @@ -142,19 +142,17 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, /* Allocate space for the thread handles */ ctx->threads = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), customMem); ctx->threadCapacity = 0; + ctx->threadLimit = numThreads; ctx->customMem = customMem; /* Check for errors */ if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; } /* Initialize the threads */ - { size_t i; - for (i = 0; i < numThreads; ++i) { - if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) { - ctx->threadCapacity = i; - POOL_free(ctx); - return NULL; - } } - ctx->threadCapacity = numThreads; - ctx->threadLimit = numThreads; + while (ctx->threadCapacity < numThreads) { + if (ZSTD_pthread_create(&ctx->threads[ctx->threadCapacity++], NULL, &POOL_thread, ctx)) { + --ctx->threadCapacity; + POOL_free(ctx); + return NULL; + } } return ctx; } @@ -220,23 +218,22 @@ static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads) return 0; } /* numThreads > threadCapacity */ + ctx->threadLimit = numThreads; { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); if (!threadPool) return 1; - /* replace existing thread pool */ + /* extend existing thread pool */ ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(ZSTD_pthread_t)); ZSTD_customFree(ctx->threads, ctx->customMem); ctx->threads = threadPool; /* Initialize additional threads */ - { size_t threadId; - for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) { - if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) { - ctx->threadCapacity = threadId; - return 1; - } } - } } + while (ctx->threadCapacity < numThreads) { + if (ZSTD_pthread_create(&threadPool[ctx->threadCapacity++], NULL, &POOL_thread, ctx)) { + --ctx->threadCapacity; + return 1; + } + } + } /* successfully expanded */ - ctx->threadCapacity = numThreads; - ctx->threadLimit = numThreads; return 0; } From 6a8715f8d43dcbaec8d33945a7cfdae06ef1be6d Mon Sep 17 00:00:00 2001 From: Jennifer Lee Date: Wed, 4 Mar 2026 13:29:20 -0800 Subject: [PATCH 219/245] update man --- programs/zstd.1.md | 3 ++- programs/zstdcli.c | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/programs/zstd.1.md b/programs/zstd.1.md index bb9258d57..49d9e5f88 100644 --- a/programs/zstd.1.md +++ b/programs/zstd.1.md @@ -131,6 +131,7 @@ the last one takes effect. In all cases, the nb of threads is capped to `ZSTDMT_NBWORKERS_MAX`, which is either 64 in 32-bit mode, or 256 for 64-bit environments. This modifier does nothing if `zstd` is compiled without multithread support. + Note that memory usage increases with each thread. * `--single-thread`: Use a single thread for both I/O and compression. As compression is serialized with I/O, this can be slightly slower. @@ -157,7 +158,7 @@ the last one takes effect. when combined with multiple worker threads (>=2). * `--long[=#]`: enables long distance matching with `#` `windowLog`, if `#` is not - present it defaults to `27`. + present it defaults to `27`. The highest possible value is 31 This increases the window size (`windowLog`) and memory usage for both the compressor and decompressor. This setting is designed to improve the compression ratio for files with diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 34db7bf51..7749b2908 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1540,7 +1540,12 @@ int main(int argCount, const char* argv[]) /* check compression level limits */ { int const maxCLevel = ultra ? ZSTD_maxCLevel() : ZSTDCLI_CLEVEL_MAX; if (cLevel > maxCLevel) { - DISPLAYLEVEL(2, "Warning : compression level higher than max, reduced to %i \n", maxCLevel); + DISPLAYLEVEL(2, "Warning : compression level higher than max, reduced to %i. ", maxCLevel); + DISPLAYLEVEL(2, "Specify --ultra to raise the limit to 22 and use " + "--long=31 for maximum compression. Note that this " + "requires high amounts of memory, and the resulting data " + "might be rejected by third-party decoders and is " + "therefore only recommended for archival purposes. \n"); cLevel = maxCLevel; } } #endif From 1bd8e553633bb1b51fae051bc6b7fa75cb135fc6 Mon Sep 17 00:00:00 2001 From: jlee303 Date: Thu, 5 Mar 2026 15:12:33 -0800 Subject: [PATCH 220/245] Update programs/zstd.1.md Co-authored-by: Nick Terrell --- programs/zstd.1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/zstd.1.md b/programs/zstd.1.md index 49d9e5f88..1721441df 100644 --- a/programs/zstd.1.md +++ b/programs/zstd.1.md @@ -158,7 +158,7 @@ the last one takes effect. when combined with multiple worker threads (>=2). * `--long[=#]`: enables long distance matching with `#` `windowLog`, if `#` is not - present it defaults to `27`. The highest possible value is 31 + present it defaults to `27`. The highest possible value is 31. This increases the window size (`windowLog`) and memory usage for both the compressor and decompressor. This setting is designed to improve the compression ratio for files with From d7ee3207cc0db53f78fc6a69babc80747b1b7658 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 5 Mar 2026 18:44:12 -0500 Subject: [PATCH 221/245] Remove LICENSE file in build/ dir --- build/LICENSE | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 build/LICENSE diff --git a/build/LICENSE b/build/LICENSE deleted file mode 100644 index e69de29bb..000000000 From 7b04e6dd1e2385df0701e2c513db2478e5950d1b Mon Sep 17 00:00:00 2001 From: Jennifer Lee Date: Fri, 6 Mar 2026 09:47:03 -0800 Subject: [PATCH 222/245] Retry CI From f1e77ab2ba96f8fe2b7139b76989f7cd7022d6c9 Mon Sep 17 00:00:00 2001 From: Integral Date: Fri, 6 Mar 2026 15:36:57 +0800 Subject: [PATCH 223/245] Accept G, GB and GiB suffixes for options --- programs/zstdcli.c | 60 ++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 34db7bf51..e0d7faa43 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -347,7 +347,7 @@ static void errorOut(const char* msg) /*! readU32FromCharChecked() : * @return 0 if success, and store the result in *value. - * allows and interprets K, KB, KiB, M, MB and MiB suffix. + * allows and interprets K, KB, KiB, M, MB, MiB, G, GB and GiB suffix. * Will also modify `*stringPtr`, advancing it to position where it stopped reading. * @return 1 if an overflow error occurs */ static int readU32FromCharChecked(const char** stringPtr, unsigned* value) @@ -362,15 +362,22 @@ static int readU32FromCharChecked(const char** stringPtr, unsigned* value) if (result < last) return 1; /* overflow error */ (*stringPtr)++ ; } - if ((**stringPtr=='K') || (**stringPtr=='M')) { - unsigned const maxK = ((unsigned)(-1)) >> 10; - if (result > maxK) return 1; /* overflow error */ - result <<= 10; - if (**stringPtr=='M') { - if (result > maxK) return 1; /* overflow error */ - result <<= 10; + if ((**stringPtr=='K') || (**stringPtr=='M') || (**stringPtr=='G')) { + switch (**stringPtr) { + case 'K': + if (result > (((unsigned)-1) >> 10)) return 1; /* overflow error */ + result <<= 10; + break; + case 'M': + if (result > (((unsigned)-1) >> 20)) return 1; /* overflow error */ + result <<= 20; + break; + case 'G': + if (result > (((unsigned)-1) >> 30)) return 1; /* overflow error */ + result <<= 30; + break; } - (*stringPtr)++; /* skip `K` or `M` */ + (*stringPtr)++; /* skip `K`, `M` or `G` */ if (**stringPtr=='i') (*stringPtr)++; if (**stringPtr=='B') (*stringPtr)++; } @@ -380,7 +387,7 @@ static int readU32FromCharChecked(const char** stringPtr, unsigned* value) /*! readU32FromChar() : * @return : unsigned integer value read from input in `char` format. - * allows and interprets K, KB, KiB, M, MB and MiB suffix. + * allows and interprets K, KB, KiB, M, MB, MiB, G, GB and GiB suffix. * Will also modify `*stringPtr`, advancing it to position where it stopped reading. * Note : function will exit() program if digit sequence overflows */ static unsigned readU32FromChar(const char** stringPtr) { @@ -392,7 +399,7 @@ static unsigned readU32FromChar(const char** stringPtr) { /*! readIntFromChar() : * @return : signed integer value read from input in `char` format. - * allows and interprets K, KB, KiB, M, MB and MiB suffix. + * allows and interprets K, KB, KiB, M, MB, MiB, G, GB and GiB suffix. * Will also modify `*stringPtr`, advancing it to position where it stopped reading. * Note : function will exit() program if digit sequence overflows */ static int readIntFromChar(const char** stringPtr) { @@ -409,7 +416,7 @@ static int readIntFromChar(const char** stringPtr) { /*! readSizeTFromCharChecked() : * @return 0 if success, and store the result in *value. - * allows and interprets K, KB, KiB, M, MB and MiB suffix. + * allows and interprets K, KB, KiB, M, MB, MiB, G, GB and GiB suffix. * Will also modify `*stringPtr`, advancing it to position where it stopped reading. * @return 1 if an overflow error occurs */ static int readSizeTFromCharChecked(const char** stringPtr, size_t* value) @@ -424,15 +431,22 @@ static int readSizeTFromCharChecked(const char** stringPtr, size_t* value) if (result < last) return 1; /* overflow error */ (*stringPtr)++ ; } - if ((**stringPtr=='K') || (**stringPtr=='M')) { - size_t const maxK = ((size_t)(-1)) >> 10; - if (result > maxK) return 1; /* overflow error */ - result <<= 10; - if (**stringPtr=='M') { - if (result > maxK) return 1; /* overflow error */ - result <<= 10; + if ((**stringPtr=='K') || (**stringPtr=='M') || (**stringPtr=='G')) { + switch (**stringPtr) { + case 'K': + if (result > (((size_t)-1) >> 10)) return 1; /* overflow error */ + result <<= 10; + break; + case 'M': + if (result > (((size_t)-1) >> 20)) return 1; /* overflow error */ + result <<= 20; + break; + case 'G': + if (result > (((size_t)-1) >> 30)) return 1; /* overflow error */ + result <<= 30; + break; } - (*stringPtr)++; /* skip `K` or `M` */ + (*stringPtr)++; /* skip `K`, `M` or `G` */ if (**stringPtr=='i') (*stringPtr)++; if (**stringPtr=='B') (*stringPtr)++; } @@ -442,7 +456,7 @@ static int readSizeTFromCharChecked(const char** stringPtr, size_t* value) /*! readSizeTFromChar() : * @return : size_t value read from input in `char` format. - * allows and interprets K, KB, KiB, M, MB and MiB suffix. + * allows and interprets K, KB, KiB, M, MB, MiB, G, GB and GiB suffix. * Will also modify `*stringPtr`, advancing it to position where it stopped reading. * Note : function will exit() program if digit sequence overflows */ static size_t readSizeTFromChar(const char** stringPtr) { @@ -830,7 +844,7 @@ static unsigned init_nbWorkers(unsigned defaultNbWorkers) { NEXT_FIELD(__nb); \ _varu32 = readU32FromChar(&__nb); \ if(*__nb != 0) { \ - errorOut("error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed"); \ + errorOut("error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB, G, GB, GiB are allowed"); \ } \ } @@ -839,7 +853,7 @@ static unsigned init_nbWorkers(unsigned defaultNbWorkers) { NEXT_FIELD(__nb); \ _varTsize = readSizeTFromChar(&__nb); \ if(*__nb != 0) { \ - errorOut("error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed"); \ + errorOut("error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB, G, GB, GiB are allowed"); \ } \ } From 3f8f9b3f89244638f10bca664c120fd28cb14efe Mon Sep 17 00:00:00 2001 From: NiDU-NINJA Date: Sat, 7 Mar 2026 08:27:15 +0000 Subject: [PATCH 224/245] Fix potential NULL pointer dereference in ZSTD_customCalloc when custom allocator fails --- lib/common/allocations.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/common/allocations.h b/lib/common/allocations.h index 5e8995501..d4d392998 100644 --- a/lib/common/allocations.h +++ b/lib/common/allocations.h @@ -33,9 +33,13 @@ MEM_STATIC void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem) MEM_STATIC void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem) { if (customMem.customAlloc) { - /* calloc implemented as malloc+memset; - * not as efficient as calloc, but next best guess for custom malloc */ + /* calloc implemented as malloc+memset */ void* const ptr = customMem.customAlloc(customMem.opaque, size); + + if (ptr == NULL) { + return NULL; + } + ZSTD_memset(ptr, 0, size); return ptr; } From 043426b3e226a6f4b7325cfbdd21da90f702a892 Mon Sep 17 00:00:00 2001 From: Jennifer Lee Date: Mon, 9 Mar 2026 16:30:41 -0700 Subject: [PATCH 225/245] Promote flag --- programs/zstdcli.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 34db7bf51..19c6cae89 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -147,6 +147,7 @@ static void usage(FILE* f, const char* programName) DISPLAY_F(f, "Usage: %s [OPTIONS...] [INPUT... | -] [-o OUTPUT]\n\n", programName); DISPLAY_F(f, "Options:\n"); DISPLAY_F(f, " -o OUTPUT Write output to a single file, OUTPUT.\n"); + DISPLAY_F(f, " -c, --stdout Write to STDOUT (even if it is a console) and keep the INPUT file(s).\n"); DISPLAY_F(f, " -k, --keep Preserve INPUT file(s). [Default] \n"); DISPLAY_F(f, " --rm Remove INPUT file(s) after successful (de)compression to file.\n"); #ifdef ZSTD_GZCOMPRESS @@ -167,7 +168,8 @@ static void usage(FILE* f, const char* programName) DISPLAY_F(f, " -f, --force Disable input and output checks. Allows overwriting existing files,\n"); DISPLAY_F(f, " receiving input from the console, printing output to STDOUT, and\n"); DISPLAY_F(f, " operating on links, block devices, etc. Unrecognized formats will be\n"); - DISPLAY_F(f, " passed-through through as-is.\n\n"); + DISPLAY_F(f, " passed-through through as-is.\n"); + DISPLAY_F(f, " -q, --quiet Suppress warnings; pass twice to suppress errors.\n\n"); DISPLAY_F(f, " -h Display short usage and exit.\n"); DISPLAY_F(f, " -H, --help Display full help and exit.\n"); @@ -181,10 +183,8 @@ static void usageAdvanced(const char* programName) DISPLAYOUT("\n"); usage(stdout, programName); DISPLAYOUT("Advanced options:\n"); - DISPLAYOUT(" -c, --stdout Write to STDOUT (even if it is a console) and keep the INPUT file(s).\n\n"); DISPLAYOUT(" -v, --verbose Enable verbose output; pass multiple times to increase verbosity.\n"); - DISPLAYOUT(" -q, --quiet Suppress warnings; pass twice to suppress errors.\n"); #ifndef ZSTD_NOTRACE DISPLAYOUT(" --trace LOG Log tracing information to LOG.\n"); #endif From 13ea076d3b8df315cb6731971f594b8bb4f4e401 Mon Sep 17 00:00:00 2001 From: Jennifer Lee Date: Mon, 9 Mar 2026 16:40:42 -0700 Subject: [PATCH 226/245] Update tests --- tests/cli-tests/basic/help.sh.stdout.glob | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/cli-tests/basic/help.sh.stdout.glob b/tests/cli-tests/basic/help.sh.stdout.glob index 66c6906cf..eb249bf2b 100644 --- a/tests/cli-tests/basic/help.sh.stdout.glob +++ b/tests/cli-tests/basic/help.sh.stdout.glob @@ -5,6 +5,7 @@ Usage: zstd *OPTIONS...* *INPUT... | -* *-o OUTPUT* Options: -o OUTPUT Write output to a single file, OUTPUT. + -c, --stdout Write to STDOUT (even if it is a console) and keep the INPUT file(s). -k, --keep Preserve INPUT file(s). *Default* --rm Remove INPUT file(s) after successful (de)compression to file. @@ -19,11 +20,12 @@ Options: receiving input from the console, printing output to STDOUT, and operating on links, block devices, etc. Unrecognized formats will be passed-through through as-is. + -q, --quiet Suppress warnings; pass twice to suppress errors. -h Display short usage and exit. -H, --help Display full help and exit. -V, --version Display the program version and exit. - + + zstd -H ... Advanced options: From 2293e9601f89904061e468796c0613f1088ec7a2 Mon Sep 17 00:00:00 2001 From: Jennifer Lee Date: Mon, 9 Mar 2026 17:17:13 -0700 Subject: [PATCH 227/245] init commit --- contrib/largeNbDicts/largeNbDicts.c | 6 ++++-- programs/README.md | 7 +++++++ programs/fileio.c | 4 +++- programs/zstdcli.c | 8 +++++--- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/contrib/largeNbDicts/largeNbDicts.c b/contrib/largeNbDicts/largeNbDicts.c index 6b6cc34ca..f7496930b 100644 --- a/contrib/largeNbDicts/largeNbDicts.c +++ b/contrib/largeNbDicts/largeNbDicts.c @@ -45,7 +45,9 @@ #define RUN_TIME_DEFAULT_MS 1000 #define BENCH_TIME_DEFAULT_MS (BENCH_TIME_DEFAULT_S * RUN_TIME_DEFAULT_MS) -#define DISPLAY_LEVEL_DEFAULT 3 +#ifndef ZSTD_DISPLAY_LEVEL_DEFAULT +#define ZSTD_DISPLAY_LEVEL_DEFAULT 3 +#endif #define BENCH_SIZE_MAX (1200 MB) @@ -61,7 +63,7 @@ #define DISPLAY(...) fprintf(stdout, __VA_ARGS__) #define DISPLAYLEVEL(l, ...) { if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } } -static int g_displayLevel = DISPLAY_LEVEL_DEFAULT; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */ +static int g_displayLevel = ZSTD_DISPLAY_LEVEL_DEFAULT; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */ /*--- buffer_t ---*/ diff --git a/programs/README.md b/programs/README.md index 2a6978ac4..6522b647d 100644 --- a/programs/README.md +++ b/programs/README.md @@ -79,6 +79,13 @@ There are however other Makefile targets that create different variations of CLI This can be useful to produce smaller binaries. A corresponding `Makefile` target using this ability is `zstd-compress`. +- __ZSTD_DISPLAY_LEVEL_DEFAULT__ : Controls the default verbosity level of `zstd` output. + The default value is `2`. Lower values (e.g., `1`) reduce output verbosity, + while higher values (e.g., `3`) increase it. + This allows setting preferred verbosity at compile time, + rather than passing `-q` or `-v` flags at runtime. + Example : `CPPFLAGS="-DZSTD_DISPLAY_LEVEL_DEFAULT=1" make` + - __BACKTRACE__ : `zstd` can display a stack backtrace when execution generates a runtime exception. By default, this feature may be degraded/disabled on some platforms unless additional compiler directives are diff --git a/programs/fileio.c b/programs/fileio.c index a0dcad817..3b2f9b636 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -2401,7 +2401,9 @@ int FIO_compressFilename(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs, const cRess_t ress = FIO_createCResources(prefs, dictFileName, UTIL_getFileSize(srcFileName), compressionLevel, comprParams); int const result = FIO_compressFilename_srcFile(fCtx, prefs, &ress, dstFileName, srcFileName, compressionLevel); -#define DISPLAY_LEVEL_DEFAULT 2 +#ifndef ZSTD_DISPLAY_LEVEL_DEFAULT +#define ZSTD_DISPLAY_LEVEL_DEFAULT 2 +#endif FIO_freeCResources(&ress); return result; diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 34db7bf51..70e170c47 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -77,7 +77,9 @@ static unsigned init_nbWorkers(unsigned defaultNbWorkers); #define MB *(1 <<20) #define GB *(1U<<30) -#define DISPLAY_LEVEL_DEFAULT 2 +#ifndef ZSTD_DISPLAY_LEVEL_DEFAULT +#define ZSTD_DISPLAY_LEVEL_DEFAULT 2 +#endif static const char* g_defaultDictName = "dictionary"; static const unsigned g_defaultMaxDictSize = 110 KB; @@ -104,7 +106,7 @@ typedef enum { cover, fastCover, legacy } dictType; **************************************/ #undef DISPLAYLEVEL #define DISPLAYLEVEL(l, ...) { if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } } -static int g_displayLevel = DISPLAY_LEVEL_DEFAULT; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */ +static int g_displayLevel = ZSTD_DISPLAY_LEVEL_DEFAULT; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */ /*-************************************ @@ -660,7 +662,7 @@ static void setMaxCompression(ZSTD_compressionParameters* params) static void printVersion(void) { - if (g_displayLevel < DISPLAY_LEVEL_DEFAULT) { + if (g_displayLevel < ZSTD_DISPLAY_LEVEL_DEFAULT) { DISPLAYOUT("%s\n", ZSTD_VERSION_STRING); return; } From 488b3a7e37a0325a6115e2aef89708a4c41bdb33 Mon Sep 17 00:00:00 2001 From: Integral Date: Fri, 6 Mar 2026 16:50:05 +0800 Subject: [PATCH 228/245] Add tests for options with G, GB and GiB suffixes --- tests/cli-tests/basic/memlimit.sh | 24 +++++++++++++++++++ .../cli-tests/basic/memlimit.sh.stderr.exact | 21 +++++++++++----- .../cli-tests/basic/memlimit.sh.stdout.exact | 9 +++++++ tests/playTests.sh | 10 +++++++- 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/tests/cli-tests/basic/memlimit.sh b/tests/cli-tests/basic/memlimit.sh index 88d734d0d..ec7f93a10 100755 --- a/tests/cli-tests/basic/memlimit.sh +++ b/tests/cli-tests/basic/memlimit.sh @@ -35,6 +35,30 @@ rm file.zst println "+ zstd --memory=1MiB file" zstd -q --memory=1MiB file && die "Should allow numeric parameter with expected suffix" rm file.zst +println "+ zstd --memory=1G file" +zstd -q --memory=1G file && die "Should allow numeric parameter with expected suffix" +rm file.zst +println "+ zstd --memory=1GB file" +zstd -q --memory=1GB file && die "Should allow numeric parameter with expected suffix" +rm file.zst +println "+ zstd --memory=1GiB file" +zstd -q --memory=1GiB file && die "Should allow numeric parameter with expected suffix" +rm file.zst +println "+ zstd --memory=3G file" +zstd -q --memory=3G file && die "Should allow numeric parameter with expected suffix" +rm file.zst +println "+ zstd --memory=3GB file" +zstd -q --memory=3GB file && die "Should allow numeric parameter with expected suffix" +rm file.zst +println "+ zstd --memory=3GiB file" +zstd -q --memory=3GiB file && die "Should allow numeric parameter with expected suffix" +rm file.zst +println "+ zstd --memory=4G file" +zstd --memory=4G file && die "Should not allow out-of-bound numeric parameter" +println "+ zstd --memory=4GB file" +zstd --memory=4GB file && die "Should not allow out-of-bound numeric parameter" +println "+ zstd --memory=4GiB file" +zstd --memory=4GiB file && die "Should not allow out-of-bound numeric parameter" rm file exit 0 diff --git a/tests/cli-tests/basic/memlimit.sh.stderr.exact b/tests/cli-tests/basic/memlimit.sh.stderr.exact index 3785b0f92..28784a1e6 100644 --- a/tests/cli-tests/basic/memlimit.sh.stderr.exact +++ b/tests/cli-tests/basic/memlimit.sh.stderr.exact @@ -1,9 +1,9 @@ -error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed -error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed -error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed -error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed -error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed -error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB are allowed +error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB, G, GB, GiB are allowed +error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB, G, GB, GiB are allowed +error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB, G, GB, GiB are allowed +error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB, G, GB, GiB are allowed +error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB, G, GB, GiB are allowed +error: only numeric values with optional suffixes K, KB, KiB, M, MB, MiB, G, GB, GiB are allowed Should allow numeric parameter without suffix Should allow numeric parameter with expected suffix Should allow numeric parameter with expected suffix @@ -11,3 +11,12 @@ Should allow numeric parameter with expected suffix Should allow numeric parameter with expected suffix Should allow numeric parameter with expected suffix Should allow numeric parameter with expected suffix +Should allow numeric parameter with expected suffix +Should allow numeric parameter with expected suffix +Should allow numeric parameter with expected suffix +Should allow numeric parameter with expected suffix +Should allow numeric parameter with expected suffix +Should allow numeric parameter with expected suffix +error: numeric value overflows 32-bit unsigned int +error: numeric value overflows 32-bit unsigned int +error: numeric value overflows 32-bit unsigned int diff --git a/tests/cli-tests/basic/memlimit.sh.stdout.exact b/tests/cli-tests/basic/memlimit.sh.stdout.exact index 1821648e4..a1a5520e7 100644 --- a/tests/cli-tests/basic/memlimit.sh.stdout.exact +++ b/tests/cli-tests/basic/memlimit.sh.stdout.exact @@ -11,3 +11,12 @@ + zstd --memory=1M file + zstd --memory=1MB file + zstd --memory=1MiB file ++ zstd --memory=1G file ++ zstd --memory=1GB file ++ zstd --memory=1GiB file ++ zstd --memory=3G file ++ zstd --memory=3GB file ++ zstd --memory=3GiB file ++ zstd --memory=4G file ++ zstd --memory=4GB file ++ zstd --memory=4GiB file diff --git a/tests/playTests.sh b/tests/playTests.sh index d3ce39846..d8ea0c3da 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -1075,13 +1075,19 @@ cat tmp | zstd -14 -f --size-hint=11050 | zstd -t # slightly too high cat tmp | zstd -14 -f --size-hint=10950 | zstd -t # slightly too low cat tmp | zstd -14 -f --size-hint=22000 | zstd -t # considerably too high cat tmp | zstd -14 -f --size-hint=5500 | zstd -t # considerably too low -println "test : allows and interprets K,KB,KiB,M,MB and MiB suffix" +println "test : allows and interprets K,KB,KiB,M,MB,MiB,G,GB and GiB suffix" cat tmp | zstd -14 -f --size-hint=11K | zstd -t cat tmp | zstd -14 -f --size-hint=11KB | zstd -t cat tmp | zstd -14 -f --size-hint=11KiB | zstd -t cat tmp | zstd -14 -f --size-hint=1M | zstd -t cat tmp | zstd -14 -f --size-hint=1MB | zstd -t cat tmp | zstd -14 -f --size-hint=1MiB | zstd -t +cat tmp | zstd -14 -f --size-hint=1G | zstd -t +cat tmp | zstd -14 -f --size-hint=1GB | zstd -t +cat tmp | zstd -14 -f --size-hint=1GiB | zstd -t +cat tmp | zstd -14 -f --size-hint=3G | zstd -t +cat tmp | zstd -14 -f --size-hint=3GB | zstd -t +cat tmp | zstd -14 -f --size-hint=3GiB | zstd -t println "\n===> dictionary tests " @@ -1684,6 +1690,8 @@ roundTripTest -g1M -P50 "1 --single-thread --long=29" " --memory=512MB" roundTripTest -g1M -P50 "1 --single-thread --long=29 --zstd=wlog=28" " --memory=256MB" roundTripTest -g1M -P50 "1 --single-thread --long=29" " --long=28 --memory=512MB" roundTripTest -g1M -P50 "1 --single-thread --long=29" " --zstd=wlog=28 --memory=512MB" +roundTripTest -g1M -P50 "1 --single-thread --long=30" " --memory=1GB" +roundTripTest -g1M -P50 "1 --single-thread --long=30" " --zstd=wlog=29 --memory=1GB" if [ "$ZSTD_LIB_EXCLUDE_COMPRESSORS_DFAST_AND_UP" -ne "1" ]; then From 3041c8e539b6027381939690ff12600ef01ade6d Mon Sep 17 00:00:00 2001 From: Jennifer Lee Date: Wed, 11 Mar 2026 08:29:06 -0700 Subject: [PATCH 229/245] Update #define format --- contrib/largeNbDicts/largeNbDicts.c | 2 +- programs/fileio.c | 2 +- programs/zstdcli.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/largeNbDicts/largeNbDicts.c b/contrib/largeNbDicts/largeNbDicts.c index f7496930b..30c1396ec 100644 --- a/contrib/largeNbDicts/largeNbDicts.c +++ b/contrib/largeNbDicts/largeNbDicts.c @@ -46,7 +46,7 @@ #define BENCH_TIME_DEFAULT_MS (BENCH_TIME_DEFAULT_S * RUN_TIME_DEFAULT_MS) #ifndef ZSTD_DISPLAY_LEVEL_DEFAULT -#define ZSTD_DISPLAY_LEVEL_DEFAULT 3 +# define ZSTD_DISPLAY_LEVEL_DEFAULT 3 #endif #define BENCH_SIZE_MAX (1200 MB) diff --git a/programs/fileio.c b/programs/fileio.c index 3b2f9b636..78a906d53 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -2402,7 +2402,7 @@ int FIO_compressFilename(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs, const int const result = FIO_compressFilename_srcFile(fCtx, prefs, &ress, dstFileName, srcFileName, compressionLevel); #ifndef ZSTD_DISPLAY_LEVEL_DEFAULT -#define ZSTD_DISPLAY_LEVEL_DEFAULT 2 +# define ZSTD_DISPLAY_LEVEL_DEFAULT 2 #endif FIO_freeCResources(&ress); diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 70e170c47..1be8fc26b 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -78,7 +78,7 @@ static unsigned init_nbWorkers(unsigned defaultNbWorkers); #define GB *(1U<<30) #ifndef ZSTD_DISPLAY_LEVEL_DEFAULT -#define ZSTD_DISPLAY_LEVEL_DEFAULT 2 +# define ZSTD_DISPLAY_LEVEL_DEFAULT 2 #endif static const char* g_defaultDictName = "dictionary"; From 3f565b731e65b48800e2a8da31825b5b2af15c26 Mon Sep 17 00:00:00 2001 From: Jennifer Lee Date: Thu, 12 Mar 2026 11:32:48 -0700 Subject: [PATCH 230/245] rever -q --- programs/zstdcli.c | 4 ++-- tests/cli-tests/basic/help.sh.stdout.glob | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 19c6cae89..b3c7a9900 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -168,8 +168,7 @@ static void usage(FILE* f, const char* programName) DISPLAY_F(f, " -f, --force Disable input and output checks. Allows overwriting existing files,\n"); DISPLAY_F(f, " receiving input from the console, printing output to STDOUT, and\n"); DISPLAY_F(f, " operating on links, block devices, etc. Unrecognized formats will be\n"); - DISPLAY_F(f, " passed-through through as-is.\n"); - DISPLAY_F(f, " -q, --quiet Suppress warnings; pass twice to suppress errors.\n\n"); + DISPLAY_F(f, " passed-through through as-is.\n\n"); DISPLAY_F(f, " -h Display short usage and exit.\n"); DISPLAY_F(f, " -H, --help Display full help and exit.\n"); @@ -185,6 +184,7 @@ static void usageAdvanced(const char* programName) DISPLAYOUT("Advanced options:\n"); DISPLAYOUT(" -v, --verbose Enable verbose output; pass multiple times to increase verbosity.\n"); + DISPLAY_F(f, " -q, --quiet Suppress warnings; pass twice to suppress errors.\n"); #ifndef ZSTD_NOTRACE DISPLAYOUT(" --trace LOG Log tracing information to LOG.\n"); #endif diff --git a/tests/cli-tests/basic/help.sh.stdout.glob b/tests/cli-tests/basic/help.sh.stdout.glob index eb249bf2b..08cfdb1b3 100644 --- a/tests/cli-tests/basic/help.sh.stdout.glob +++ b/tests/cli-tests/basic/help.sh.stdout.glob @@ -20,12 +20,11 @@ Options: receiving input from the console, printing output to STDOUT, and operating on links, block devices, etc. Unrecognized formats will be passed-through through as-is. - -q, --quiet Suppress warnings; pass twice to suppress errors. -h Display short usage and exit. -H, --help Display full help and exit. -V, --version Display the program version and exit. - + + zstd -H ... Advanced options: From e374fc76fe48d394d9265641a3e1dbbcf5050bac Mon Sep 17 00:00:00 2001 From: Jennifer Lee Date: Thu, 12 Mar 2026 11:34:43 -0700 Subject: [PATCH 231/245] fix display format --- programs/zstdcli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index b3c7a9900..0cb4f3ba2 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -184,7 +184,7 @@ static void usageAdvanced(const char* programName) DISPLAYOUT("Advanced options:\n"); DISPLAYOUT(" -v, --verbose Enable verbose output; pass multiple times to increase verbosity.\n"); - DISPLAY_F(f, " -q, --quiet Suppress warnings; pass twice to suppress errors.\n"); + DISPLAYOUT(" -q, --quiet Suppress warnings; pass twice to suppress errors.\n"); #ifndef ZSTD_NOTRACE DISPLAYOUT(" --trace LOG Log tracing information to LOG.\n"); #endif From cef5a5611a3792cf9eaab5826f48e92c7c287f0a Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Tue, 17 Mar 2026 13:08:14 -0700 Subject: [PATCH 232/245] Fix unintended high memory usage --- lib/compress/zstd_ldm.c | 6 +++++- tests/fuzzer.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/lib/compress/zstd_ldm.c b/lib/compress/zstd_ldm.c index 070551cad..7bf36cd86 100644 --- a/lib/compress/zstd_ldm.c +++ b/lib/compress/zstd_ldm.c @@ -152,7 +152,11 @@ void ZSTD_ldm_adjustParameters(ldmParams_t* params, } } if (params->hashLog == 0) { - params->hashLog = BOUNDED(ZSTD_HASHLOG_MIN, params->windowLog - params->hashRateLog, ZSTD_HASHLOG_MAX); + if (params->windowLog <= params->hashRateLog) { + params->hashLog = ZSTD_HASHLOG_MIN; + } else { + params->hashLog = BOUNDED(ZSTD_HASHLOG_MIN, params->windowLog - params->hashRateLog, ZSTD_HASHLOG_MAX); + } } if (params->minMatchLength == 0) { params->minMatchLength = LDM_MIN_MATCH_LENGTH; diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 472f8c8b3..7b7c9d666 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -1414,6 +1414,37 @@ static int basicUnitTests(U32 const seed, double compressibility) } DISPLAYLEVEL(3, "OK \n"); + DISPLAYLEVEL(3, "test%3i : ldm hashRateLog > windowLog underflow check : ", testNb++); + { + /* Test that when windowLog < hashRateLog, we don't get excessive memory usage + * due to underflow in hashLog calculation (windowLog - hashRateLog). */ + ZSTD_CCtx* const cctx = ZSTD_createCCtx(); + + size_t const size = (1U << 10); // 1 KB + size_t const dstCapacity = ZSTD_compressBound(size); + void* src = (void*)malloc(size); + void* dst = (void*)malloc(dstCapacity); + + RDG_genBuffer(src, size, 0.5, 0.5, seed); + + CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_enableLongDistanceMatching, ZSTD_ps_enable)); + CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_ldmHashLog, 0)); + CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 12)); + CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_ldmHashRateLog, 13)); + + CHECK_Z(ZSTD_compress2(cctx, dst, dstCapacity, src, size)); + + { size_t const cctxSize = ZSTD_sizeof_CCtx(cctx); + DISPLAYLEVEL(3, "CCtx size: %u bytes ", (unsigned)cctxSize); + CHECK_LT(cctxSize, 50 MB); + } + + ZSTD_freeCCtx(cctx); + free(src); + free(dst); + } + DISPLAYLEVEL(3, "OK \n"); + DISPLAYLEVEL(3, "test%3i : testing dict compression with enableLdm and forceMaxWindow : ", testNb++); { ZSTD_CCtx* const cctx = ZSTD_createCCtx(); From 5fc4931c04de9d2c21b41a99cda546b369506508 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 05:50:27 +0000 Subject: [PATCH 233/245] Bump microsoft/setup-msbuild from 2.0.0 to 3.0.0 Bumps [microsoft/setup-msbuild](https://github.com/microsoft/setup-msbuild) from 2.0.0 to 3.0.0. - [Release notes](https://github.com/microsoft/setup-msbuild/releases) - [Commits](https://github.com/microsoft/setup-msbuild/compare/6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce...30375c66a4eea26614e0d39710365f22f8b0af57) --- updated-dependencies: - dependency-name: microsoft/setup-msbuild dependency-version: 3.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/cmake-tests.yml | 2 +- .github/workflows/dev-short-tests.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cmake-tests.yml b/.github/workflows/cmake-tests.yml index 3660dcbcf..47817a659 100644 --- a/.github/workflows/cmake-tests.yml +++ b/.github/workflows/cmake-tests.yml @@ -133,7 +133,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0 + uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # tag=v3.0.0 - name: "Configure CMake (${{ matrix.name }})" run: | cd build\cmake diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index aef73157e..5031d107b 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -321,7 +321,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0 + uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # tag=v3.0.0 - name: Build ${{matrix.name}} working-directory: ${{env.GITHUB_WORKSPACE}} # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference @@ -524,7 +524,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0 + uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # tag=v3.0.0 - name: Build and run tests working-directory: ${{env.GITHUB_WORKSPACE}} env: From 497a433e0141ddde8f7c84aebd3ff343ed3f960a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 05:50:32 +0000 Subject: [PATCH 234/245] Bump android-actions/setup-android from 3.2.2 to 4.0.0 Bumps [android-actions/setup-android](https://github.com/android-actions/setup-android) from 3.2.2 to 4.0.0. - [Release notes](https://github.com/android-actions/setup-android/releases) - [Commits](https://github.com/android-actions/setup-android/compare/9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407...651bceb6f9ca583f16b8d75b62c36ded2ae6fc9c) --- updated-dependencies: - dependency-name: android-actions/setup-android dependency-version: 4.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/android-ndk-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index 890d6fb7c..bd4aa6fde 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -22,7 +22,7 @@ jobs: distribution: 'temurin' - name: Setup Android SDK - uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3.2.2 + uses: android-actions/setup-android@651bceb6f9ca583f16b8d75b62c36ded2ae6fc9c # v4.0.0 - name: Install Android NDK run: | From a23bf84362c3f751cdc11b3b2709c03c677378ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 05:50:38 +0000 Subject: [PATCH 235/245] Bump msys2/setup-msys2 from 2.30.0 to 2.31.0 Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.30.0 to 2.31.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/4f806de0a5a7294ffabaff804b38a9b435a73bda...cafece8e6baf9247cf9b1bf95097b0b983cc558d) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.31.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dev-long-tests.yml | 2 +- .github/workflows/dev-short-tests.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index f72a99729..447a865c5 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -274,7 +274,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - - uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # tag=v2.30.0 + - uses: msys2/setup-msys2@cafece8e6baf9247cf9b1bf95097b0b983cc558d # tag=v2.31.0 with: msystem: MINGW64 install: make diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index aef73157e..13f929b20 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -487,7 +487,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - - uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # tag=v2.30.0 + - uses: msys2/setup-msys2@cafece8e6baf9247cf9b1bf95097b0b983cc558d # tag=v2.31.0 with: msystem: ${{ matrix.msystem }} install: make diffutils diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 401441d12..cb659e5fb 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 # MSYS2 setup - - uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # tag=v2.30.0 + - uses: msys2/setup-msys2@cafece8e6baf9247cf9b1bf95097b0b983cc558d # tag=v2.31.0 if: matrix.shell == 'msys2' with: msystem: ${{ matrix.msystem }} From 0d815ad877b43b7d2e05e18cb51673b66d0afade Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 05:50:47 +0000 Subject: [PATCH 236/245] Bump github/codeql-action from 4.31.2 to 4.35.1 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.2 to 4.35.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/0499de31b99561a6d14a36a5f662c2a54f91beee...c10b8064de6f491fea524254123dbe5e09572f13) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.35.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 31b3f731d..1e372f63a 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,6 +59,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # tag=v4.31.2 + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # tag=v4.35.1 with: sarif_file: results.sarif From 44ebbde6a3178b53e4da5a28426fbf82d1fbb6f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ey=C3=BCp=20Can=20Akman?= Date: Sun, 19 Apr 2026 20:11:15 +0300 Subject: [PATCH 237/245] Fake console stdin in valgrindTest to force failure --- build/meson/tests/valgrindTest.py | 2 +- tests/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/meson/tests/valgrindTest.py b/build/meson/tests/valgrindTest.py index 05d84878b..8bf840704 100644 --- a/build/meson/tests/valgrindTest.py +++ b/build/meson/tests/valgrindTest.py @@ -19,7 +19,7 @@ def valgrindTest(valgrind, datagen, fuzzer, zstd, fullbench): subprocess.check_call([*VALGRIND_ARGS, datagen, '-g50M'], stdout=subprocess.DEVNULL) - if subprocess.call([*VALGRIND_ARGS, zstd], + if subprocess.call([*VALGRIND_ARGS, zstd, '--fake-stdin-is-console'], stdout=subprocess.DEVNULL) == 0: raise subprocess.SubprocessError('zstd without argument should have failed') diff --git a/tests/Makefile b/tests/Makefile index c74c219dc..bfa796ba0 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -281,7 +281,7 @@ test-valgrind: VALGRIND = valgrind --leak-check=full --show-leak-kinds=all --err test-valgrind: zstd datagen fuzzer fullbench @echo "\n ---- valgrind tests : memory analyzer ----" $(VALGRIND) ./datagen -g50M > $(VOID) - $(VALGRIND) $(PRGDIR)/zstd ; if [ $$? -eq 0 ] ; then echo "zstd without argument should have failed"; false; fi + $(VALGRIND) $(PRGDIR)/zstd --fake-stdin-is-console ; if [ $$? -eq 0 ] ; then echo "zstd without argument should have failed"; false; fi ./datagen -g80 | $(VALGRIND) $(PRGDIR)/zstd - -c > $(VOID) ./datagen -g16KB | $(VALGRIND) $(PRGDIR)/zstd -vf - -c > $(VOID) ./datagen -g2930KB | $(VALGRIND) $(PRGDIR)/zstd -5 -vf - -o tmp From c770d993fbed02b2fdc53f5534f076327a53ee23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 06:18:32 +0000 Subject: [PATCH 238/245] Bump msys2/setup-msys2 from 2.31.0 to 2.31.1 Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.31.0 to 2.31.1. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/cafece8e6baf9247cf9b1bf95097b0b983cc558d...e9898307ac31d1a803454791be09ab9973336e1c) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.31.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/dev-long-tests.yml | 2 +- .github/workflows/dev-short-tests.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 447a865c5..64360cbd5 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -274,7 +274,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - - uses: msys2/setup-msys2@cafece8e6baf9247cf9b1bf95097b0b983cc558d # tag=v2.31.0 + - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # tag=v2.31.1 with: msystem: MINGW64 install: make diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 179d49e00..acd55584e 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -487,7 +487,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - - uses: msys2/setup-msys2@cafece8e6baf9247cf9b1bf95097b0b983cc558d # tag=v2.31.0 + - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # tag=v2.31.1 with: msystem: ${{ matrix.msystem }} install: make diffutils diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index cb659e5fb..fcd79b89f 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 # MSYS2 setup - - uses: msys2/setup-msys2@cafece8e6baf9247cf9b1bf95097b0b983cc558d # tag=v2.31.0 + - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # tag=v2.31.1 if: matrix.shell == 'msys2' with: msystem: ${{ matrix.msystem }} From cb6b844cb5f708e34f4bdcec956f26dfb80105de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 06:18:35 +0000 Subject: [PATCH 239/245] Bump actions/upload-artifact from 7.0.0 to 7.0.1 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v7...v7.0.1) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/commit.yml | 2 +- .github/workflows/dev-long-tests.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index af3028e3c..8b8bb0f57 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -99,6 +99,6 @@ jobs: echo " are still good, copy it into the repo and commit it." echo "> diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv" diff tests/regression/results.csv $CIRCLE_ARTIFACTS/results.csv - - uses: actions/upload-artifact@v7.0.0 + - uses: actions/upload-artifact@v7.0.1 with: path: "/tmp/circleci-artifacts" diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 447a865c5..441cd2683 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -317,7 +317,7 @@ jobs: dry-run: false sanitizer: ${{ matrix.sanitizer }} - name: Upload Crash - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # tag=v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # tag=v7.0.1 if: failure() && steps.build.outcome == 'success' with: name: ${{ matrix.sanitizer }}-artifacts diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 1e372f63a..caa862ca3 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -51,7 +51,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # tag=v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # tag=v7.0.1 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index cb659e5fb..cd1ef23de 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -93,7 +93,7 @@ jobs: mv bin/ zstd-${{ github.ref_name }}-${{matrix.ziparch}}/ - name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip for manual inspection - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # tag=v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # tag=v7.0.1 with: compression-level: 9 # maximum compression if-no-files-found: error # defaults to `warn` From 5233c58e6ca0b1c4c6b353ad79649191ed195bdc Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 14 May 2026 13:55:54 -0400 Subject: [PATCH 240/245] [doc] Clarify requirements around Block_Maximum_Size in spec Clarify that it is legal to send compressed blocks that are larger than the uncompressed size so long as their `Block_Content` is no larger than `Block_Maximum_Size`. See https://github.com/facebook/zstd/issues/4667 --- doc/zstd_compression_format.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/doc/zstd_compression_format.md b/doc/zstd_compression_format.md index 7700c472d..cdad14f58 100644 --- a/doc/zstd_compression_format.md +++ b/doc/zstd_compression_format.md @@ -16,7 +16,7 @@ Distribution of this document is unlimited. ### Version -0.4.4 (2025-03-22) +0.4.5 (2026-05-14) Introduction @@ -387,20 +387,24 @@ When `Block_Type` is `RLE_Block`, since `Block_Content`’s size is always 1, __`Block_Content`__ and __`Block_Maximum_Size`__ -The size of `Block_Content` is limited by `Block_Maximum_Size`, -which is the smallest of: +The size of `Block_Content` is limited by `Block_Maximum_Size`, which is +determined once for a given frame and is the smallest of: - `Window_Size` - 128 KiB (131.072 bytes) -`Block_Maximum_Size` is constant for a given frame. -This maximum is applicable to both the decompressed size -and the compressed size of any block in the frame. +Both the `Block_Content` and the decompressed size of any block in the frame must +be no larger than `Block_Maximum_Size`. The reasoning for this limit is that a decoder can read this information at the beginning of a frame and use it to allocate buffers. The guarantees on the size of blocks ensure that the buffers will be large enough for any following block of the valid frame. +If a compressed block is larger than its uncompressed content, it is recommended +to send it uncompressed (i.e., a `Raw_Block`). However, as long as +`Block_Content` is no larger than `Block_Maximum_Size`, it is legal to send such +a compressed block, even if it's larger than its uncompressed content. + Compressed Blocks ----------------- @@ -1742,6 +1746,7 @@ or at least provide a meaningful error code explaining for which reason it canno Version changes --------------- +- 0.4.5 : minor clarification regarding Block_Maximum_Size - 0.4.4 : minor clarification for block size - 0.4.3 : clarifications for Huffman prefix code assignment example - 0.4.2 : refactor FSE table construction process, inspired by Donald Pian From a20ab7436fcb947c7322655c7cf03710cefdf1c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 05:32:43 +0000 Subject: [PATCH 241/245] Bump github/codeql-action/upload-sarif from 4.35.1 to 4.36.2 Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 4.35.1 to 4.36.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/c10b8064de6f491fea524254123dbe5e09572f13...8aad20d150bbac5944a9f9d289da16a4b0d87c1e) --- updated-dependencies: - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.36.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index caa862ca3..fb678cf68 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,6 +59,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # tag=v4.35.1 + uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # tag=v4.36.2 with: sarif_file: results.sarif From 61b9912eec9d703248a96fdf0e9ec5bd14bf7e5c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 05:32:46 +0000 Subject: [PATCH 242/245] Bump cygwin/cygwin-install-action from 6.0.1 to 6.0.2 Bumps [cygwin/cygwin-install-action](https://github.com/cygwin/cygwin-install-action) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/cygwin/cygwin-install-action/releases) - [Commits](https://github.com/cygwin/cygwin-install-action/compare/711d29f3da23c9f4a1798e369a6f01198c13b11a...3f0a3f9f988f7e96b8c18098ae05eaec175f5b52) --- updated-dependencies: - dependency-name: cygwin/cygwin-install-action dependency-version: 6.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/dev-short-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index acd55584e..cfd0294ca 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -544,7 +544,7 @@ jobs: steps: - run: git config --global core.autocrlf input - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - - uses: cygwin/cygwin-install-action@711d29f3da23c9f4a1798e369a6f01198c13b11a # tag=v6 + - uses: cygwin/cygwin-install-action@3f0a3f9f988f7e96b8c18098ae05eaec175f5b52 # tag=v6 with: platform: x86_64 packages: >- From a1ddcdae2d8a81668d4d8aa38b15e2e17bed1efc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 05:32:35 +0000 Subject: [PATCH 243/245] Bump actions/cache from 5 to 6 Bumps [actions/cache](https://github.com/actions/cache) from 5 to 6. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/commit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml index 8b8bb0f57..a66818409 100644 --- a/.github/workflows/commit.yml +++ b/.github/workflows/commit.yml @@ -75,7 +75,7 @@ jobs: steps: - uses: actions/checkout@v6.0.2 - name: restore_cache - uses: actions/cache@v5 + uses: actions/cache@v6 with: key: regression-cache-{{ checksum "tests/regression/data.c" }}-v0 path: tests/regression/cache From e0764492056386c0d4334bff26d53efccc08e01a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 05:32:52 +0000 Subject: [PATCH 244/245] Bump actions/setup-java from 5.2.0 to 5.6.0 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 5.2.0 to 5.6.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/be666c2fcd27ec809703dec50e508c2fdc7f6654...03ad4de0992f5dab5e18fcb136590ce7c4a0ac95) --- updated-dependencies: - dependency-name: actions/setup-java dependency-version: 5.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/android-ndk-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android-ndk-build.yml b/.github/workflows/android-ndk-build.yml index bd4aa6fde..1e9e23e08 100644 --- a/.github/workflows/android-ndk-build.yml +++ b/.github/workflows/android-ndk-build.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - name: Set up JDK 17 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0 with: java-version: '17' distribution: 'temurin' From af48fb967f65fd4d70ede433fc2562b114c66264 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 05:32:58 +0000 Subject: [PATCH 245/245] Bump msys2/setup-msys2 from 2.31.1 to 2.32.0 Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.31.1 to 2.32.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/e9898307ac31d1a803454791be09ab9973336e1c...66cd2cce69caa17b53920067426061ca1de3a884) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-version: 2.32.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/dev-long-tests.yml | 2 +- .github/workflows/dev-short-tests.yml | 2 +- .github/workflows/windows-artifacts.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index da607543e..c5b1e22d5 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -274,7 +274,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # tag=v2.31.1 + - uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # tag=v2.32.0 with: msystem: MINGW64 install: make diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index cfd0294ca..4b8a95d18 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -487,7 +487,7 @@ jobs: shell: msys2 {0} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 - - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # tag=v2.31.1 + - uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # tag=v2.32.0 with: msystem: ${{ matrix.msystem }} install: make diffutils diff --git a/.github/workflows/windows-artifacts.yml b/.github/workflows/windows-artifacts.yml index 9998584d9..97454beb2 100644 --- a/.github/workflows/windows-artifacts.yml +++ b/.github/workflows/windows-artifacts.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # tag=v6.0.2 # MSYS2 setup - - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # tag=v2.31.1 + - uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # tag=v2.32.0 if: matrix.shell == 'msys2' with: msystem: ${{ matrix.msystem }}