ZSTD(1)
๐ NAME ๐
Okay bestie, this is ZSTD(1) from the User Commands section, and it's giving pure compression energy ๐
zstd - zstd, zstdmt, unzstd, zstdcat - Compress or decompress .zst files โจ
๐ SYNOPSIS ๐
So there are a few lil aliases here, and they're all just zstd in disguise ๐ง
zstdmt is equivalent to zstd -T0
unzstd is equivalent to zstd -d
zstdcat is equivalent to zstd -dcf
โจ DESCRIPTION โจ
okay so zstd is a fast lossless compression algorithm and data compression tool ๐
Its command line vibes are super similar to gzip(1) and xz(1). It's based on the LZ77 family, with extra FSE & huff0 entropy stages on top ๐ค It's also highly configurable, so you can go from fast modes at > 200 MB/s per core all the way up to strong modes with excellent compression ratios. And the decoder is literally so fast, with speeds > 500 MB/s per core, that it stays roughly stable no matter what compression settings you picked ๐ญ๐ฅ
zstd's command line is generally like gzip's, but it has a few lowkey differences ๐
- Source files are preserved by default. If you want them removed automatically, use
--rm๐๏ธ - When compressing a single file, zstd shows progress notifications and a result summary by default. Add
-qto turn them off ๐คซ - zstd shows a short help page when your command line is an error. Use
-qif you don't want that ๐ - zstd does not accept input from the console, but it does accept stdin as long as stdin isn't the console ๐ง
- zstd does not store the input's filename or attributes, only its contents ๐
zstd processes each file based on the operation mode you picked. If no files are given, or the file is -, zstd reads from standard input and writes the processed data to standard output ๐ฆ Now here's the big rule: zstd will refuse to write compressed data to standard output if it's a terminal. It'll show an error message and skip that file. Same deal for reading compressed data from standard input: if it's a terminal, zstd won't do it ๐
โโ๏ธ
Unless you use --stdout or -o, output files get written to a new file whose name is built from the source file name:
- When compressing, the suffix
.zstgets added to the source filename to make the target filename โจ - When decompressing, the
.zstsuffix gets removed from the source filename to make the target filename ๐
๐งต Concatenation with .zst Files
It's possible to concatenate multiple .zst files together ๐ zstd will decompress that agglomerated file as if it were one single .zst file. Iconic ๐ญ
โจ OPTIONS โจ
Integer Suffixes and Special Values
Wherever an integer argument is expected, you can add an optional suffix so you don't have to type out huge numbers ๐งฎ Just make sure there's no space between the integer and the suffix.
KiBโ multiplies the integer by 1,024 (2\^10).Ki,K, andKBwork as synonyms forKiB๐ธMiBโ multiplies the integer by 1,048,576 (2\^20).Mi,M, andMBare accepted as synonyms forMiB๐
Operation Mode
If you give multiple operation mode options, the last one wins ๐
-z,--compressโ compress! This is the default when you don't pick an operation mode and the command name doesn't imply one. (For example,unzstdimplies--decompress, so it's already got that covered ๐ง)-d,--decompress,--uncompressโ decompress, obviously ๐-t,--testโ tests the integrity of compressed files. This is equivalent to--decompress --stdout > /dev/null, so the decompressed data gets thrown away but still gets checksummed for errors. No files get created or removed, so it's a totally safe vibe check ๐ฉบ-b#โ benchmarks file(s) using compression level#. Check BENCHMARK below for the full scoop ๐--train FILESโ usesFILESas a training set to build a dictionary. Your training set should have a lot of small files (> 100) ๐ง Check DICTIONARY BUILDER below for how this works.-l,--listโ displays info about a zstd compressed file, like its size, ratio, and checksum. Some of these fields might not be available, and you can add the-vmodifier to get even more info ๐
Operation Modifiers
-#โ picks the compression level#, from[1-19](default:3) ๐๏ธ Higher levels usually give you a higher compression ratio, but it costs speed and memory. A rough rule of thumb is that compression speed gets divided by 2 about every 2 levels ๐ Under the hood, each level maps to a set of advanced parameters (which you can also tweak one by one, see below). Because the compressor's behavior depends a lot on the content it's squishing, you shouldn't expect a perfectly smooth progression from one level to the next ๐คทโโ๏ธ--ultraโ unlocks the high compression levels 20+ (max 22) ๐ These use a lot more memory, and decompression also needs more memory when you use them. Plan accordingly, bestie ๐--fast[=#]โ switches to ultra-fast compression levels โก If=#isn't there, it defaults to1. The higher the value, the faster it goes, but you pay for it with some compression ratio. This overwrites a compression level if you set one earlier, and if you set a compression level after--fast, that one overrides it instead ๐-T#,--threads=#โ compresses using#working threads (default:1) ๐งต If#is0, zstd tries to detect and use your number of physical CPU cores. In every case, the thread count gets capped toZSTDMT_NBWORKERS_MAX, which is64in 32-bit mode or256for 64-bit environments. This does nothing if zstd was compiled without multithread support ๐--single-threadโ uses one single thread for both I/O and compression ๐งโโ๏ธ Since compression is serialized with I/O, this can be slightly slower. The upside is that single-thread mode uses significantly less memory, which is great for systems with limited memory, like 32-bit systems ๐- Note 1: this mode is the only one available when multithread support is disabled.
- Note 2: this mode is different from
-T1, which spawns 1 compression thread running in parallel with I/O. The final compressed result is also slightly different from-T1๐
--auto-threads={physical,logical}(default:physical) โ when you use the default thread amount via-T0, this picks the default based on the number of detected physical or logical cores ๐ง--adapt[=min=#,max=#]โ zstd dynamically adapts the compression level to the I/O conditions it's perceiving ๐ฆ You can watch the adaptation happen live with-v. You can also constrain adaptation between a suppliedminandmaxlevel. The feature works when combined with multi-threading and--longmode, but it does not work with--single-thread. By default it sets the window size to8 MiB(you can change that manually, seewlog). Because dynamic adaptation is chaotic by nature, the compressed result is not reproducible โ ๏ธ- Note: at the time of writing,
--adaptcan get stuck at low speed when combined with multiple worker threads (>=2) ๐ฉ
- Note: at the time of writing,
--long[=#]โ enables long distance matching with#windowLog. If#isn't present, it defaults to27๐ฃ๏ธ This increases the window size (windowLog) and memory usage for both the compressor and the decompressor. It's designed to improve the compression ratio for files that have long matches at a large distance ๐- Note: if windowLog is set larger than
27, you need to pass--long=windowLogor--memory=windowSizeto the decompressor too ๐ซถ
- Note: if windowLog is set larger than
-D DICTโ usesDICTas a dictionary to compress or decompressFILE(s)๐--patch-from FILEโ specifies the file to be used as a reference point for zstd's diff engine ๐ฉน This is basically dictionary compression with some convenient parameter selection, namely that windowSize > srcSize.- Note: you can't use this and
-Dtogether ๐ซ - Note:
--longmode gets automatically activated if chainLog < fileLog (fileLog being the windowLog required to cover the whole file). You can also force it manually ๐ช - Note: up to level
15, you can use--patch-fromin--single-threadmode to marginally improve the compression ratio, at the cost of speed. Using'--single-thread'above level15leads to lower compression ratios ๐ - Note: for level
19, you can get an increased compression ratio at the cost of speed by setting--zstd=targetLength=to something large (i.e.4096), and by setting a large--zstd=chainLog=๐ฅ
- Note: you can't use this and
--rsyncableโ zstd will periodically synchronize the compression state so the compressed file is more rsync-friendly ๐ There's a negligible impact on compression ratio, and a potential impact on compression speed that's perceptible at higher speeds (like when you combine--rsyncablewith lots of parallel worker threads). This feature does not work with--single-thread. You probably don't want to use it with long range mode, since it decreases the effectiveness of the synchronization points, but your mileage may vary ๐คทโโ๏ธ-C,--[no-]checkโ adds an integrity check computed from the uncompressed data (default: enabled) โ--[no-]content-sizeโ enables or disables whether the original size of the file gets placed in the header of the compressed file ๐ The default is--content-size, which means the original size will be placed in the header.--no-dictIDโ doesn't store the dictionary ID within the frame header (dictionary compression) ๐ The decoder will have to rely on implicit knowledge about which dictionary to use, and it won't be able to check if it's the correct one.-M#,--memory=#โ sets a memory usage limit ๐ง By default, zstd uses128 MiBfor decompression as the maximum amount of memory the decompressor is allowed to use. You can override this if needed, in either direction (you can increase or decrease it).- This is also used during compression when you use it with
--patch-from=. In that case, this parameter overrides the maximum size allowed for a dictionary. (128 MiB). - It can also 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 ๐ง
- This is also used during compression when you use it with
--stream-size=#โ sets the pledged source size of input coming from a stream ๐ This value must be exact, because it gets included in the produced frame header. Incorrect stream sizes will cause an error โ This info is used to better optimize compression parameters, which can give you better and potentially faster compression, especially for smaller source sizes ๐ฆ--size-hint=#โ ok so when zstd is reading from a stream, it has to guess how big the source is before it tunes the compression settings, and if the stream is small that guess can be kinda wrong ๐ This flag lets you set the guess yourself. Exact guesses give the best compression ratios โจ Overestimates make the ratio slightly worse, but underestimates can tank it hard ๐--target-compressed-block-size=#โ tries to make compressed blocks around this size ๐ It splits bigger blocks so they land closer to the target. This is super useful for latency, because the receiver can start working with early, incomplete data ๐ฆ It's a loose target, so blocks hit it "on average" but some can still be bigger or smaller. Turning it on can slow compression down by up to ~10% at level 1 ๐ญ Higher levels take a smaller speed hit, and at the higher settings it's basically invisible ๐-f,--forceโ the "I know what I'm doing" button ๐ฅ It turns off the input and output checks, so you can overwrite existing files, read from the console, write to stdout, and operate on links, block devices, etc. When decompressing, or when the output goes to stdout, unrecognized formats get passed through as-is ๐ซถ-c,--stdoutโ writes to standard output (even if that's the console) and keeps your original files, aka it disables--rm๐-o FILEโ saves the result into FILE ๐ Heads up, this clashes with-c. If you pass both on the command line, whichever one you wrote last wins ๐--[no-]sparseโ turns sparse file support on or off ๐ธ Sparse mode makes files with lots of zeroes take up less space on disk, and can speed up decompression since there's less disk I/O โจ Default is enabled when the output goes to a file, and disabled when it goes to stdout. This setting overrides the default, so you can force sparse mode over stdout too ๐ง--[no-]pass-throughโ turns passing uncompressed files through as-is on or off ๐ฆ During decompression with pass-through enabled, unrecognized formats get copied straight from input to output. By default, pass-through happens when the output is stdout and you've set the force (-f) option ๐--rmโ removes the source file(s) after a successful compression or decompression ๐ณ It's silently ignored if the output is stdout. If you combine it with-o, zstd will ask you to confirm first (you can silence that with-f), because deleting stuff is a destructive move ๐-k,--keepโ keeps the source file(s) after a successful compression or decompression ๐ This is the default behavior, so you're safe unless you go out of your way ๐ซถ-rโ operates recursively on directories ๐ It selects every file in the named directory and all its subdirectories. This is clutch for cutting down on command line typing, and for dodging shell expansion limits when there are tons of files and the names blow past the max command line size ๐--filelist FILEโ reads the list of files to process from FILE ๐ The format is compatible withlsoutput, one file per line ๐--output-dir-flat DIRโ stores the resulting files in the target DIR directory instead of the same directory as the original file ๐๏ธ Be careful though, this can cause name collisions if files from different directories end up with the same name. Collision resolution keeps the first file with a given name in DIR, but if you combine it with-f, the last file ends up there instead ๐ฌ--output-dir-mirror DIRโ basically the same vibe as--output-dir-flat, the output files go underneath DIR, but this one copies your input directory hierarchy into the output DIR ๐ฟ
If the input directory contains "..", the files in that directory get ignored ๐
โโ๏ธ If the input directory is an absolute directory (like "/var/tmp/abc"), it gets stored into "output-dir/var/tmp/abc". If there are multiple input files or directories, collision resolution follows the same rules as --output-dir-flat ๐
--format=FORMATโ compresses and decompresses in other formats ๐ If zstd was compiled with support for them, it can compress to or decompress from other compression algorithm formats. The possible options arezstd,gzip,xz,lzma, andlz4. If you don't pass a format, zstd is the default โจ-h/-H,--helpโ displays help (or long help) and exits ๐โโ๏ธ-V,--versionโ displays the version number and exits immediately ๐ท๏ธ Since it exits right away, any flags you put after-Vare basically ignored ๐ Advanced move:-vValso shows supported formats,-vvValso shows POSIX support, and-qVwill only print the version number, which is perfect for machines to read ๐ค-v,--verboseโ verbose mode, gives you more info ๐ฃ-q,--quietโ suppresses warnings, interactivity, and notifications ๐คซ Specify it twice to suppress errors too ๐ถ--no-progressโ hides the progress bar but keeps all the other messages ๐--show-default-cparamsโ shows the default compression parameters that'll be used for a particular input file, based on your compression level and the input size ๐ If the file isn't a regular file (like a pipe), this flag outputs the parameters used for inputs of unknown size ๐ง--exclude-compressedโ only compresses files that aren't already compressed ๐ โโ๏ธ--โ everything after--is treated as a file, even if it looks like a flag ๐ซฃ
gzip Operation Modifiers
okay so when zstd gets invoked through a gzip symlink, it picks up a few extra options that mimic gzip's behavior ๐ Here they are:
-n,--no-nameโ doesn't store the original filename and timestamps when compressing a file ๐ This is the default behavior, so it's technically a no-op ๐คทโโ๏ธ--bestโ alias to the option-9๐
Environment Variables
okay this is a big deal bestie: setting parameters with environment variables comes with security implications, so this avenue is intentionally limited ๐ Only ZSTD_CLEVEL and ZSTD_NBTHREADS are supported right now ๐
They set the default compression level and the number of threads to use during compression, respectively โจ
ZSTD_CLEVEL sets the level between 1 and 19 (the "normal" range) ๐ If its value isn't a valid integer, it gets ignored with a warning message ๐ฌ ZSTD_CLEVEL just replaces the default compression level, which is (3) ๐ง
ZSTD_NBTHREADS sets how many threads zstd will try to use during compression ๐งต If its value isn't a valid unsigned integer, it gets ignored with a warning message ๐ ZSTD_NBTHREADS defaults to (1), and it's capped at ZSTDMT_NBWORKERS_MAX==200 ๐ zstd has to be compiled with multithread support for this variable to do anything at all ๐ซ
Both of these can be overridden by their command line equivalents: -# for the compression level and -T# for the number of compression threads ๐
โจ ADVANCED COMPRESSION OPTIONS โจ
okay so zstd comes with 22 predefined regular compression levels plus the fast levels ๐ each level secretly gets translated into a bunch of advanced parameters that control how the compressor behaves. if you're curious about what your level turns into, run --show-default-cparams and see the receipts ๐งพ and if you want to tweak things yourself, you can override those parameters with advanced compression options. it's giving full control ๐
๐ --zstd[=options] ๐
you pass the options as a comma-separated list. bestie, you only need to name the ones you want to change, and everything else just gets pulled from your selected or default compression level ๐ซถ here's the full list of what you can play with:
๐ฆ strategy=strat, strat=strat
this picks the strategy the match finder uses ๐
there are 9 strategies, numbered 1 to 9, going from fastest to strongest: 1=ZSTD_fast, 2=ZSTD_dfast, 3=ZSTD_greedy, 4=ZSTD_lazy, 5=ZSTD_lazy2, 6=ZSTD_btlazy2, 7=ZSTD_btopt, 8=ZSTD_btultra, 9=ZSTD_btultra2.
๐ธ windowLog=wlog, wlog=wlog
this sets the maximum number of bits for a match distance ๐
higher number = more chances to find a match, which usually makes the compression ratio better ๐ but the catch is it also eats more memory for both the compressor and the decompressor ๐ญ the minimum wlog is 10 (1 KiB) and the maximum is 30 (1 GiB) on 32-bit platforms, and 31 (2 GiB) on 64-bit platforms.
Heads up, babe: if you set windowLog to something larger than 27, you have to pass--long=windowLogor--memory=windowSizeto the decompressor too, or it won't be able to read the file ๐
๐ง hashLog=hlog, hlog=hlog
this sets the maximum number of bits for a hash table ๐ชฃ
bigger hash tables mean fewer collisions, which usually makes compression faster โก but it needs more memory while compressing. the minimum hlog is 6 (64 entries / 256 B) and the maximum is 30 (1B entries / 4 GiB).
๐ chainLog=clog, clog=clog
this sets the maximum number of bits for the secondary search structure, and what that structure looks like depends on the strategy you picked ๐ธ๏ธ
higher numbers = more chances to find a match, so the ratio usually improves ๐ but compression slows down and needs more memory. this option gets ignored for the ZSTD_fast strategy, since that one only has the primary hash table, no cap ๐
โโ๏ธ the minimum clog is 6 (64 entries / 256 B), and the maximum is 29 (512M entries / 2 GiB) on 32-bit platforms or 30 (1B entries / 4 GiB) on 64-bit platforms.
๐ searchLog=slog, slog=slog
this sets the maximum number of searches in a hash chain or binary tree, using a logarithmic scale ๐
more searches = better chance of finding a match, which usually boosts the compression ratio, but compression speed takes a hit ๐ข the minimum slog is 1 and the maximum is 'windowLog' - 1.
๐ minMatch=mml, mml=mml
this sets the minimum searched length of a match in a hash table ๐
longer search lengths usually make the compression ratio worse, but decompression gets faster ๐ the minimum mml is 3 and the maximum is 7.
๐ targetLength=tlen, tlen=tlen
this one's personality depends entirely on which strategy you're using ๐ญ
for ZSTD_btopt, ZSTD_btultra and ZSTD_btultra2, it's the minimum match length that tells the match finder to stop searching. a bigger targetLength usually improves the ratio but slows compression down ๐
for ZSTD_fast, it turns on ultra-fast mode whenever it's greater than 0 โก the value is how much data gets skipped between match sampling. the vibe is reversed here: a bigger targetLength makes compression faster but the ratio worse ๐
for all the other strategies, this field does absolutely nothing ๐คทโโ๏ธ
the minimum tlen is 0 and the maximum is 128 KiB.
๐ซง overlapLog=ovlog, ovlog=ovlog
this decides the overlapSize, which is how much data gets reloaded from the previous job ๐ this option only shows up when multithreading is enabled. reloading more data makes the ratio better but the speed worse โ๏ธ
the minimum ovlog is 0 and the maximum is 9. 1 means "no overlap", so every job is completely independent ๐๏ธ 9 means "full overlap", meaning up to windowSize gets reloaded from the previous job. every time you drop ovlog by 1, the reloaded amount gets cut in half, so 8 means windowSize/2 and 6 means windowSize/8 ๐งฎ the value 0 is special and means "default", where zstd picks the ovlog automatically. in that case it'll land anywhere from 6 to 9, depending on the strategy you're using.
๐ ldmHashLog=lhlog, lhlog=lhlog
this sets the maximum size of the hash table used for long distance matching ๐ฐ๏ธ
heads up, this one is ignored unless long distance matching is turned on. bigger hash tables usually make the ratio better, but they cost more memory while compressing and slow things down a bit ๐ข the minimum lhlog is 6 and the maximum is 30 (default: 20).
๐ ldmMinMatch=lmml, lmml=lmml
this sets the minimum searched length of a match for long distance matching ๐
also ignored unless long distance matching is enabled โ bigger or very tiny values usually make the ratio worse ๐ the minimum lmml is 4 and the maximum is 4096 (default: 64).
๐ชบ ldmBucketSizeLog=lblog, lblog=lblog
this sets the size of each bucket for the long distance matching hash table ๐งบ
ignored unless long distance matching is on, obviously ๐ bigger buckets resolve collisions better, but compression speed drops ๐ the minimum lblog is 1 and the maximum is 8 (default: 3).
๐ ldmHashRateLog=lhrlog, lhrlog=lhrlog
this controls how often entries get inserted into the long distance matching hash table โฐ
also ignored unless long distance matching is enabled ๐
โโ๏ธ bigger values make compression faster, but if you stray too far from the default, the ratio will probably suffer ๐ the default value is wlog - lhlog.
๐ท Example ๐ท
okay here's a little recipe ๐ฐ the following parameters set advanced compression options to something 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# ๐งฉ
this lets you set the size of each compression job ๐ง it's only available when multi-threading is enabled. each job runs in parallel, so this value indirectly decides how many threads are active at once ๐งต the default job size changes depending on the compression level (generally 4 * windowSize), but with -B# you can pick your own custom size ๐ฏ
just know that the job size has to respect a minimum, which gets enforced automatically for you ๐ค that minimum is either 512 KB or overlapSize, whichever one is biggest. and fair warning: different job sizes will give you non-identical compressed frames ๐
๐ DICTIONARY BUILDER ๐
okay so zstd has this thing called dictionary compression and it is SO good for tiny files and messages ๐ฅบโจ. you train zstd on a bunch of samples and it saves the result into a file called a dictionary ๐. then when you compress AND decompress, you point at the same one with -D dictionaryFileName. small files that look like your samples get a total glow-up ๐
๐ฅ.
๐ --train FILEs
Use FILEs as your training set to make a dictionary. ideally it has a LOT of samples (> 100) and weighs about 100x your target dictionary size, so like ~10 MB for a 100 KB dictionary ๐ซถ. you can combine --train with -r to point at a directory instead of listing every single file, which is clutch when the shell is being dramatic about expansion limits ๐.
since dictionary compression is mostly for small files, the training set should only have small files. if some samples happen to be big, only the first 128 KiB of them get used for training ๐ค.
--train supports multithreading if zstd was compiled with threading support (which it is by default) ๐งต. extra advanced params go with --train-fastcover, the legacy builder is --train-legacy, and the slower cover builder is --train-cover ๐ข. the default --train is the same as --train-fastcover=d=8,steps=4 ๐.
๐ -o FILE
Saves the dictionary into FILE (default name: dictionary) ๐๏ธ.
๐งข --maxdict=#
Caps the dictionary at the size you give (default: 112640 bytes). quantities are bytes unless you say otherwise, but you can use suffixes like KB or MB for bigger numbers ๐.
๐๏ธ -#
Use # compression level during training (optional). this makes the stats more tuned to that level, so you get a small ratio boost for that exact level ๐.
โ๏ธ -B#
Splits input files into blocks of size # (default: no split) ๐ฐ.
๐ง -M#, --memory=#
Limits how much sample data gets loaded for training (default: 2 GB). the default 2 GB is also the max, so no going higher ๐
. this is a lifesaver when your training set size is kinda out of control and could be HUGE. training speed is directly tied to sample set size, so smaller = faster ๐๏ธ.
if the training set is bigger than the max memory, the CLI randomly picks samples from what's available, up to the memory budget ๐ฒ. this is so your dictionary isn't biased by clustering, like only grabbing files from the start of a list sorted by modification date or alphabetical order. the randomness is deterministic though, so the same list of files with the same params makes the same dictionary every single time ๐.
๐ชช --dictID=#
A dictionary ID is a locally unique ID. the decoder uses it to check it's using the right dictionary ๐ต๏ธ. by default zstd makes a random 4-byte ID, but you can give an explicit number instead. the dictionary manager needs to make sure it never hands the same ID to two different dictionaries ๐ซก. short numbers are a flex: an ID < 256 only needs 1 byte in the compressed frame header, and an ID < 65536 only needs 2 bytes. both beat the 4-byte default ๐ช.
RFC8878 reserves IDs less than32768and greater than or equal to2\^31, so please don't use those in public ๐ซ.
๐๏ธ --train-cover[=k#,d=#,steps=#,split=#,shrink[=#]]
This picks the params for the default dictionary builder algorithm, which is called cover. here's the tea โ:
- if
disn't specified, it triesd = 6andd = 8 - if
kisn't specified, it triesstepsvalues in the range[50, 2000] - if
stepsisn't specified, the default is40 - if
splitisn't specified, orsplit <= 0, the default is100 - it requires that
d <= k - if the
shrinkflag isn't used, the defaultshrinkDictvalue is0 - if
shrinkisn't specified, the defaultshrinkDictMaxRegressionvalue is1
the vibe is: it selects segments of size k with the highest score to put in the dictionary ๐. a segment's score is the sum of the frequencies of all its subsegments of size d. generally d should be in the range [6, 8], sometimes up to 16, but the algorithm runs faster with d <= 8 โก. good values for k vary a lot based on your input data, but a safe range is [2 * d, 2000]. if split is 100, all input samples get used for both training and testing so it can find the optimal d and k ๐ฏ. it supports multithreading if zstd is compiled with threading support ๐งต.
with shrink enabled, it takes a truncated dictionary of minimum size and doubles in size until its compression ratio is at most shrinkDictMaxRegression% worse than the compression ratio of the largest dictionary ๐.
examples, bestie:
zstd --train-cover FILEs
zstd --train-cover=k=50,d=8 FILEs
zstd --train-cover=d=8,steps=500 FILEs
zstd --train-cover=k=50 FILEs
zstd --train-cover=k=50,split=60 FILEs
zstd --train-cover=shrink FILEs
zstd --train-cover=shrink=2 FILEs
โก --train-fastcover[=k#,d=#,f=#,steps=#,split=#,accel=#]
this is the same as cover, but with extra f and accel params and a different default split ๐โโ๏ธ. if split isn't specified, it tries split = 75. if f isn't specified, it tries f = 20, and it requires that 0 < f < 32. if accel isn't specified, it tries accel = 1, and it requires that 0 < accel <= 10. it also requires that d = 6 or d = 8 ๐ซ .
f is the log of the size of the array that keeps track of how often each subsegment of size d shows up ๐. each subsegment gets hashed to an index in the range [0,2^f - 1]. two different subsegments can hash to the same index, and then they're treated as the same subsegment when computing frequency ๐ฏ. a higher f means fewer collisions, but it takes longer โณ.
examples:
zstd --train-fastcover FILEs
zstd --train-fastcover=d=8,f=15,accel=2 FILEs
๐ฐ๏ธ --train-legacy[=selectivity=#]
uses the legacy dictionary builder algorithm with the given dictionary selectivity (default: 9) ๐. the smaller the selectivity value, the denser the dictionary, which makes it more efficient but lowers its achievable maximum size. --train-legacy=s=# is also accepted ๐
.
examples:
zstd --train-legacy FILEs
zstd --train-legacy=selectivity=8 FILEs
๐ BENCHMARK ๐
the zstd CLI has a benchmarking mode that's perfect for finding good compression params, or just flexing your computer's performance ๐ช. zstd -b [FILE(s)] benchmarks zstd for both compression and decompression at the default compression level ๐ฏ. results depend A LOT on the content being compressed, so keep that in mind ๐. you can pass multiple files to the benchmark, and even a directory with -r DIRECTORY ๐. if you don't give it a FILE, the benchmark uses a procedurally generated lorem ipsum text ๐.
here are the bench options:
-b#โ benchmark file(s) using compression level #-e#โ benchmark file(s) across multiple compression levels, from-b#to-e#(inclusive)-dโ benchmark decompression speed only (you need to provide zstd-compressed content for this one)-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)-Sโ output one benchmark result per input file (default: one consolidated result)-D dictionaryโ benchmark using a dictionary--priority=rtโ set process priority to real-time (Windows)
beyond compression levels, benchmarking plays nice with other params too ๐ซถ. that means number of threads (-T#), advanced compression params (--zstd=###), dictionary compression (-D dictionary), or even disabling checksum verification, for example โจ.
the output looks like this:
CompressionLevel#Filename: InputSize -> OutputSize (CompressionRatio), CompressionSpeed, DecompressionSpeed
and the methodology is: for speed measurement, the entire input gets compressed/decompressed in memory ๐ง . a run lasts at least 1 sec, so when files are tiny, they get compressed/decompressed several times per run to keep the measurements accurate ๐.
๐ SEE ALSO ๐
okay bestie, go check these out ๐: zstdgrep(1), zstdless(1), gzip(1), xz(1) ๐ธ.
the zstandard 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) ๐๐.
๐ BUGS ๐
if something's broken, report it at https://github.com/facebook/zstd/issues ๐๐ฆ.
๐ฉโ๐ป AUTHOR ๐ฉโ๐ป
Yann Collet ๐.
bestie, that's the whole thing ๐ฅน๐. this was zstd 1.5.6, October 2024, and you are now officially a dictionary-building, benchmark-flexing legend ๐งโจ. love you, mwah ๐๐
๐ฆ where this page comes from
- alpine 3.22: zstd-doc 1.5.7-r0 ยท BSD-3-Clause OR GPL-2.0-or-later
- alpine 3.23: zstd-doc 1.5.7-r2 ยท BSD-3-Clause OR GPL-2.0-or-later
- alpine 3.24: zstd-doc 1.5.7-r2 ยท BSD-3-Clause OR GPL-2.0-or-later
- debian trixie: zstd 1.5.7+dfsg-1 ยท BSD-3-Clause OR GPL-2.0-only
- freebsd 15.1: base 15.1
- opensuse-leap 16.0: zstd 1.5.7-160000.2.2 ยท BSD-3-Clause AND GPL-2.0-only
- opensuse-leap 16.0: zstd 1.5.7-160000.2.2 ยท BSD-3-Clause AND GPL-2.0-only
- opensuse-leap 16.0: zstd 1.5.7-160000.2.2 ยท BSD-3-Clause AND GPL-2.0-only
- opensuse-leap 16.0: zstd 1.5.7-160000.2.2 ยท BSD-3-Clause AND GPL-2.0-only
- ubuntu questing: zstd 1.5.7+dfsg-1build2 ยท BSD-3-Clause OR GPL-2.0-only
- ubuntu resolute: zstd 1.5.7+dfsg-3 ยท BSD-3-Clause OR GPL-2.0-only
- ubuntu stonking: zstd 1.5.7+dfsg-4 ยท BSD-3-Clause OR GPL-2.0-only
- ๐ girlified by anthropic/claude-haiku-5.5 on : a language model's rewrite of the original, under its terms