Compare commits

..
1 Commits
Author SHA1 Message Date
Nick Terrell 2d1b4c0706 testing 2017-10-18 15:16:18 -07:00
70 changed files with 2812 additions and 3089 deletions
+5 -32
View File
@@ -5,29 +5,6 @@ sudo: required
dist: trusty dist: trusty
matrix: matrix:
include: include:
# Ubuntu 14.04
- env: Cmd="make cxxtest && make clean && make gnu90build && make clean && make cmakebuild && make clean && make travis-install"
- env: Cmd='make gcc6install && CC=gcc-6 make clean uasan-test'
- env: Cmd='make gcc6install libc6install && CC=gcc-6 make clean uasan-test32'
- env: Cmd='make clang38install && CC=clang-3.8 make clean msan-test'
- env: Cmd='make clang38install && CC=clang-3.8 make clean tsan-test-zstream'
- env: Cmd='make valgrindinstall && make -C tests clean valgrindTest'
- env: Cmd='make arminstall && make armtest'
- env: Cmd='make arminstall && make aarch64test'
- env: Cmd='make ppcinstall && make ppctest'
- env: Cmd='make ppcinstall && make ppc64test'
- env: Cmd='make gpp6install valgrindinstall && make -C zlibWrapper test && make -C zlibWrapper valgrindTest'
- env: Cmd='make gcc6install && CC=gcc-6 make uasan-test-zstd-nolegacy'
- env: Cmd='make gcc6install && CC=gcc-6 make uasan-test-zbuff'
- env: Cmd='make -j uasanregressiontest'
- env: Cmd='make -j msanregressiontest'
- env: Cmd='make -C tests versionsTest && make lz4install && make clean && make -C tests test-lz4'
# OS X Mavericks # OS X Mavericks
- env: Cmd="make test" - env: Cmd="make test"
os: osx os: osx
@@ -49,13 +26,9 @@ branches:
script: script:
- JOB_NUMBER=$(echo $TRAVIS_JOB_NUMBER | sed -e 's:[0-9][0-9]*\.\(.*\):\1:') - JOB_NUMBER=$(echo $TRAVIS_JOB_NUMBER | sed -e 's:[0-9][0-9]*\.\(.*\):\1:')
- echo JOB_NUMBER=$JOB_NUMBER TRAVIS_BRANCH=$TRAVIS_BRANCH TRAVIS_EVENT_TYPE=$TRAVIS_EVENT_TYPE TRAVIS_PULL_REQUEST=$TRAVIS_PULL_REQUEST - echo JOB_NUMBER=$JOB_NUMBER TRAVIS_BRANCH=$TRAVIS_BRANCH TRAVIS_EVENT_TYPE=$TRAVIS_EVENT_TYPE TRAVIS_PULL_REQUEST=$TRAVIS_PULL_REQUEST
- export FUZZERTEST=-T3mn; - export FUZZERTEST=-T5mn;
export ZSTREAM_TESTTIME=-T80s; export ZSTREAM_TESTTIME=-T2mn;
export DECODECORPUS_TESTTIME=-T40s; export DECODECORPUS_TESTTIME=-T1mn;
if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then git fetch origin dev;
date; git checkout -f FETCH_HEAD;
git fetch origin dev;
git checkout -f FETCH_HEAD;
date;
fi;
sh -c "$Cmd" || travis_terminate 1; sh -c "$Cmd" || travis_terminate 1;
+7 -5
View File
@@ -72,12 +72,9 @@ zstdmt:
zlibwrapper: zlibwrapper:
$(MAKE) -C $(ZWRAPDIR) test $(MAKE) -C $(ZWRAPDIR) test
.PHONY: check
check: shortest
.PHONY: test shortest .PHONY: test shortest
test shortest: test shortest:
$(MAKE) -C $(PRGDIR) allVariants MOREFLAGS="-g -DZSTD_DEBUG=1" $(MAKE) -C $(PRGDIR) allVariants
$(MAKE) -C $(TESTDIR) $@ $(MAKE) -C $(TESTDIR) $@
.PHONY: examples .PHONY: examples
@@ -130,6 +127,11 @@ uninstall:
travis-install: travis-install:
$(MAKE) install PREFIX=~/install_test_dir $(MAKE) install PREFIX=~/install_test_dir
.PHONY: gppbuild
gppbuild: clean
g++ -v
CC=g++ $(MAKE) -C programs all CFLAGS="-O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror"
.PHONY: gcc5build .PHONY: gcc5build
gcc5build: clean gcc5build: clean
gcc-5 -v gcc-5 -v
@@ -161,7 +163,7 @@ aarch64build: clean
CC=aarch64-linux-gnu-gcc CFLAGS="-Werror" $(MAKE) allzstd CC=aarch64-linux-gnu-gcc CFLAGS="-Werror" $(MAKE) allzstd
ppcbuild: clean ppcbuild: clean
CC=powerpc-linux-gnu-gcc CFLAGS="-m32 -Wno-attributes -Werror" $(MAKE) allzstd CC=powerpc-linux-gnu-gcc CLAGS="-m32 -Wno-attributes -Werror" $(MAKE) allzstd
ppc64build: clean ppc64build: clean
CC=powerpc-linux-gnu-gcc CFLAGS="-m64 -Werror" $(MAKE) allzstd CC=powerpc-linux-gnu-gcc CFLAGS="-m64 -Werror" $(MAKE) allzstd
-12
View File
@@ -1,15 +1,3 @@
v1.3.3
perf: faster zstd_opt strategy (levels 17-19)
fix : bug #944 : multithreading with shared ditionary and large data, reported by @gsliepen
cli : fix : content size written in header by default
cli : fix : improved LZ4 format support, by @felixhandte
cli : new : hidden command `-S`, to benchmark multiple files while generating one result per file
api : fix : support large skippable frames, by @terrelln
api : fix : streaming interface was adding a useless 3-bytes null block to small frames
api : change : when setting `pledgedSrcSize`, use `ZSTD_CONTENTSIZE_UNKNOWN` macro value to mean "unknown"
build: fix : compilation under rhel6 and centos6, reported by @pixelb
build: added `check` target
v1.3.2 v1.3.2
new : long range mode, using --long command, by Stella Lau (@stellamplau) new : long range mode, using --long command, by Stella Lau (@stellamplau)
new : ability to generate and decode magicless frames (#591) new : ability to generate and decode magicless frames (#591)
+32 -29
View File
@@ -1,15 +1,14 @@
<p align="center"><img src="https://raw.githubusercontent.com/facebook/zstd/readme/doc/images/zstd_logo86.png" alt="Zstandard"></p> __Zstandard__, or `zstd` as short version, is a fast lossless compression algorithm,
targeting real-time compression scenarios at zlib-level and better compression ratios.
__Zstandard__, or `zstd` as short version, is a fast lossless compression algorithm, It is provided as an open-source BSD-licensed **C** library,
targeting real-time compression scenarios at zlib-level and better compression ratios. and a command line utility producing and decoding `.zst` and `.gz` files.
It's backed by a very fast entropy stage, provided by [Huff0 and FSE library](https://github.com/Cyan4973/FiniteStateEntropy). For other programming languages,
you can consult a list of known ports on [Zstandard homepage](http://www.zstd.net/#other-languages).
The project is provided as an open-source BSD-licensed **C** library, | dev branch status |
and a command line utility producing and decoding `.zst`, `.gz`, `.xz` and `.lz4` files. |-------------------|
Should your project require another programming language, | [![Build Status][travisDevBadge]][travisLink] [![Build status][AppveyorDevBadge]][AppveyorLink] [![Build status][CircleDevBadge]][CircleLink]
a list of known ports and bindings is provided on [Zstandard homepage](http://www.zstd.net/#other-languages).
Development branch status : [![Build Status][travisDevBadge]][travisLink] [![Build status][AppveyorDevBadge]][AppveyorLink] [![Build status][CircleDevBadge]][CircleLink]
[travisDevBadge]: https://travis-ci.org/facebook/zstd.svg?branch=dev "Continuous Integration test suite" [travisDevBadge]: https://travis-ci.org/facebook/zstd.svg?branch=dev "Continuous Integration test suite"
[travisLink]: https://travis-ci.org/facebook/zstd [travisLink]: https://travis-ci.org/facebook/zstd
@@ -18,9 +17,8 @@ Development branch status : [![Build Status][travisDevBadge]][travisLink] [![B
[CircleDevBadge]: https://circleci.com/gh/facebook/zstd/tree/dev.svg?style=shield "Short test suite" [CircleDevBadge]: https://circleci.com/gh/facebook/zstd/tree/dev.svg?style=shield "Short test suite"
[CircleLink]: https://circleci.com/gh/facebook/zstd [CircleLink]: https://circleci.com/gh/facebook/zstd
### Benchmarks
For reference, several fast compression algorithms were tested and compared As a reference, several fast compression algorithms were tested and compared
on a server running Linux Debian (`Linux version 4.8.0-1-amd64`), on a server running Linux Debian (`Linux version 4.8.0-1-amd64`),
with a Core i7-6700K CPU @ 4.0GHz, with a Core i7-6700K CPU @ 4.0GHz,
using [lzbench], an open-source in-memory benchmark by @inikep using [lzbench], an open-source in-memory benchmark by @inikep
@@ -45,9 +43,7 @@ on the [Silesia compression corpus].
[LZ4]: http://www.lz4.org/ [LZ4]: http://www.lz4.org/
Zstd can also offer stronger compression ratios at the cost of compression speed. Zstd can also offer stronger compression ratios at the cost of compression speed.
Speed vs Compression trade-off is configurable by small increments. Speed vs Compression trade-off is configurable by small increments. Decompression speed is preserved and remains roughly the same at all settings, a property shared by most LZ compression algorithms, such as [zlib] or lzma.
Decompression speed is preserved and remains roughly the same at all settings,
a property shared by most LZ compression algorithms, such as [zlib] or lzma.
The following tests were run The following tests were run
on a server running Linux Debian (`Linux version 4.8.0-1-amd64`) on a server running Linux Debian (`Linux version 4.8.0-1-amd64`)
@@ -60,8 +56,8 @@ Compression Speed vs Ratio | Decompression Speed
---------------------------|-------------------- ---------------------------|--------------------
![Compression Speed vs Ratio](doc/images/Cspeed4.png "Compression Speed vs Ratio") | ![Decompression Speed](doc/images/Dspeed4.png "Decompression Speed") ![Compression Speed vs Ratio](doc/images/Cspeed4.png "Compression Speed vs Ratio") | ![Decompression Speed](doc/images/Dspeed4.png "Decompression Speed")
A few other algorithms can produce higher compression ratios at slower speeds, falling outside of the graph. Several algorithms can produce higher compression ratios, but at slower speeds, falling outside of the graph.
For a larger picture including slow modes, [click on this link](doc/images/DCspeed5.png). For a larger picture including very slow modes, [click on this link](doc/images/DCspeed5.png) .
### The case for Small Data compression ### The case for Small Data compression
@@ -88,7 +84,7 @@ Training works if there is some correlation in a family of small data samples. T
Hence, deploying one dictionary per type of data will provide the greatest benefits. Hence, deploying one dictionary per type of data will provide the greatest benefits.
Dictionary gains are mostly effective in the first few KB. Then, the compression algorithm will gradually use previously decoded content to better compress the rest of the file. Dictionary gains are mostly effective in the first few KB. Then, the compression algorithm will gradually use previously decoded content to better compress the rest of the file.
#### Dictionary compression How To: #### Dictionary compression How To :
1) Create the dictionary 1) Create the dictionary
@@ -103,16 +99,19 @@ Dictionary gains are mostly effective in the first few KB. Then, the compression
`zstd -D dictionaryName --decompress FILE.zst` `zstd -D dictionaryName --decompress FILE.zst`
### Build instructions ### Build
Once you have the repository cloned, there are multiple ways provided to build Zstandard.
#### Makefile #### Makefile
If your system is compatible with standard `make` (or `gmake`), If your system is compatible with a standard `make` (or `gmake`) binary generator,
invoking `make` in root directory will generate `zstd` cli in root directory. you can simply run it at the root directory.
It will generate `zstd` within root directory.
Other available options include: Other available options include :
- `make install` : create and install zstd cli, library and man pages - `make install` : create and install zstd binary, library and man page
- `make check` : create and run `zstd`, tests its behavior on local platform - `make test` : create and run `zstd` and test tools on local platform
#### cmake #### cmake
@@ -126,9 +125,9 @@ A Meson project is provided within `contrib/meson`.
#### Visual Studio (Windows) #### Visual Studio (Windows)
Going into `build` directory, you will find additional possibilities: Going into `build` directory, you will find additional possibilities :
- Projects for Visual Studio 2005, 2008 and 2010. - Projects for Visual Studio 2005, 2008 and 2010
+ VS2010 project is compatible with VS2012, VS2013 and VS2015. + VS2010 project is compatible with VS2012, VS2013 and VS2015
- Automated build scripts for Visual compiler by @KrzysFR , in `build/VS_scripts`, - Automated build scripts for Visual compiler by @KrzysFR , in `build/VS_scripts`,
which will build `zstd` cli and `libzstd` library without any need to open Visual Studio solution. which will build `zstd` cli and `libzstd` library without any need to open Visual Studio solution.
@@ -144,7 +143,11 @@ Zstandard is dual-licensed under [BSD](LICENSE) and [GPLv2](COPYING).
### Contributing ### Contributing
The "dev" branch is the one where all contributions are merged before reaching "master". The "dev" branch is the one where all contributions will be merged before reaching "master".
If you plan to propose a patch, please commit into the "dev" branch, or its own feature branch. If you plan to propose a patch, please commit into the "dev" branch or its own feature branch.
Direct commit to "master" are not permitted. Direct commit to "master" are not permitted.
For more information, please read [CONTRIBUTING](CONTRIBUTING.md). For more information, please read [CONTRIBUTING](CONTRIBUTING.md).
### Miscellaneous
Zstd entropy stage is provided by [Huff0 and FSE, from Finite State Entropy library](https://github.com/Cyan4973/FiniteStateEntropy).
+1 -1
View File
@@ -63,7 +63,7 @@ SET(Headers
${LIBRARY_DIR}/common/huf.h ${LIBRARY_DIR}/common/huf.h
${LIBRARY_DIR}/common/mem.h ${LIBRARY_DIR}/common/mem.h
${LIBRARY_DIR}/common/zstd_internal.h ${LIBRARY_DIR}/common/zstd_internal.h
${LIBRARY_DIR}/compress/zstd_compress_internal.h ${LIBRARY_DIR}/compress/zstd_compress.h
${LIBRARY_DIR}/compress/zstd_fast.h ${LIBRARY_DIR}/compress/zstd_fast.h
${LIBRARY_DIR}/compress/zstd_double_fast.h ${LIBRARY_DIR}/compress/zstd_double_fast.h
${LIBRARY_DIR}/compress/zstd_lazy.h ${LIBRARY_DIR}/compress/zstd_lazy.h
+23 -6
View File
@@ -3,11 +3,13 @@ dependencies:
- sudo dpkg --add-architecture i386 - sudo dpkg --add-architecture i386
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; sudo apt-get -y -qq update - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; sudo apt-get -y -qq update
- sudo apt-get -y install gcc-powerpc-linux-gnu gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross - sudo apt-get -y install gcc-powerpc-linux-gnu gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross
- sudo apt-get -y install libstdc++-7-dev clang gcc g++ gcc-5 gcc-6 gcc-7 zlib1g-dev liblzma-dev
- sudo apt-get -y install linux-libc-dev:i386 libc6-dev-i386
test: test:
override: override:
- ? | - ? |
if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then cc -v; CFLAGS="-O0 -Werror" make all && make clean; fi && if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then cc -v; make all && make clean && make -C lib libzstd-nomt && make clean; fi &&
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make gnu90build && make clean; fi if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make gnu90build && make clean; fi
: :
parallel: true parallel: true
@@ -18,7 +20,22 @@ test:
parallel: true parallel: true
- ? | - ? |
if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then make c11build && make clean; fi && if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then make c11build && make clean; fi &&
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make ppc64build && make clean; fi if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make cmakebuild && make clean; fi
:
parallel: true
- ? |
if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then make gppbuild && make clean; fi &&
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make gcc5build && make clean; fi
:
parallel: true
- ? |
if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then make gcc6build && make clean; fi &&
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make clangbuild && make clean; fi
:
parallel: true
- ? |
if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then make m32build && make clean; fi &&
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make armbuild && make clean; fi
: :
parallel: true parallel: true
- ? | - ? |
@@ -27,8 +44,8 @@ test:
: :
parallel: true parallel: true
- ? | - ? |
if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then make -j regressiontest && make clean; fi && if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then make ppc64build && make clean; fi &&
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make armbuild && make clean; fi if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make gcc7build && make clean; fi
: :
parallel: true parallel: true
- ? | - ? |
@@ -37,8 +54,8 @@ test:
: :
parallel: true parallel: true
- ? | - ? |
if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then make cxxtest && make clean; fi && if [[ "$CIRCLE_NODE_INDEX" == "0" ]] ; then make -j regressiontest && make clean; fi &&
if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then make -C lib libzstd-nomt && make clean; fi if [[ "$CIRCLE_NODE_TOTAL" < "2" ]] || [[ "$CIRCLE_NODE_INDEX" == "1" ]]; then true; fi # Could add another test here
: :
parallel: true parallel: true
+2 -1
View File
@@ -141,7 +141,7 @@ static LDM_hashEntry *getBucket(const LDM_hashTable *table, const hash_t hash) {
return table->entries + (hash << HASH_BUCKET_SIZE_LOG); return table->entries + (hash << HASH_BUCKET_SIZE_LOG);
} }
static unsigned ZSTD_NbCommonBytes (size_t val) { static unsigned ZSTD_NbCommonBytes (register size_t val) {
if (MEM_isLittleEndian()) { if (MEM_isLittleEndian()) {
if (MEM_64bits()) { if (MEM_64bits()) {
# if defined(_MSC_VER) && defined(_WIN64) # if defined(_MSC_VER) && defined(_WIN64)
@@ -854,3 +854,4 @@ void LDM_outputConfiguration(void) {
printf("HASH_CHAR_OFFSET: %d\n", HASH_CHAR_OFFSET); printf("HASH_CHAR_OFFSET: %d\n", HASH_CHAR_OFFSET);
printf("=====================\n"); printf("=====================\n");
} }
+6 -43
View File
@@ -2,39 +2,14 @@ project('zstd', 'c', license: 'BSD')
libm = meson.get_compiler('c').find_library('m', required: true) libm = meson.get_compiler('c').find_library('m', required: true)
lib_dir = join_paths('..', '..', 'lib') lib_dir = join_paths(meson.source_root(), '..', '..', 'lib')
common_dir = join_paths(lib_dir, 'common') common_dir = join_paths(lib_dir, 'common')
compress_dir = join_paths(lib_dir, 'compress') compress_dir = join_paths(lib_dir, 'compress')
decompress_dir = join_paths(lib_dir, 'decompress') decompress_dir = join_paths(lib_dir, 'decompress')
dictbuilder_dir = join_paths(lib_dir, 'dictBuilder') dictbuilder_dir = join_paths(lib_dir, 'dictBuilder')
deprecated_dir = join_paths(lib_dir, 'deprecated') deprecated_dir = join_paths(lib_dir, 'deprecated')
libzstd_srcs = [ libzstd_srcs = [join_paths(common_dir, 'entropy_common.c'), join_paths(common_dir, 'fse_decompress.c'), join_paths(common_dir, 'threading.c'), join_paths(common_dir, 'pool.c'), join_paths(common_dir, 'zstd_common.c'), join_paths(common_dir, 'error_private.c'), join_paths(common_dir, 'xxhash.c'), join_paths(compress_dir, 'fse_compress.c'), join_paths(compress_dir, 'huf_compress.c'), join_paths(compress_dir, 'zstd_compress.c'), join_paths(compress_dir, 'zstdmt_compress.c'), join_paths(decompress_dir, 'huf_decompress.c'), join_paths(decompress_dir, 'zstd_decompress.c'), join_paths(dictbuilder_dir, 'cover.c'), join_paths(dictbuilder_dir, 'divsufsort.c'), join_paths(dictbuilder_dir, 'zdict.c'), join_paths(deprecated_dir, 'zbuff_common.c'), join_paths(deprecated_dir, 'zbuff_compress.c'), join_paths(deprecated_dir, 'zbuff_decompress.c')]
join_paths(common_dir, 'entropy_common.c'),
join_paths(common_dir, 'fse_decompress.c'),
join_paths(common_dir, 'threading.c'),
join_paths(common_dir, 'pool.c'),
join_paths(common_dir, 'zstd_common.c'),
join_paths(common_dir, 'error_private.c'),
join_paths(common_dir, 'xxhash.c'),
join_paths(compress_dir, 'fse_compress.c'),
join_paths(compress_dir, 'huf_compress.c'),
join_paths(compress_dir, 'zstd_compress.c'),
join_paths(compress_dir, 'zstd_fast.c'),
join_paths(compress_dir, 'zstd_double_fast.c'),
join_paths(compress_dir, 'zstd_lazy.c'),
join_paths(compress_dir, 'zstd_opt.c'),
join_paths(compress_dir, 'zstd_ldm.c'),
join_paths(compress_dir, 'zstdmt_compress.c'),
join_paths(decompress_dir, 'huf_decompress.c'),
join_paths(decompress_dir, 'zstd_decompress.c'),
join_paths(dictbuilder_dir, 'cover.c'),
join_paths(dictbuilder_dir, 'divsufsort.c'),
join_paths(dictbuilder_dir, 'zdict.c'),
join_paths(deprecated_dir, 'zbuff_common.c'),
join_paths(deprecated_dir, 'zbuff_compress.c'),
join_paths(deprecated_dir, 'zbuff_decompress.c')
]
libzstd_includes = [include_directories(common_dir, dictbuilder_dir, compress_dir, lib_dir)] libzstd_includes = [include_directories(common_dir, dictbuilder_dir, compress_dir, lib_dir)]
@@ -44,15 +19,7 @@ if get_option('legacy_support')
legacy_dir = join_paths(lib_dir, 'legacy') legacy_dir = join_paths(lib_dir, 'legacy')
libzstd_includes += [include_directories(legacy_dir)] libzstd_includes += [include_directories(legacy_dir)]
libzstd_srcs += [ libzstd_srcs += [join_paths(legacy_dir, 'zstd_v01.c'), join_paths(legacy_dir, 'zstd_v02.c'), join_paths(legacy_dir, 'zstd_v03.c'), join_paths(legacy_dir, 'zstd_v04.c'), join_paths(legacy_dir, 'zstd_v05.c'), join_paths(legacy_dir, 'zstd_v06.c'), join_paths(legacy_dir, 'zstd_v07.c')]
join_paths(legacy_dir, 'zstd_v01.c'),
join_paths(legacy_dir, 'zstd_v02.c'),
join_paths(legacy_dir, 'zstd_v03.c'),
join_paths(legacy_dir, 'zstd_v04.c'),
join_paths(legacy_dir, 'zstd_v05.c'),
join_paths(legacy_dir, 'zstd_v06.c'),
join_paths(legacy_dir, 'zstd_v07.c')
]
else else
libzstd_cflags = [] libzstd_cflags = []
endif endif
@@ -72,20 +39,16 @@ libzstd = library('zstd',
dependencies: libzstd_deps, dependencies: libzstd_deps,
install: true) install: true)
programs_dir = join_paths('..', '..', 'programs') programs_dir = join_paths(meson.source_root(), '..', '..', 'programs')
zstd = executable('zstd', zstd = executable('zstd',
join_paths(programs_dir, 'bench.c'), join_paths(programs_dir, 'bench.c'), join_paths(programs_dir, 'datagen.c'), join_paths(programs_dir, 'dibio.c'), join_paths(programs_dir, 'fileio.c'), join_paths(programs_dir, 'zstdcli.c'),
join_paths(programs_dir, 'datagen.c'),
join_paths(programs_dir, 'dibio.c'),
join_paths(programs_dir, 'fileio.c'),
join_paths(programs_dir, 'zstdcli.c'),
include_directories: libzstd_includes, include_directories: libzstd_includes,
c_args: ['-DZSTD_NODICT', '-DZSTD_NOBENCH'], c_args: ['-DZSTD_NODICT', '-DZSTD_NOBENCH'],
link_with: libzstd, link_with: libzstd,
install: true) install: true)
tests_dir = join_paths('..', '..', 'tests') tests_dir = join_paths(meson.source_root(), '..', '..', 'tests')
datagen_c = join_paths(programs_dir, 'datagen.c') datagen_c = join_paths(programs_dir, 'datagen.c')
test_includes = libzstd_includes + [include_directories(programs_dir)] test_includes = libzstd_includes + [include_directories(programs_dir)]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

+3 -3
View File
@@ -91,10 +91,10 @@ Overview
Frames Frames
------ ------
Zstandard compressed data is made of one or more __frames__. Zstandard compressed data is made of up one or more __frames__.
Each frame is independent and can be decompressed indepedently of other frames. Each frame is independent and can be decompressed indepedently of other frames.
The decompressed content of multiple concatenated frames is the concatenation of The decompressed content of multiple concatenated frames is the concatenation of
each frame decompressed content. each frames decompressed content.
There are two frame formats defined by Zstandard: There are two frame formats defined by Zstandard:
Zstandard frames and Skippable frames. Zstandard frames and Skippable frames.
@@ -182,7 +182,7 @@ data must be regenerated within a single continuous memory segment.
In this case, `Window_Descriptor` byte is skipped, In this case, `Window_Descriptor` byte is skipped,
but `Frame_Content_Size` is necessarily present. but `Frame_Content_Size` is necessarily present.
As a consequence, the decoder must allocate a memory segment As a consequence, the decoder must allocate a memory segment
of size equal or larger than `Frame_Content_Size`. of size equal or bigger than `Frame_Content_Size`.
In order to preserve the decoder from unreasonable memory requirements, In order to preserve the decoder from unreasonable memory requirements,
a decoder is allowed to reject a compressed frame a decoder is allowed to reject a compressed frame
+54 -66
View File
@@ -1,10 +1,10 @@
<html> <html>
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>zstd 1.3.3 Manual</title> <title>zstd 1.3.2 Manual</title>
</head> </head>
<body> <body>
<h1>zstd 1.3.3 Manual</h1> <h1>zstd 1.3.2 Manual</h1>
<hr> <hr>
<a name="Contents"></a><h2>Contents</h2> <a name="Contents"></a><h2>Contents</h2>
<ol> <ol>
@@ -19,17 +19,16 @@
<li><a href="#Chapter9">Streaming decompression - HowTo</a></li> <li><a href="#Chapter9">Streaming decompression - HowTo</a></li>
<li><a href="#Chapter10">START OF ADVANCED AND EXPERIMENTAL FUNCTIONS</a></li> <li><a href="#Chapter10">START OF ADVANCED AND EXPERIMENTAL FUNCTIONS</a></li>
<li><a href="#Chapter11">Advanced types</a></li> <li><a href="#Chapter11">Advanced types</a></li>
<li><a href="#Chapter12">Custom memory allocation functions</a></li> <li><a href="#Chapter12">Frame size functions</a></li>
<li><a href="#Chapter13">Frame size functions</a></li> <li><a href="#Chapter13">Context memory usage</a></li>
<li><a href="#Chapter14">Context memory usage</a></li> <li><a href="#Chapter14">Advanced compression functions</a></li>
<li><a href="#Chapter15">Advanced compression functions</a></li> <li><a href="#Chapter15">Advanced decompression functions</a></li>
<li><a href="#Chapter16">Advanced decompression functions</a></li> <li><a href="#Chapter16">Advanced streaming functions</a></li>
<li><a href="#Chapter17">Advanced streaming functions</a></li> <li><a href="#Chapter17">Buffer-less and synchronous inner streaming functions</a></li>
<li><a href="#Chapter18">Buffer-less and synchronous inner streaming functions</a></li> <li><a href="#Chapter18">Buffer-less streaming compression (synchronous mode)</a></li>
<li><a href="#Chapter19">Buffer-less streaming compression (synchronous mode)</a></li> <li><a href="#Chapter19">Buffer-less streaming decompression (synchronous mode)</a></li>
<li><a href="#Chapter20">Buffer-less streaming decompression (synchronous mode)</a></li> <li><a href="#Chapter20">New advanced API (experimental)</a></li>
<li><a href="#Chapter21">New advanced API (experimental)</a></li> <li><a href="#Chapter21">Block level API</a></li>
<li><a href="#Chapter22">Block level API</a></li>
</ol> </ol>
<hr> <hr>
<a name="Chapter1"></a><h2>Introduction</h2><pre> <a name="Chapter1"></a><h2>Introduction</h2><pre>
@@ -112,7 +111,7 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
@return : content size to be decompressed, as a 64-bits value _if known and not empty_, 0 otherwise. @return : content size to be decompressed, as a 64-bits value _if known and not empty_, 0 otherwise.
</p></pre><BR> </p></pre><BR>
<h3>Helper functions</h3><pre></pre><b><pre>#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) </b>/* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */<b> <h3>Helper functions</h3><pre></pre><b><pre>#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < 128 KB) ? ((128 KB - (srcSize)) >> 11) </b>/* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */<b>
size_t ZSTD_compressBound(size_t srcSize); </b>/*!< maximum compressed size in worst case scenario */<b> size_t ZSTD_compressBound(size_t srcSize); </b>/*!< maximum compressed size in worst case scenario */<b>
unsigned ZSTD_isError(size_t code); </b>/*!< tells if a `size_t` function result is an error code */<b> unsigned ZSTD_isError(size_t code); </b>/*!< tells if a `size_t` function result is an error code */<b>
const char* ZSTD_getErrorName(size_t code); </b>/*!< provides readable string from an error code */<b> const char* ZSTD_getErrorName(size_t code); </b>/*!< provides readable string from an error code */<b>
@@ -347,15 +346,17 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
ZSTD_frameParameters fParams; ZSTD_frameParameters fParams;
} ZSTD_parameters; } ZSTD_parameters;
</b></pre><BR> </b></pre><BR>
<a name="Chapter12"></a><h2>Custom memory allocation functions</h2><pre></pre> <h3>Custom memory allocation functions</h3><pre></pre><b><pre>typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size);
typedef void (*ZSTD_freeFunction) (void* opaque, void* address);
<pre><b>typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem;
</b></pre><BR> </b>/* use this constant to defer to stdlib's functions */<b>
<a name="Chapter13"></a><h2>Frame size functions</h2><pre></pre> static const ZSTD_customMem ZSTD_defaultCMem = { NULL, NULL, NULL };
</pre></b><BR>
<a name="Chapter12"></a><h2>Frame size functions</h2><pre></pre>
<pre><b>size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize); <pre><b>size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize);
</b><p> `src` should point to the start of a ZSTD encoded frame or skippable frame </b><p> `src` should point to the start of a ZSTD encoded frame or skippable frame
`srcSize` must be >= first frame size `srcSize` must be at least as large as the frame
@return : the compressed size of the first frame starting at `src`, @return : the compressed size of the first frame starting at `src`,
suitable to pass to `ZSTD_decompress` or similar, suitable to pass to `ZSTD_decompress` or similar,
or an error code if input is invalid or an error code if input is invalid
@@ -390,7 +391,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
@return : size of the Frame Header @return : size of the Frame Header
</p></pre><BR> </p></pre><BR>
<a name="Chapter14"></a><h2>Context memory usage</h2><pre></pre> <a name="Chapter13"></a><h2>Context memory usage</h2><pre></pre>
<pre><b>size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); <pre><b>size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);
size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx); size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);
@@ -449,7 +450,7 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
</p></pre><BR> </p></pre><BR>
<a name="Chapter15"></a><h2>Advanced compression functions</h2><pre></pre> <a name="Chapter14"></a><h2>Advanced compression functions</h2><pre></pre>
<pre><b>ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); <pre><b>ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
</b><p> Create a ZSTD compression context using external alloc and free functions </b><p> Create a ZSTD compression context using external alloc and free functions
@@ -461,8 +462,7 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
It must outlive context usage. It must outlive context usage.
workspaceSize: Use ZSTD_estimateCCtxSize() or ZSTD_estimateCStreamSize() workspaceSize: Use ZSTD_estimateCCtxSize() or ZSTD_estimateCStreamSize()
to determine how large workspace must be to support scenario. to determine how large workspace must be to support scenario.
@return : pointer to ZSTD_CCtx* (same address as workspace, but different type), @return : pointer to ZSTD_CCtx*, or NULL if error (size too small)
or NULL if error (typically size too small)
Note : zstd will never resize nor malloc() when using a static cctx. Note : zstd will never resize nor malloc() when using a static cctx.
If it needs more memory than available, it will simply error out. If it needs more memory than available, it will simply error out.
Note 2 : there is no corresponding "free" function. Note 2 : there is no corresponding "free" function.
@@ -505,8 +505,7 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
to determine how large workspace must be. to determine how large workspace must be.
cParams : use ZSTD_getCParams() to transform a compression level cParams : use ZSTD_getCParams() to transform a compression level
into its relevants cParams. into its relevants cParams.
@return : pointer to ZSTD_CDict* (same address as workspace, but different type), @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
or NULL if error (typically, size too small).
Note : there is no corresponding "free" function. Note : there is no corresponding "free" function.
Since workspace was allocated externally, it must be freed externally. Since workspace was allocated externally, it must be freed externally.
@@ -519,7 +518,7 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
<pre><b>ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); <pre><b>ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
</b><p> same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`. </b><p> same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`.
All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 All fields of `ZSTD_frameParameters` are set to default (0)
</p></pre><BR> </p></pre><BR>
<pre><b>size_t ZSTD_checkCParams(ZSTD_compressionParameters params); <pre><b>size_t ZSTD_checkCParams(ZSTD_compressionParameters params);
@@ -546,7 +545,7 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
</b><p> Same as ZSTD_compress_usingCDict(), with fine-tune control over frame parameters </b><p> Same as ZSTD_compress_usingCDict(), with fine-tune control over frame parameters
</p></pre><BR> </p></pre><BR>
<a name="Chapter16"></a><h2>Advanced decompression functions</h2><pre></pre> <a name="Chapter15"></a><h2>Advanced decompression functions</h2><pre></pre>
<pre><b>unsigned ZSTD_isFrame(const void* buffer, size_t size); <pre><b>unsigned ZSTD_isFrame(const void* buffer, size_t size);
</b><p> Tells if the content of `buffer` starts with a valid Frame Identifier. </b><p> Tells if the content of `buffer` starts with a valid Frame Identifier.
@@ -565,8 +564,7 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
It must outlive context usage. It must outlive context usage.
workspaceSize: Use ZSTD_estimateDCtxSize() or ZSTD_estimateDStreamSize() workspaceSize: Use ZSTD_estimateDCtxSize() or ZSTD_estimateDStreamSize()
to determine how large workspace must be to support scenario. to determine how large workspace must be to support scenario.
@return : pointer to ZSTD_DCtx* (same address as workspace, but different type), @return : pointer to ZSTD_DCtx*, or NULL if error (size too small)
or NULL if error (typically size too small)
Note : zstd will never resize nor malloc() when using a static dctx. Note : zstd will never resize nor malloc() when using a static dctx.
If it needs more memory than available, it will simply error out. If it needs more memory than available, it will simply error out.
Note 2 : static dctx is incompatible with legacy support Note 2 : static dctx is incompatible with legacy support
@@ -629,26 +627,24 @@ size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMet
When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code. When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code.
</p></pre><BR> </p></pre><BR>
<a name="Chapter17"></a><h2>Advanced streaming functions</h2><pre></pre> <a name="Chapter16"></a><h2>Advanced streaming functions</h2><pre></pre>
<h3>Advanced Streaming compression functions</h3><pre></pre><b><pre>ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); <h3>Advanced Streaming compression functions</h3><pre></pre><b><pre>ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); </b>/**< same as ZSTD_initStaticCCtx() */<b> ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); </b>/**< same as ZSTD_initStaticCCtx() */<b>
size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); </b>/**< pledgedSrcSize must be correct. If it is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, "0" also disables frame content size field. It may be enabled in the future. */<b> size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); </b>/**< pledgedSrcSize must be correct, a size of 0 means unknown. for a frame size of 0 use initCStream_advanced */<b>
size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); </b>/**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/<b> size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); </b>/**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/<b>
size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
ZSTD_parameters params, unsigned long long pledgedSrcSize); </b>/**< pledgedSrcSize must be correct. If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. dict is loaded with ZSTD_dm_auto and ZSTD_dlm_byCopy. */<b> ZSTD_parameters params, unsigned long long pledgedSrcSize); </b>/**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0. dict is loaded with ZSTD_dm_auto and ZSTD_dlm_byCopy. */<b>
size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); </b>/**< note : cdict will just be referenced, and must outlive compression session */<b> size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); </b>/**< note : cdict will just be referenced, and must outlive compression session */<b>
size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize); </b>/**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters. pledgedSrcSize must be correct. If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. */<b> size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize); </b>/**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters */<b>
</pre></b><BR> </pre></b><BR>
<pre><b>size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); <pre><b>size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
</b><p> start a new compression job, using same parameters from previous job. </b><p> start a new compression job, using same parameters from previous job.
This is typically useful to skip dictionary loading stage, since it will re-use it in-place.. This is typically useful to skip dictionary loading stage, since it will re-use it in-place..
Note that zcs must be init at least once before using ZSTD_resetCStream(). Note that zcs must be init at least once before using ZSTD_resetCStream().
If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN. pledgedSrcSize==0 means "srcSize unknown".
If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end. If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end.
For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs, @return : 0, or an error code (which can be tested using ZSTD_isError())
but it may change to mean "empty" in some future version, so prefer using macro ZSTD_CONTENTSIZE_UNKNOWN.
@return : 0, or an error code (which can be tested using ZSTD_isError())
</p></pre><BR> </p></pre><BR>
<h3>Advanced Streaming decompression functions</h3><pre></pre><b><pre>ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); <h3>Advanced Streaming decompression functions</h3><pre></pre><b><pre>ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);
@@ -659,14 +655,14 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di
size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); </b>/**< note : ddict is referenced, it must outlive decompression session */<b> size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); </b>/**< note : ddict is referenced, it must outlive decompression session */<b>
size_t ZSTD_resetDStream(ZSTD_DStream* zds); </b>/**< re-use decompression parameters from previous init; saves dictionary loading */<b> size_t ZSTD_resetDStream(ZSTD_DStream* zds); </b>/**< re-use decompression parameters from previous init; saves dictionary loading */<b>
</pre></b><BR> </pre></b><BR>
<a name="Chapter18"></a><h2>Buffer-less and synchronous inner streaming functions</h2><pre> <a name="Chapter17"></a><h2>Buffer-less and synchronous inner streaming functions</h2><pre>
This is an advanced API, giving full control over buffer management, for users which need direct control over memory. This is an advanced API, giving full control over buffer management, for users which need direct control over memory.
But it's also a complex one, with several restrictions, documented below. But it's also a complex one, with several restrictions, documented below.
Prefer normal streaming API for an easier experience. Prefer normal streaming API for an easier experience.
<BR></pre> <BR></pre>
<a name="Chapter19"></a><h2>Buffer-less streaming compression (synchronous mode)</h2><pre> <a name="Chapter18"></a><h2>Buffer-less streaming compression (synchronous mode)</h2><pre>
A ZSTD_CCtx object is required to track streaming operations. A ZSTD_CCtx object is required to track streaming operations.
Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource. Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource.
ZSTD_CCtx object can be re-used multiple times within successive compression operations. ZSTD_CCtx object can be re-used multiple times within successive compression operations.
@@ -697,12 +693,12 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds); </b>/**< re-use decompression para
<h3>Buffer-less streaming compression functions</h3><pre></pre><b><pre>size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); <h3>Buffer-less streaming compression functions</h3><pre></pre><b><pre>size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); </b>/**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */<b> size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); </b>/**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0 */<b>
size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); </b>/**< note: fails if cdict==NULL */<b> size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); </b>/**< note: fails if cdict==NULL */<b>
size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); </b>/* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */<b> size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); </b>/* compression parameters are already set within cdict. pledgedSrcSize=0 means null-size */<b>
size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); </b>/**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */<b> size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); </b>/**< note: if pledgedSrcSize can be 0, indicating unknown size. if it is non-zero, it must be accurate. for 0 size frames, use compressBegin_advanced */<b>
</pre></b><BR> </pre></b><BR>
<a name="Chapter20"></a><h2>Buffer-less streaming decompression (synchronous mode)</h2><pre> <a name="Chapter19"></a><h2>Buffer-less streaming decompression (synchronous mode)</h2><pre>
A ZSTD_DCtx object is required to track streaming operations. A ZSTD_DCtx object is required to track streaming operations.
Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it.
A ZSTD_DCtx object can be re-used multiple times. A ZSTD_DCtx object can be re-used multiple times.
@@ -788,7 +784,7 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
</pre></b><BR> </pre></b><BR>
<pre><b>typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; <pre><b>typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e;
</b></pre><BR> </b></pre><BR>
<a name="Chapter21"></a><h2>New advanced API (experimental)</h2><pre></pre> <a name="Chapter20"></a><h2>New advanced API (experimental)</h2><pre></pre>
<pre><b>typedef enum { <pre><b>typedef enum {
</b>/* Question : should we have a format ZSTD_f_auto ?<b> </b>/* Question : should we have a format ZSTD_f_auto ?<b>
@@ -852,19 +848,18 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
* Special: value 0 means "do not change strategy". */ * Special: value 0 means "do not change strategy". */
</b>/* frame parameters */<b> </b>/* frame parameters */<b>
ZSTD_p_contentSizeFlag=200, </b>/* Content size will be written into frame header _whenever known_ (default:1)<b> ZSTD_p_contentSizeFlag=200, </b>/* Content size is written into frame header _whenever known_ (default:1)<b>
* Content size must be known at the beginning of compression, * note that content size must be known at the beginning,
* it is provided using ZSTD_CCtx_setPledgedSrcSize() */ * it is sent using ZSTD_CCtx_setPledgedSrcSize() */
ZSTD_p_checksumFlag, </b>/* A 32-bits checksum of content is written at end of frame (default:0) */<b> ZSTD_p_checksumFlag, </b>/* A 32-bits checksum of content is written at end of frame (default:0) */<b>
ZSTD_p_dictIDFlag, </b>/* When applicable, dictionary's ID is written into frame header (default:1) */<b> ZSTD_p_dictIDFlag, </b>/* When applicable, dictID of dictionary is provided in frame header (default:1) */<b>
</b>/* multi-threading parameters */<b> </b>/* multi-threading parameters */<b>
ZSTD_p_nbThreads=400, </b>/* Select how many threads a compression job can spawn (default:1)<b> ZSTD_p_nbThreads=400, </b>/* Select how many threads a compression job can spawn (default:1)<b>
* More threads improve speed, but also increase memory usage. * More threads improve speed, but also increase memory usage.
* Can only receive a value > 1 if ZSTD_MULTITHREAD is enabled. * Can only receive a value > 1 if ZSTD_MULTITHREAD is enabled.
* Special: value 0 means "do not change nbThreads" */ * Special: value 0 means "do not change nbThreads" */
ZSTD_p_jobSize, </b>/* Size of a compression job. This value is only enforced in streaming (non-blocking) mode.<b> ZSTD_p_jobSize, </b>/* Size of a compression job. Each compression job is completed in parallel.<b>
* Each compression job is completed in parallel, so indirectly controls the nb of active threads.
* 0 means default, which is dynamically determined based on compression parameters. * 0 means default, which is dynamically determined based on compression parameters.
* Job size must be a minimum of overlapSize, or 1 KB, whichever is largest * Job size must be a minimum of overlapSize, or 1 KB, whichever is largest
* The minimum size is automatically and transparently enforced */ * The minimum size is automatically and transparently enforced */
@@ -909,8 +904,7 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
<pre><b>size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value); <pre><b>size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value);
</b><p> Set one compression parameter, selected by enum ZSTD_cParameter. </b><p> Set one compression parameter, selected by enum ZSTD_cParameter.
Note : when `value` is an enum, cast it to unsigned for proper type checking. Note : when `value` is an enum, cast it to unsigned for proper type checking.
@result : informational value (typically, the one being set, possibly corrected), @result : 0, or an error code (which can be tested with ZSTD_isError()).
or an error code (which can be tested with ZSTD_isError()).
</p></pre><BR> </p></pre><BR>
<pre><b>size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize); <pre><b>size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize);
@@ -919,7 +913,7 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
@result : 0, or an error code (which can be tested with ZSTD_isError()). @result : 0, or an error code (which can be tested with ZSTD_isError()).
Note 1 : 0 means zero, empty. Note 1 : 0 means zero, empty.
In order to mean "unknown content size", pass constant ZSTD_CONTENTSIZE_UNKNOWN. In order to mean "unknown content size", pass constant ZSTD_CONTENTSIZE_UNKNOWN.
ZSTD_CONTENTSIZE_UNKNOWN is default value for any new compression job. Note that ZSTD_CONTENTSIZE_UNKNOWN is default value for new compression jobs.
Note 2 : If all data is provided and consumed in a single round, Note 2 : If all data is provided and consumed in a single round,
this value is overriden by srcSize instead. this value is overriden by srcSize instead.
</p></pre><BR> </p></pre><BR>
@@ -991,19 +985,13 @@ size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t
- Compression parameters cannot be changed once compression is started. - Compression parameters cannot be changed once compression is started.
- outpot->pos must be <= dstCapacity, input->pos must be <= srcSize - outpot->pos must be <= dstCapacity, input->pos must be <= srcSize
- outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit. - outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit.
- In single-thread mode (default), function is blocking : it completed its job before returning to caller. - @return provides the minimum amount of data still to flush from internal buffers
- In multi-thread mode, function is non-blocking : it just acquires a copy of input, and distribute job to internal worker threads,
and then immediately returns, just indicating that there is some data remaining to be flushed.
The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte.
- Exception : in multi-threading mode, if the first call requests a ZSTD_e_end directive, it is blocking : it will complete compression before giving back control to caller.
- @return provides the minimum amount of data remaining to be flushed from internal buffers
or an error code, which can be tested using ZSTD_isError(). or an error code, which can be tested using ZSTD_isError().
if @return != 0, flush is not fully completed, there is still some data left within internal buffers. if @return != 0, flush is not fully completed, there is some data left within internal buffers.
This is useful to determine if a ZSTD_e_flush or ZSTD_e_end directive is completed. - after a ZSTD_e_end directive, if internal buffer is not fully flushed,
- after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0),
only ZSTD_e_end or ZSTD_e_flush operations are allowed. only ZSTD_e_end or ZSTD_e_flush operations are allowed.
Before starting a new compression job, or changing compression parameters, It is necessary to fully flush internal buffers
it is required to fully flush internal buffers. before starting a new compression job, or changing compression parameters.
</p></pre><BR> </p></pre><BR>
@@ -1178,7 +1166,7 @@ size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t
</p></pre><BR> </p></pre><BR>
<a name="Chapter22"></a><h2>Block level API</h2><pre></pre> <a name="Chapter21"></a><h2>Block level API</h2><pre></pre>
<pre><b></b><p> Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes). <pre><b></b><p> Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
User will have to take in charge required information to regenerate data, such as compressed and content sizes. User will have to take in charge required information to regenerate data, such as compressed and content sizes.
+10 -31
View File
@@ -15,9 +15,15 @@ cxx_library(
header_namespace='', header_namespace='',
visibility=['PUBLIC'], visibility=['PUBLIC'],
exported_headers=subdir_glob([ exported_headers=subdir_glob([
('compress', 'zstd*.h'), ('compress', 'zstdmt_compress.h'),
]), ]),
srcs=glob(['compress/zstd*.c']), headers=subdir_glob([
('compress', 'zstd_opt.h'),
]),
srcs=[
'compress/zstd_compress.c',
'compress/zstdmt_compress.c',
],
deps=[':common'], deps=[':common'],
) )
@@ -25,7 +31,7 @@ cxx_library(
name='decompress', name='decompress',
header_namespace='', header_namespace='',
visibility=['PUBLIC'], visibility=['PUBLIC'],
srcs=glob(['decompress/zstd*.c']), srcs=['decompress/zstd_decompress.c'],
deps=[ deps=[
':common', ':common',
':legacy', ':legacy',
@@ -52,9 +58,6 @@ cxx_library(
]), ]),
srcs=glob(['legacy/*.c']), srcs=glob(['legacy/*.c']),
deps=[':common'], deps=[':common'],
exported_preprocessor_flags=[
'-DZSTD_LEGACY_SUPPORT=4',
],
) )
cxx_library( cxx_library(
@@ -71,15 +74,6 @@ cxx_library(
deps=[':common'], deps=[':common'],
) )
cxx_library(
name='compiler',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('common', 'compiler.h'),
]),
)
cxx_library( cxx_library(
name='bitstream', name='bitstream',
header_namespace='', header_namespace='',
@@ -106,7 +100,6 @@ cxx_library(
], ],
deps=[ deps=[
':bitstream', ':bitstream',
':compiler',
':errors', ':errors',
':mem', ':mem',
], ],
@@ -140,10 +133,7 @@ cxx_library(
('common', 'pool.h'), ('common', 'pool.h'),
]), ]),
srcs=['common/pool.c'], srcs=['common/pool.c'],
deps=[ deps=[':threading'],
':threading',
':zstd_common',
],
) )
cxx_library( cxx_library(
@@ -154,12 +144,6 @@ cxx_library(
('common', 'threading.h'), ('common', 'threading.h'),
]), ]),
srcs=['common/threading.c'], srcs=['common/threading.c'],
exported_preprocessor_flags=[
'-DZSTD_MULTITHREAD',
],
exported_linker_flags=[
'-pthread',
],
) )
cxx_library( cxx_library(
@@ -170,9 +154,6 @@ cxx_library(
('common', 'xxhash.h'), ('common', 'xxhash.h'),
]), ]),
srcs=['common/xxhash.c'], srcs=['common/xxhash.c'],
exported_preprocessor_flags=[
'-DXXH_NAMESPACE=ZSTD_',
],
) )
cxx_library( cxx_library(
@@ -185,7 +166,6 @@ cxx_library(
]), ]),
srcs=['common/zstd_common.c'], srcs=['common/zstd_common.c'],
deps=[ deps=[
':compiler',
':errors', ':errors',
':mem', ':mem',
], ],
@@ -195,7 +175,6 @@ cxx_library(
name='common', name='common',
deps=[ deps=[
':bitstream', ':bitstream',
':compiler',
':entropy', ':entropy',
':errors', ':errors',
':mem', ':mem',
+1 -1
View File
@@ -167,7 +167,7 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
/*-************************************************************** /*-**************************************************************
* Internal functions * Internal functions
****************************************************************/ ****************************************************************/
MEM_STATIC unsigned BIT_highbit32 (U32 val) MEM_STATIC unsigned BIT_highbit32 (register U32 val)
{ {
assert(val != 0); assert(val != 0);
{ {
+13 -15
View File
@@ -56,6 +56,8 @@ MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (size
typedef int32_t S32; typedef int32_t S32;
typedef uint64_t U64; typedef uint64_t U64;
typedef int64_t S64; typedef int64_t S64;
typedef intptr_t iPtrDiff;
typedef uintptr_t uPtrDiff;
#else #else
typedef unsigned char BYTE; typedef unsigned char BYTE;
typedef unsigned short U16; typedef unsigned short U16;
@@ -64,6 +66,8 @@ MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (size
typedef signed int S32; typedef signed int S32;
typedef unsigned long long U64; typedef unsigned long long U64;
typedef signed long long S64; typedef signed long long S64;
typedef ptrdiff_t iPtrDiff;
typedef size_t uPtrDiff;
#endif #endif
@@ -119,26 +123,20 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
/* currently only defined for gcc and icc */ /* currently only defined for gcc and icc */
#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32)) #if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))
__pragma( pack(push, 1) ) __pragma( pack(push, 1) )
typedef struct { U16 v; } unalign16; typedef union { U16 u16; U32 u32; U64 u64; size_t st; } unalign;
typedef struct { U32 v; } unalign32;
typedef struct { U64 v; } unalign64;
typedef struct { size_t v; } unalignArch;
__pragma( pack(pop) ) __pragma( pack(pop) )
#else #else
typedef struct { U16 v; } __attribute__((packed)) unalign16; typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign;
typedef struct { U32 v; } __attribute__((packed)) unalign32;
typedef struct { U64 v; } __attribute__((packed)) unalign64;
typedef struct { size_t v; } __attribute__((packed)) unalignArch;
#endif #endif
MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; } MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; } MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; } MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; } MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalign*)ptr)->st; }
MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; } MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; } MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; } MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; }
#else #else
+2 -1
View File
@@ -11,6 +11,7 @@
/* ====== Dependencies ======= */ /* ====== Dependencies ======= */
#include <stddef.h> /* size_t */ #include <stddef.h> /* size_t */
#include <stdlib.h> /* malloc, calloc, free */
#include "pool.h" #include "pool.h"
/* ====== Compiler specifics ====== */ /* ====== Compiler specifics ====== */
@@ -114,7 +115,7 @@ POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customM
* and full queues. * and full queues.
*/ */
ctx->queueSize = queueSize + 1; ctx->queueSize = queueSize + 1;
ctx->queue = (POOL_job*)ZSTD_malloc(ctx->queueSize * sizeof(POOL_job), customMem); ctx->queue = (POOL_job*) malloc(ctx->queueSize * sizeof(POOL_job));
ctx->queueHead = 0; ctx->queueHead = 0;
ctx->queueTail = 0; ctx->queueTail = 0;
ctx->numThreadsBusy = 0; ctx->numThreadsBusy = 0;
+4 -10
View File
@@ -31,27 +31,21 @@ const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; }
* ZSTD Error Management * ZSTD Error Management
******************************************/ ******************************************/
/*! ZSTD_isError() : /*! ZSTD_isError() :
* tells if a return value is an error code */ * tells if a return value is an error code */
unsigned ZSTD_isError(size_t code) { return ERR_isError(code); } unsigned ZSTD_isError(size_t code) { return ERR_isError(code); }
/*! ZSTD_getErrorName() : /*! ZSTD_getErrorName() :
* provides error code string from function result (useful for debugging) */ * provides error code string from function result (useful for debugging) */
const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); } const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); }
/*! ZSTD_getError() : /*! ZSTD_getError() :
* convert a `size_t` function result into a proper ZSTD_errorCode enum */ * convert a `size_t` function result into a proper ZSTD_errorCode enum */
ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); } ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); }
/*! ZSTD_getErrorString() : /*! ZSTD_getErrorString() :
* provides error code string from enum */ * provides error code string from enum */
const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); } const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); }
/*! g_debuglog_enable :
* turn on/off debug traces (global switch) */
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 2)
int g_debuglog_enable = 1;
#endif
/*=************************************************************** /*=**************************************************************
* Custom allocator * Custom allocator
+169 -51
View File
@@ -11,10 +11,6 @@
#ifndef ZSTD_CCOMMON_H_MODULE #ifndef ZSTD_CCOMMON_H_MODULE
#define ZSTD_CCOMMON_H_MODULE #define ZSTD_CCOMMON_H_MODULE
/* this module contains definitions which must be identical
* across compression, decompression and dictBuilder.
* It also contains a few functions useful to at least 2 of them
* and which benefit from being inlined */
/*-************************************* /*-*************************************
* Dependencies * Dependencies
@@ -54,26 +50,21 @@ extern "C" {
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2) #if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2)
# include <stdio.h> # include <stdio.h>
extern int g_debuglog_enable;
/* recommended values for ZSTD_DEBUG display levels : /* recommended values for ZSTD_DEBUG display levels :
* 1 : no display, enables assert() only * 1 : no display, enables assert() only
* 2 : reserved for currently active debug path * 2 : reserved for currently active debugging path
* 3 : events once per object lifetime (CCtx, CDict, etc.) * 3 : events once per object lifetime (CCtx, CDict)
* 4 : events once per frame * 4 : events once per frame
* 5 : events once per block * 5 : events once per block
* 6 : events once per sequence (*very* verbose) */ * 6 : events once per sequence (*very* verbose) */
# define RAWLOG(l, ...) { \ # define DEBUGLOG(l, ...) { \
if ((g_debuglog_enable) & (l<=ZSTD_DEBUG)) { \ if (l<=ZSTD_DEBUG) { \
fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, __FILE__ ": "); \
} } fprintf(stderr, __VA_ARGS__); \
# define DEBUGLOG(l, ...) { \ fprintf(stderr, " \n"); \
if ((g_debuglog_enable) & (l<=ZSTD_DEBUG)) { \
fprintf(stderr, __FILE__ ": " __VA_ARGS__); \
fprintf(stderr, " \n"); \
} } } }
#else #else
# define RAWLOG(l, ...) {} /* disabled */ # define DEBUGLOG(l, ...) {} /* disabled */
# define DEBUGLOG(l, ...) {} /* disabled */
#endif #endif
@@ -94,7 +85,9 @@ extern int g_debuglog_enable;
#define ZSTD_OPT_NUM (1<<12) #define ZSTD_OPT_NUM (1<<12)
#define ZSTD_REP_NUM 3 /* number of repcodes */ #define ZSTD_REP_NUM 3 /* number of repcodes */
#define ZSTD_REP_CHECK (ZSTD_REP_NUM) /* number of repcodes to check by the optimal parser */
#define ZSTD_REP_MOVE (ZSTD_REP_NUM-1) #define ZSTD_REP_MOVE (ZSTD_REP_NUM-1)
#define ZSTD_REP_MOVE_OPT (ZSTD_REP_NUM)
static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
#define KB *(1 <<10) #define KB *(1 <<10)
@@ -141,40 +134,28 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy
#define LLFSELog 9 #define LLFSELog 9
#define OffFSELog 8 #define OffFSELog 8
static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0, static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9,10,11,12,
1, 1, 1, 1, 2, 2, 3, 3,
4, 6, 7, 8, 9,10,11,12,
13,14,15,16 }; 13,14,15,16 };
static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2, static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2,
2, 3, 2, 1, 1, 1, 1, 1,
-1,-1,-1,-1 }; -1,-1,-1,-1 };
#define LL_DEFAULTNORMLOG 6 /* for static allocation */ #define LL_DEFAULTNORMLOG 6 /* for static allocation */
static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG; static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0, static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9,10,11,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 2, 2, 3, 3,
4, 4, 5, 7, 8, 9,10,11,
12,13,14,15,16 }; 12,13,14,15,16 };
static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2, static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1,-1,-1,
-1,-1,-1,-1,-1 }; -1,-1,-1,-1,-1 };
#define ML_DEFAULTNORMLOG 6 /* for static allocation */ #define ML_DEFAULTNORMLOG 6 /* for static allocation */
static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG; static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
static const S16 OF_defaultNorm[DefaultMaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2, static const S16 OF_defaultNorm[DefaultMaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1 };
1, 1, 1, 1, 1, 1, 1, 1,
-1,-1,-1,-1,-1 };
#define OF_DEFAULTNORMLOG 5 /* for static allocation */ #define OF_DEFAULTNORMLOG 5 /* for static allocation */
static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG; static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
@@ -186,7 +167,7 @@ static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); }
#define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; } #define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
/*! ZSTD_wildcopy() : /*! ZSTD_wildcopy() :
* custom version of memcpy(), can overwrite up to WILDCOPY_OVERLENGTH bytes (if length==0) */ * custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */
#define WILDCOPY_OVERLENGTH 8 #define WILDCOPY_OVERLENGTH 8
MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length) MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length)
{ {
@@ -210,14 +191,17 @@ MEM_STATIC void ZSTD_wildcopy_e(void* dst, const void* src, void* dstEnd) /* s
/*-******************************************* /*-*******************************************
* Private declarations * Private interfaces
*********************************************/ *********************************************/
typedef struct ZSTD_stats_s ZSTD_stats_t;
typedef struct seqDef_s { typedef struct seqDef_s {
U32 offset; U32 offset;
U16 litLength; U16 litLength;
U16 matchLength; U16 matchLength;
} seqDef; } seqDef;
typedef struct { typedef struct {
seqDef* sequencesStart; seqDef* sequencesStart;
seqDef* sequences; seqDef* sequences;
@@ -232,8 +216,100 @@ typedef struct {
U32 repToConfirm[ZSTD_REP_NUM]; U32 repToConfirm[ZSTD_REP_NUM];
} seqStore_t; } seqStore_t;
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */ typedef struct {
void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */ U32 off;
U32 len;
} ZSTD_match_t;
typedef struct {
U32 price;
U32 off;
U32 mlen;
U32 litlen;
U32 rep[ZSTD_REP_NUM];
} ZSTD_optimal_t;
typedef struct {
U32* litFreq;
U32* litLengthFreq;
U32* matchLengthFreq;
U32* offCodeFreq;
ZSTD_match_t* matchTable;
ZSTD_optimal_t* priceTable;
U32 matchLengthSum;
U32 matchSum;
U32 litLengthSum;
U32 litSum;
U32 offCodeSum;
U32 log2matchLengthSum;
U32 log2matchSum;
U32 log2litLengthSum;
U32 log2litSum;
U32 log2offCodeSum;
U32 factor;
U32 staticPrices;
U32 cachedPrice;
U32 cachedLitLength;
const BYTE* cachedLiterals;
} optState_t;
typedef struct {
U32 offset;
U32 checksum;
} ldmEntry_t;
typedef struct {
ldmEntry_t* hashTable;
BYTE* bucketOffsets; /* Next position in bucket to insert entry */
U64 hashPower; /* Used to compute the rolling hash.
* Depends on ldmParams.minMatchLength */
} ldmState_t;
typedef struct {
U32 enableLdm; /* 1 if enable long distance matching */
U32 hashLog; /* Log size of hashTable */
U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */
U32 minMatchLength; /* Minimum match length */
U32 hashEveryLog; /* Log number of entries to skip */
} ldmParams_t;
typedef struct {
U32 hufCTable[HUF_CTABLE_SIZE_U32(255)];
FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
U32 workspace[HUF_WORKSPACE_SIZE_U32];
HUF_repeat hufCTable_repeatMode;
FSE_repeat offcode_repeatMode;
FSE_repeat matchlength_repeatMode;
FSE_repeat litlength_repeatMode;
} ZSTD_entropyCTables_t;
struct ZSTD_CCtx_params_s {
ZSTD_format_e format;
ZSTD_compressionParameters cParams;
ZSTD_frameParameters fParams;
int compressionLevel;
U32 forceWindow; /* force back-references to respect limit of
* 1<<wLog, even for dictionary */
/* Multithreading: used to pass parameters to mtctx */
U32 nbThreads;
unsigned jobSize;
unsigned overlapSizeLog;
/* Long distance matching parameters */
ldmParams_t ldmParams;
/* For use with createCCtxParams() and freeCCtxParams() only */
ZSTD_customMem customMem;
}; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx);
void ZSTD_seqToCodes(const seqStore_t* seqStorePtr);
/* custom memory allocation functions */ /* custom memory allocation functions */
void* ZSTD_malloc(size_t size, ZSTD_customMem customMem); void* ZSTD_malloc(size_t size, ZSTD_customMem customMem);
@@ -241,7 +317,9 @@ void* ZSTD_calloc(size_t size, ZSTD_customMem customMem);
void ZSTD_free(void* ptr, ZSTD_customMem customMem); void ZSTD_free(void* ptr, ZSTD_customMem customMem);
MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ /*====== common function ======*/
MEM_STATIC U32 ZSTD_highbit32(U32 val)
{ {
assert(val != 0); assert(val != 0);
{ {
@@ -252,26 +330,67 @@ MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus
# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ # elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
return 31 - __builtin_clz(val); return 31 - __builtin_clz(val);
# else /* Software version */ # else /* Software version */
static const U32 DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
U32 v = val; U32 v = val;
int r;
v |= v >> 1; v |= v >> 1;
v |= v >> 2; v |= v >> 2;
v |= v >> 4; v |= v >> 4;
v |= v >> 8; v |= v >> 8;
v |= v >> 16; v |= v >> 16;
return DeBruijnClz[(v * 0x07C4ACDDU) >> 27]; r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
return r;
# endif # endif
} }
} }
/* hidden functions */
/* ZSTD_invalidateRepCodes() : /* ZSTD_invalidateRepCodes() :
* ensures next compression will not use repcodes from previous block. * ensures next compression will not use repcodes from previous block.
* Note : only works with regular variant; * Note : only works with regular variant;
* do not use with extDict variant ! */ * do not use with extDict variant ! */
void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); /* zstdmt, adaptive_compression (shouldn't get this definition from here) */ void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx);
/*! ZSTD_initCStream_internal() :
* Private use only. Init streaming operation.
* expects params to be valid.
* must receive dict, or cdict, or none, but not both.
* @return : 0, or an error code */
size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
const void* dict, size_t dictSize,
const ZSTD_CDict* cdict,
ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
/*! ZSTD_compressStream_generic() :
* Private use only. To be called from zstdmt_compress.c in single-thread mode. */
size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
ZSTD_outBuffer* output,
ZSTD_inBuffer* input,
ZSTD_EndDirective const flushMode);
/*! ZSTD_getCParamsFromCDict() :
* as the name implies */
ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict);
/* ZSTD_compressBegin_advanced_internal() :
* Private use only. To be called from zstdmt_compress.c. */
size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
const void* dict, size_t dictSize,
ZSTD_dictMode_e dictMode,
ZSTD_CCtx_params params,
unsigned long long pledgedSrcSize);
/* ZSTD_compress_advanced_internal() :
* Private use only. To be called from zstdmt_compress.c. */
size_t ZSTD_compress_advanced_internal(ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
const void* dict,size_t dictSize,
ZSTD_CCtx_params params);
typedef struct { typedef struct {
blockType_e blockType; blockType_e blockType;
U32 lastBlock; U32 lastBlock;
@@ -279,8 +398,7 @@ typedef struct {
} blockProperties_t; } blockProperties_t;
/*! ZSTD_getcBlockSize() : /*! ZSTD_getcBlockSize() :
* Provides the size of compressed block from block header `src` */ * Provides the size of compressed block from block header `src` */
/* Used by: decompress, fullbench (does not get its definition from here) */
size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, size_t ZSTD_getcBlockSize(const void* src, size_t srcSize,
blockProperties_t* bpPtr); blockProperties_t* bpPtr);
+336 -433
View File
@@ -26,7 +26,7 @@
#include "fse.h" #include "fse.h"
#define HUF_STATIC_LINKING_ONLY #define HUF_STATIC_LINKING_ONLY
#include "huf.h" #include "huf.h"
#include "zstd_compress_internal.h" #include "zstd_compress.h"
#include "zstd_fast.h" #include "zstd_fast.h"
#include "zstd_double_fast.h" #include "zstd_double_fast.h"
#include "zstd_lazy.h" #include "zstd_lazy.h"
@@ -42,6 +42,17 @@ size_t ZSTD_compressBound(size_t srcSize) {
} }
/*-*************************************
* Sequence storage
***************************************/
static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
{
ssPtr->lit = ssPtr->litStart;
ssPtr->sequences = ssPtr->sequencesStart;
ssPtr->longLengthID = 0;
}
/*-************************************* /*-*************************************
* Context memory management * Context memory management
***************************************/ ***************************************/
@@ -67,7 +78,6 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
if (!cctx) return NULL; if (!cctx) return NULL;
cctx->customMem = customMem; cctx->customMem = customMem;
cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;
cctx->requestedParams.fParams.contentSizeFlag = 1;
ZSTD_STATIC_ASSERT(zcss_init==0); ZSTD_STATIC_ASSERT(zcss_init==0);
ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
return cctx; return cctx;
@@ -142,34 +152,28 @@ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStor
#define ZSTD_CLEVEL_CUSTOM 999 #define ZSTD_CLEVEL_CUSTOM 999
static ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( static ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
ZSTD_CCtx_params CCtxParams, U64 srcSizeHint, size_t dictSize) ZSTD_CCtx_params params, U64 srcSizeHint, size_t dictSize)
{ {
DEBUGLOG(4, "ZSTD_getCParamsFromCCtxParams: srcSize = %u, dictSize = %u", return (params.compressionLevel == ZSTD_CLEVEL_CUSTOM ?
(U32)srcSizeHint, (U32)dictSize); params.cParams :
return (CCtxParams.compressionLevel == ZSTD_CLEVEL_CUSTOM) ? ZSTD_getCParams(params.compressionLevel, srcSizeHint, dictSize));
CCtxParams.cParams :
ZSTD_getCParams(CCtxParams.compressionLevel, srcSizeHint, dictSize);
} }
static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* CCtxParams, U64 srcSize) static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* params, U64 srcSize)
{ {
DEBUGLOG(4, "ZSTD_cLevelToCCtxParams_srcSize: srcSize = %u", params->cParams = ZSTD_getCParamsFromCCtxParams(*params, srcSize, 0);
(U32)srcSize); params->compressionLevel = ZSTD_CLEVEL_CUSTOM;
CCtxParams->cParams = ZSTD_getCParamsFromCCtxParams(*CCtxParams, srcSize, 0);
CCtxParams->compressionLevel = ZSTD_CLEVEL_CUSTOM;
} }
static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx) static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx)
{ {
DEBUGLOG(4, "ZSTD_cLevelToCParams: level=%i", cctx->requestedParams.compressionLevel);
ZSTD_cLevelToCCtxParams_srcSize( ZSTD_cLevelToCCtxParams_srcSize(
&cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1); &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1);
} }
static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* CCtxParams) static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* params)
{ {
DEBUGLOG(4, "ZSTD_cLevelToCCtxParams"); ZSTD_cLevelToCCtxParams_srcSize(params, 0);
ZSTD_cLevelToCCtxParams_srcSize(CCtxParams, ZSTD_CONTENTSIZE_UNKNOWN);
} }
static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
@@ -247,7 +251,6 @@ static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value) size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value)
{ {
DEBUGLOG(4, "ZSTD_CCtx_setParameter (%u, %u)", (U32)param, value);
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
switch(param) switch(param)
@@ -256,6 +259,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
case ZSTD_p_compressionLevel: case ZSTD_p_compressionLevel:
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
if (cctx->cdict) return ERROR(stage_wrong); if (cctx->cdict) return ERROR(stage_wrong);
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
@@ -266,8 +270,9 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
case ZSTD_p_minMatch: case ZSTD_p_minMatch:
case ZSTD_p_targetLength: case ZSTD_p_targetLength:
case ZSTD_p_compressionStrategy: case ZSTD_p_compressionStrategy:
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
if (cctx->cdict) return ERROR(stage_wrong); if (cctx->cdict) return ERROR(stage_wrong);
if (value>0) ZSTD_cLevelToCParams(cctx); /* Can optimize if srcSize is known */ ZSTD_cLevelToCParams(cctx); /* Can optimize if srcSize is known */
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
case ZSTD_p_contentSizeFlag: case ZSTD_p_contentSizeFlag:
@@ -276,12 +281,15 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize, case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize,
* even when referencing into Dictionary content. * even when referencing into Dictionary content
* default : 0 when using a CDict, 1 when using a Prefix */ * default : 0 when using a CDict, 1 when using a Prefix */
cctx->loadedDictEnd = 0;
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
case ZSTD_p_nbThreads: case ZSTD_p_nbThreads:
if ((value > 1) && cctx->staticSize) { if (value==0) return 0;
DEBUGLOG(5, " setting nbThreads : %u", value);
if (value > 1 && cctx->staticSize) {
return ERROR(parameter_unsupported); /* MT not compatible with static alloc */ return ERROR(parameter_unsupported); /* MT not compatible with static alloc */
} }
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
@@ -290,15 +298,22 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
case ZSTD_p_overlapSizeLog: case ZSTD_p_overlapSizeLog:
DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->requestedParams.nbThreads);
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
case ZSTD_p_enableLongDistanceMatching: case ZSTD_p_enableLongDistanceMatching:
if (cctx->cdict) return ERROR(stage_wrong); if (cctx->cdict) return ERROR(stage_wrong);
if (value>0) ZSTD_cLevelToCParams(cctx); if (value != 0) {
ZSTD_cLevelToCParams(cctx);
}
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
case ZSTD_p_ldmHashLog: case ZSTD_p_ldmHashLog:
case ZSTD_p_ldmMinMatch: case ZSTD_p_ldmMinMatch:
if (value == 0) return 0; /* special value : 0 means "don't change anything" */
if (cctx->cdict) return ERROR(stage_wrong);
return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
case ZSTD_p_ldmBucketSizeLog: case ZSTD_p_ldmBucketSizeLog:
case ZSTD_p_ldmHashEveryLog: case ZSTD_p_ldmHashEveryLog:
if (cctx->cdict) return ERROR(stage_wrong); if (cctx->cdict) return ERROR(stage_wrong);
@@ -309,167 +324,160 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
} }
size_t ZSTD_CCtxParam_setParameter( size_t ZSTD_CCtxParam_setParameter(
ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, unsigned value) ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value)
{ {
DEBUGLOG(4, "ZSTD_CCtxParam_setParameter (%u, %u)", (U32)param, value);
switch(param) switch(param)
{ {
case ZSTD_p_format : case ZSTD_p_format :
if (value > (unsigned)ZSTD_f_zstd1_magicless) if (value > (unsigned)ZSTD_f_zstd1_magicless)
return ERROR(parameter_unsupported); return ERROR(parameter_unsupported);
CCtxParams->format = (ZSTD_format_e)value; params->format = (ZSTD_format_e)value;
return (size_t)CCtxParams->format; return 0;
case ZSTD_p_compressionLevel : case ZSTD_p_compressionLevel :
if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel(); if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel();
if (value) /* 0 : does not change current level */ if (value == 0) return 0;
CCtxParams->compressionLevel = value; params->compressionLevel = value;
return CCtxParams->compressionLevel; return 0;
case ZSTD_p_windowLog : case ZSTD_p_windowLog :
DEBUGLOG(4, "ZSTD_CCtxParam_setParameter: set windowLog=%u", value); if (value == 0) return 0;
if (value) { /* 0 : does not change current windowLog */ CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); ZSTD_cLevelToCCtxParams(params);
ZSTD_cLevelToCCtxParams(CCtxParams); params->cParams.windowLog = value;
CCtxParams->cParams.windowLog = value; return 0;
}
return CCtxParams->cParams.windowLog;
case ZSTD_p_hashLog : case ZSTD_p_hashLog :
if (value) { /* 0 : does not change current hashLog */ if (value == 0) return 0;
CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
ZSTD_cLevelToCCtxParams(CCtxParams); ZSTD_cLevelToCCtxParams(params);
CCtxParams->cParams.hashLog = value; params->cParams.hashLog = value;
} return 0;
return CCtxParams->cParams.hashLog;
case ZSTD_p_chainLog : case ZSTD_p_chainLog :
if (value) { /* 0 : does not change current chainLog */ if (value == 0) return 0;
CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
ZSTD_cLevelToCCtxParams(CCtxParams); ZSTD_cLevelToCCtxParams(params);
CCtxParams->cParams.chainLog = value; params->cParams.chainLog = value;
} return 0;
return CCtxParams->cParams.chainLog;
case ZSTD_p_searchLog : case ZSTD_p_searchLog :
if (value) { /* 0 : does not change current searchLog */ if (value == 0) return 0;
CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
ZSTD_cLevelToCCtxParams(CCtxParams); ZSTD_cLevelToCCtxParams(params);
CCtxParams->cParams.searchLog = value; params->cParams.searchLog = value;
} return 0;
return value;
case ZSTD_p_minMatch : case ZSTD_p_minMatch :
if (value) { /* 0 : does not change current minMatch length */ if (value == 0) return 0;
CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
ZSTD_cLevelToCCtxParams(CCtxParams); ZSTD_cLevelToCCtxParams(params);
CCtxParams->cParams.searchLength = value; params->cParams.searchLength = value;
} return 0;
return CCtxParams->cParams.searchLength;
case ZSTD_p_targetLength : case ZSTD_p_targetLength :
if (value) { /* 0 : does not change current sufficient_len */ if (value == 0) return 0;
CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
ZSTD_cLevelToCCtxParams(CCtxParams); ZSTD_cLevelToCCtxParams(params);
CCtxParams->cParams.targetLength = value; params->cParams.targetLength = value;
} return 0;
return CCtxParams->cParams.targetLength;
case ZSTD_p_compressionStrategy : case ZSTD_p_compressionStrategy :
if (value) { /* 0 : does not change currentstrategy */ if (value == 0) return 0;
CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra); CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
ZSTD_cLevelToCCtxParams(CCtxParams); ZSTD_cLevelToCCtxParams(params);
CCtxParams->cParams.strategy = (ZSTD_strategy)value; params->cParams.strategy = (ZSTD_strategy)value;
} return 0;
return (size_t)CCtxParams->cParams.strategy;
case ZSTD_p_contentSizeFlag : case ZSTD_p_contentSizeFlag :
/* Content size written in frame header _when known_ (default:1) */ /* Content size written in frame header _when known_ (default:1) */
DEBUGLOG(4, "set content size flag = %u", (value>0)); DEBUGLOG(5, "set content size flag = %u", (value>0));
CCtxParams->fParams.contentSizeFlag = value > 0; params->fParams.contentSizeFlag = value > 0;
return CCtxParams->fParams.contentSizeFlag; return 0;
case ZSTD_p_checksumFlag : case ZSTD_p_checksumFlag :
/* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
CCtxParams->fParams.checksumFlag = value > 0; params->fParams.checksumFlag = value > 0;
return CCtxParams->fParams.checksumFlag; return 0;
case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
DEBUGLOG(4, "set dictIDFlag = %u", (value>0)); DEBUGLOG(5, "set dictIDFlag = %u", (value>0));
CCtxParams->fParams.noDictIDFlag = (value == 0); params->fParams.noDictIDFlag = (value == 0);
return !CCtxParams->fParams.noDictIDFlag; return 0;
case ZSTD_p_forceMaxWindow : case ZSTD_p_forceMaxWindow :
CCtxParams->forceWindow = (value > 0); params->forceWindow = value > 0;
return CCtxParams->forceWindow; return 0;
case ZSTD_p_nbThreads : case ZSTD_p_nbThreads :
if (value == 0) return CCtxParams->nbThreads; if (value == 0) return 0;
#ifndef ZSTD_MULTITHREAD #ifndef ZSTD_MULTITHREAD
if (value > 1) return ERROR(parameter_unsupported); if (value > 1) return ERROR(parameter_unsupported);
return 1; return 0;
#else #else
return ZSTDMT_CCtxParam_setNbThreads(CCtxParams, value); return ZSTDMT_initializeCCtxParameters(params, value);
#endif #endif
case ZSTD_p_jobSize : case ZSTD_p_jobSize :
#ifndef ZSTD_MULTITHREAD #ifndef ZSTD_MULTITHREAD
return ERROR(parameter_unsupported); return ERROR(parameter_unsupported);
#else #else
if (CCtxParams->nbThreads <= 1) return ERROR(parameter_unsupported); if (params->nbThreads <= 1) return ERROR(parameter_unsupported);
return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_jobSize, value); return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_sectionSize, value);
#endif #endif
case ZSTD_p_overlapSizeLog : case ZSTD_p_overlapSizeLog :
#ifndef ZSTD_MULTITHREAD #ifndef ZSTD_MULTITHREAD
return ERROR(parameter_unsupported); return ERROR(parameter_unsupported);
#else #else
if (CCtxParams->nbThreads <= 1) return ERROR(parameter_unsupported); if (params->nbThreads <= 1) return ERROR(parameter_unsupported);
return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_overlapSectionLog, value); return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_overlapSectionLog, value);
#endif #endif
case ZSTD_p_enableLongDistanceMatching : case ZSTD_p_enableLongDistanceMatching :
if (value) { if (value != 0) {
ZSTD_cLevelToCCtxParams(CCtxParams); ZSTD_cLevelToCCtxParams(params);
CCtxParams->cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; params->cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
} }
return ZSTD_ldm_initializeParameters(&CCtxParams->ldmParams, value); return ZSTD_ldm_initializeParameters(&params->ldmParams, value);
case ZSTD_p_ldmHashLog : case ZSTD_p_ldmHashLog :
if (value) { /* 0 : does not change current ldmHashLog */ if (value == 0) return 0;
CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
CCtxParams->ldmParams.hashLog = value; params->ldmParams.hashLog = value;
} return 0;
return CCtxParams->ldmParams.hashLog;
case ZSTD_p_ldmMinMatch : case ZSTD_p_ldmMinMatch :
if (value) { /* 0 : does not change current ldmMinMatch */ if (value == 0) return 0;
CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX); CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX);
CCtxParams->ldmParams.minMatchLength = value; params->ldmParams.minMatchLength = value;
} return 0;
return CCtxParams->ldmParams.minMatchLength;
case ZSTD_p_ldmBucketSizeLog : case ZSTD_p_ldmBucketSizeLog :
if (value > ZSTD_LDM_BUCKETSIZELOG_MAX) { if (value > ZSTD_LDM_BUCKETSIZELOG_MAX) {
return ERROR(parameter_outOfBound); return ERROR(parameter_outOfBound);
} }
CCtxParams->ldmParams.bucketSizeLog = value; params->ldmParams.bucketSizeLog = value;
return value; return 0;
case ZSTD_p_ldmHashEveryLog : case ZSTD_p_ldmHashEveryLog :
if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN) { if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN) {
return ERROR(parameter_outOfBound); return ERROR(parameter_outOfBound);
} }
CCtxParams->ldmParams.hashEveryLog = value; params->ldmParams.hashEveryLog = value;
return value; return 0;
default: return ERROR(parameter_unsupported); default: return ERROR(parameter_unsupported);
} }
} }
/** ZSTD_CCtx_setParametersUsingCCtxParams() : /**
* just applies `params` into `cctx` * This function should be updated whenever ZSTD_CCtx_params is updated.
* no action is performed, parameters are merely stored. * Parameters are copied manually before the dictionary is loaded.
* The multithreading parameters jobSize and overlapSizeLog are set only if
* nbThreads > 1.
*
* Pledged srcSize is treated as unknown.
*/ */
size_t ZSTD_CCtx_setParametersUsingCCtxParams( size_t ZSTD_CCtx_setParametersUsingCCtxParams(
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
@@ -477,14 +485,33 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams(
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
if (cctx->cdict) return ERROR(stage_wrong); if (cctx->cdict) return ERROR(stage_wrong);
cctx->requestedParams = *params; /* Assume the compression and frame parameters are validated */
cctx->requestedParams.cParams = params->cParams;
cctx->requestedParams.fParams = params->fParams;
cctx->requestedParams.compressionLevel = params->compressionLevel;
/* Set force window explicitly since it sets cctx->loadedDictEnd */
CHECK_F( ZSTD_CCtx_setParameter(
cctx, ZSTD_p_forceMaxWindow, params->forceWindow) );
/* Set multithreading parameters explicitly */
CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_nbThreads, params->nbThreads) );
if (params->nbThreads > 1) {
CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_jobSize, params->jobSize) );
CHECK_F( ZSTD_CCtx_setParameter(
cctx, ZSTD_p_overlapSizeLog, params->overlapSizeLog) );
}
/* Copy long distance matching parameters */
cctx->requestedParams.ldmParams = params->ldmParams;
/* customMem is used only for create/free params and can be ignored */
return 0; return 0;
} }
ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
{ {
DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize); DEBUGLOG(4, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize);
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
return 0; return 0;
@@ -496,14 +523,14 @@ size_t ZSTD_CCtx_loadDictionary_advanced(
{ {
if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */ if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); DEBUGLOG(4, "load dictionary of size %u", (U32)dictSize);
ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */ ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */
if (dict==NULL || dictSize==0) { /* no dictionary mode */ if (dict==NULL || dictSize==0) { /* no dictionary mode */
cctx->cdictLocal = NULL; cctx->cdictLocal = NULL;
cctx->cdict = NULL; cctx->cdict = NULL;
} else { } else {
ZSTD_compressionParameters const cParams = ZSTD_compressionParameters const cParams =
ZSTD_getCParamsFromCCtxParams(cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, dictSize); ZSTD_getCParamsFromCCtxParams(cctx->requestedParams, 0, dictSize);
cctx->cdictLocal = ZSTD_createCDict_advanced( cctx->cdictLocal = ZSTD_createCDict_advanced(
dict, dictSize, dict, dictSize,
dictLoadMethod, dictMode, dictLoadMethod, dictMode,
@@ -729,7 +756,10 @@ size_t ZSTD_estimateCStreamSize(int compressionLevel) {
static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1, static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
ZSTD_compressionParameters cParams2) ZSTD_compressionParameters cParams2)
{ {
return (cParams1.hashLog == cParams2.hashLog) U32 bslog1 = MIN(cParams1.windowLog, ZSTD_BLOCKSIZELOG_MAX);
U32 bslog2 = MIN(cParams2.windowLog, ZSTD_BLOCKSIZELOG_MAX);
return (bslog1 == bslog2) /* same block size */
& (cParams1.hashLog == cParams2.hashLog)
& (cParams1.chainLog == cParams2.chainLog) & (cParams1.chainLog == cParams2.chainLog)
& (cParams1.strategy == cParams2.strategy) /* opt parser space */ & (cParams1.strategy == cParams2.strategy) /* opt parser space */
& ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */ & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */
@@ -748,38 +778,12 @@ static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1,
ldmParams1.hashEveryLog == ldmParams2.hashEveryLog); ldmParams1.hashEveryLog == ldmParams2.hashEveryLog);
} }
typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
/* ZSTD_sufficientBuff() :
* check internal buffers exist for streaming if buffPol == ZSTDb_buffered .
* Note : they are assumed to be correctly sized if ZSTD_equivalentCParams()==1 */
static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t blockSize1,
ZSTD_buffered_policy_e buffPol2,
ZSTD_compressionParameters cParams2,
U64 pledgedSrcSize)
{
size_t const windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize));
size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2);
size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0;
DEBUGLOG(4, "ZSTD_sufficientBuff: windowSize2=%u from wlog=%u",
(U32)windowSize2, cParams2.windowLog);
DEBUGLOG(4, "ZSTD_sufficientBuff: blockSize2 %u <=? blockSize1 %u",
(U32)blockSize2, (U32)blockSize1);
return (blockSize2 <= blockSize1) /* seqStore space depends on blockSize */
& (neededBufferSize2 <= bufferSize1);
}
/** Equivalence for resetCCtx purposes */ /** Equivalence for resetCCtx purposes */
static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1, static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
ZSTD_CCtx_params params2, ZSTD_CCtx_params params2)
size_t buffSize1, size_t blockSize1,
ZSTD_buffered_policy_e buffPol2,
U64 pledgedSrcSize)
{ {
DEBUGLOG(4, "ZSTD_equivalentParams: pledgedSrcSize=%u", (U32)pledgedSrcSize);
return ZSTD_equivalentCParams(params1.cParams, params2.cParams) && return ZSTD_equivalentCParams(params1.cParams, params2.cParams) &&
ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams) && ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams);
ZSTD_sufficientBuff(buffSize1, blockSize1, buffPol2, params2.cParams, pledgedSrcSize);
} }
/*! ZSTD_continueCCtx() : /*! ZSTD_continueCCtx() :
@@ -787,11 +791,7 @@ static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize) static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
{ {
U32 const end = (U32)(cctx->nextSrc - cctx->base); U32 const end = (U32)(cctx->nextSrc - cctx->base);
size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); DEBUGLOG(4, "continue mode");
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
DEBUGLOG(4, "ZSTD_continueCCtx");
cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */
cctx->appliedParams = params; cctx->appliedParams = params;
cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
cctx->consumedSrcSize = 0; cctx->consumedSrcSize = 0;
@@ -812,6 +812,7 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pl
} }
typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e; typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
/*! ZSTD_resetCCtx_internal() : /*! ZSTD_resetCCtx_internal() :
note : `params` are assumed fully validated at this stage */ note : `params` are assumed fully validated at this stage */
@@ -820,16 +821,13 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
ZSTD_compResetPolicy_e const crp, ZSTD_compResetPolicy_e const crp,
ZSTD_buffered_policy_e const zbuff) ZSTD_buffered_policy_e const zbuff)
{ {
DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u", DEBUGLOG(4, "ZSTD_resetCCtx_internal");
(U32)pledgedSrcSize, params.cParams.windowLog);
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
DEBUGLOG(4, "pledgedSrcSize: %u", (U32)pledgedSrcSize);
if (crp == ZSTDcrp_continue) { if (crp == ZSTDcrp_continue) {
if (ZSTD_equivalentParams(zc->appliedParams, params, if (ZSTD_equivalentParams(params, zc->appliedParams)) {
zc->inBuffSize, zc->blockSize, DEBUGLOG(4, "ZSTD_equivalentParams()==1");
zbuff, pledgedSrcSize)) {
DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%u)",
zc->appliedParams.cParams.windowLog, (U32)zc->blockSize);
assert(!(params.ldmParams.enableLdm && assert(!(params.ldmParams.enableLdm &&
params.ldmParams.hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET)); params.ldmParams.hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET));
zc->entropy->hufCTable_repeatMode = HUF_repeat_none; zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
@@ -838,7 +836,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
zc->entropy->litlength_repeatMode = FSE_repeat_none; zc->entropy->litlength_repeatMode = FSE_repeat_none;
return ZSTD_continueCCtx(zc, params, pledgedSrcSize); return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
} } } }
DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx");
if (params.ldmParams.enableLdm) { if (params.ldmParams.enableLdm) {
/* Adjust long distance matching parameters */ /* Adjust long distance matching parameters */
@@ -849,8 +846,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength); ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength);
} }
{ size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
U32 const divider = (params.cParams.searchLength==3) ? 3 : 4; U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
size_t const maxNbSeq = blockSize / divider; size_t const maxNbSeq = blockSize / divider;
size_t const tokenSpace = blockSize + 11*maxNbSeq; size_t const tokenSpace = blockSize + 11*maxNbSeq;
@@ -862,7 +858,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
size_t const h3Size = ((size_t)1) << hashLog3; size_t const h3Size = ((size_t)1) << hashLog3;
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0; size_t const buffInSize = (zbuff==ZSTDb_buffered) ? ((size_t)1 << params.cParams.windowLog) + blockSize : 0;
void* ptr; void* ptr;
/* Check if workSpace is large enough, alloc a new one if needed */ /* Check if workSpace is large enough, alloc a new one if needed */
@@ -878,15 +874,11 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
: 0; : 0;
size_t const neededSpace = entropySpace + optSpace + ldmSpace + size_t const neededSpace = entropySpace + optSpace + ldmSpace +
tableSpace + tokenSpace + bufferSpace; tableSpace + tokenSpace + bufferSpace;
DEBUGLOG(4, "Need %uKB workspace, including %uKB for tables, and %uKB for buffers",
(U32)(neededSpace>>10), (U32)(tableSpace>>10), (U32)(bufferSpace>>10));
DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u - windowSize: %u - blockSize: %u",
(U32)chainSize, (U32)hSize, (U32)h3Size, (U32)windowSize, (U32)blockSize);
if (zc->workSpaceSize < neededSpace) { /* too small : resize */ if (zc->workSpaceSize < neededSpace) { /* too small : resize */
DEBUGLOG(4, "Need to update workSpaceSize from %uK to %uK", DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n",
(unsigned)(zc->workSpaceSize>>10), (unsigned)zc->workSpaceSize>>10,
(unsigned)(neededSpace>>10)); (unsigned)neededSpace>>10);
/* static cctx : no resize, error out */ /* static cctx : no resize, error out */
if (zc->staticSize) return ERROR(memory_allocation); if (zc->staticSize) return ERROR(memory_allocation);
@@ -909,7 +901,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
zc->consumedSrcSize = 0; zc->consumedSrcSize = 0;
if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
zc->appliedParams.fParams.contentSizeFlag = 0; zc->appliedParams.fParams.contentSizeFlag = 0;
DEBUGLOG(4, "pledged content size : %u ; flag : %u", DEBUGLOG(5, "pledged content size : %u ; flag : %u",
(U32)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag); (U32)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
zc->blockSize = blockSize; zc->blockSize = blockSize;
@@ -935,7 +927,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
/* opt parser space */ /* opt parser space */
if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) { if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) {
DEBUGLOG(4, "reserving optimal parser space"); DEBUGLOG(5, "reserving optimal parser space");
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
zc->optState.litFreq = (U32*)ptr; zc->optState.litFreq = (U32*)ptr;
zc->optState.litLengthFreq = zc->optState.litFreq + (1<<Litbits); zc->optState.litLengthFreq = zc->optState.litFreq + (1<<Litbits);
@@ -959,7 +951,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
} }
/* table Space */ /* table Space */
DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset);
if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */ if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
zc->hashTable = (U32*)(ptr); zc->hashTable = (U32*)(ptr);
@@ -1008,16 +999,15 @@ void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
/*! ZSTD_copyCCtx_internal() : /*! ZSTD_copyCCtx_internal() :
* Duplicate an existing context `srcCCtx` into another one `dstCCtx`. * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
* The "context", in this case, refers to the hash and chain tables, entropy
* tables, and dictionary offsets.
* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
* The "context", in this case, refers to the hash and chain tables, * pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1
* entropy tables, and dictionary references. * @return : 0, or an error code */
* `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx.
* @return : 0, or an error code */
static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
const ZSTD_CCtx* srcCCtx, const ZSTD_CCtx* srcCCtx,
unsigned windowLog,
ZSTD_frameParameters fParams, ZSTD_frameParameters fParams,
U64 pledgedSrcSize, unsigned long long pledgedSrcSize,
ZSTD_buffered_policy_e zbuff) ZSTD_buffered_policy_e zbuff)
{ {
DEBUGLOG(5, "ZSTD_copyCCtx_internal"); DEBUGLOG(5, "ZSTD_copyCCtx_internal");
@@ -1027,7 +1017,6 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
{ ZSTD_CCtx_params params = dstCCtx->requestedParams; { ZSTD_CCtx_params params = dstCCtx->requestedParams;
/* Copy only compression parameters related to tables. */ /* Copy only compression parameters related to tables. */
params.cParams = srcCCtx->appliedParams.cParams; params.cParams = srcCCtx->appliedParams.cParams;
if (windowLog) params.cParams.windowLog = windowLog;
params.fParams = fParams; params.fParams = fParams;
ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
ZSTDcrp_noMemset, zbuff); ZSTDcrp_noMemset, zbuff);
@@ -1056,12 +1045,6 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
/* copy entropy tables */ /* copy entropy tables */
memcpy(dstCCtx->entropy, srcCCtx->entropy, sizeof(ZSTD_entropyCTables_t)); memcpy(dstCCtx->entropy, srcCCtx->entropy, sizeof(ZSTD_entropyCTables_t));
/* copy repcodes */
{
int i;
for (i = 0; i < ZSTD_REP_NUM; ++i)
dstCCtx->seqStore.rep[i] = srcCCtx->seqStore.rep[i];
}
return 0; return 0;
} }
@@ -1076,12 +1059,9 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long
ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0); ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; fParams.contentSizeFlag = pledgedSrcSize>0;
fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, fParams, pledgedSrcSize, zbuff);
0 /*windowLog from srcCCtx*/, fParams, pledgedSrcSize,
zbuff);
} }
@@ -1258,7 +1238,7 @@ static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t * entropy,
ostart[4] = (BYTE)(cLitSize >> 10); ostart[4] = (BYTE)(cLitSize >> 10);
break; break;
} }
default: /* not possible : lhSize is {3,4,5} */ default: /* not possible : lhSize is {3,4,5} */
assert(0); assert(0);
} }
return lhSize+cLitSize; return lhSize+cLitSize;
@@ -1267,6 +1247,8 @@ static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t * entropy,
void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
{ {
BYTE const LL_deltaCode = 19;
BYTE const ML_deltaCode = 36;
const seqDef* const sequences = seqStorePtr->sequencesStart; const seqDef* const sequences = seqStorePtr->sequencesStart;
BYTE* const llCodeTable = seqStorePtr->llCode; BYTE* const llCodeTable = seqStorePtr->llCode;
BYTE* const ofCodeTable = seqStorePtr->ofCode; BYTE* const ofCodeTable = seqStorePtr->ofCode;
@@ -1276,9 +1258,9 @@ void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
for (u=0; u<nbSeq; u++) { for (u=0; u<nbSeq; u++) {
U32 const llv = sequences[u].litLength; U32 const llv = sequences[u].litLength;
U32 const mlv = sequences[u].matchLength; U32 const mlv = sequences[u].matchLength;
llCodeTable[u] = (BYTE)ZSTD_LLcode(llv); llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset); ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv); mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
} }
if (seqStorePtr->longLengthID==1) if (seqStorePtr->longLengthID==1)
llCodeTable[seqStorePtr->longLengthPos] = MaxLL; llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
@@ -1291,8 +1273,7 @@ typedef enum {
ZSTD_defaultAllowed = 1 ZSTD_defaultAllowed = 1
} ZSTD_defaultPolicy_e; } ZSTD_defaultPolicy_e;
MEM_STATIC MEM_STATIC symbolEncodingType_e ZSTD_selectEncodingType(
symbolEncodingType_e ZSTD_selectEncodingType(
FSE_repeat* repeatMode, size_t const mostFrequent, size_t nbSeq, FSE_repeat* repeatMode, size_t const mostFrequent, size_t nbSeq,
U32 defaultNormLog, ZSTD_defaultPolicy_e const isDefaultAllowed) U32 defaultNormLog, ZSTD_defaultPolicy_e const isDefaultAllowed)
{ {
@@ -1300,7 +1281,6 @@ symbolEncodingType_e ZSTD_selectEncodingType(
#define MAX_SEQ_FOR_STATIC_FSE 1000 #define MAX_SEQ_FOR_STATIC_FSE 1000
ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0); ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
if ((mostFrequent == nbSeq) && (!isDefaultAllowed || nbSeq > 2)) { if ((mostFrequent == nbSeq) && (!isDefaultAllowed || nbSeq > 2)) {
DEBUGLOG(5, "Selected set_rle");
/* Prefer set_basic over set_rle when there are 2 or less symbols, /* Prefer set_basic over set_rle when there are 2 or less symbols,
* since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol. * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
* If basic encoding isn't possible, always choose RLE. * If basic encoding isn't possible, always choose RLE.
@@ -1308,30 +1288,18 @@ symbolEncodingType_e ZSTD_selectEncodingType(
*repeatMode = FSE_repeat_check; *repeatMode = FSE_repeat_check;
return set_rle; return set_rle;
} }
if ( isDefaultAllowed if (isDefaultAllowed && (*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
&& (*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
DEBUGLOG(5, "Selected set_repeat");
return set_repeat; return set_repeat;
} }
if ( isDefaultAllowed if (isDefaultAllowed && ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1))))) {
&& ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1)))) ) { *repeatMode = FSE_repeat_valid;
DEBUGLOG(5, "Selected set_basic");
/* The format allows default tables to be repeated, but it isn't useful.
* When using simple heuristics to select encoding type, we don't want
* to confuse these tables with dictionaries. When running more careful
* analysis, we don't need to waste time checking both repeating tables
* and default tables.
*/
*repeatMode = FSE_repeat_none;
return set_basic; return set_basic;
} }
DEBUGLOG(5, "Selected set_compressed");
*repeatMode = FSE_repeat_check; *repeatMode = FSE_repeat_check;
return set_compressed; return set_compressed;
} }
MEM_STATIC MEM_STATIC size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
FSE_CTable* CTable, U32 FSELog, symbolEncodingType_e type, FSE_CTable* CTable, U32 FSELog, symbolEncodingType_e type,
U32* count, U32 max, U32* count, U32 max,
BYTE const* codeTable, size_t nbSeq, BYTE const* codeTable, size_t nbSeq,
@@ -1349,7 +1317,7 @@ size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
case set_repeat: case set_repeat:
return 0; return 0;
case set_basic: case set_basic:
CHECK_F(FSE_buildCTable_wksp(CTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */ CHECK_F(FSE_buildCTable_wksp(CTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize));
return 0; return 0;
case set_compressed: { case set_compressed: {
S16 norm[MaxSeq + 1]; S16 norm[MaxSeq + 1];
@@ -1371,13 +1339,11 @@ size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
} }
} }
MEM_STATIC MEM_STATIC size_t ZSTD_encodeSequences(void* dst, size_t dstCapacity,
size_t ZSTD_encodeSequences( FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
void* dst, size_t dstCapacity, FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, seqDef const* sequences, size_t nbSeq, int longOffsets)
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
seqDef const* sequences, size_t nbSeq, int longOffsets)
{ {
BIT_CStream_t blockStream; BIT_CStream_t blockStream;
FSE_CState_t stateMatchLength; FSE_CState_t stateMatchLength;
@@ -1414,12 +1380,8 @@ size_t ZSTD_encodeSequences(
BYTE const ofCode = ofCodeTable[n]; BYTE const ofCode = ofCodeTable[n];
BYTE const mlCode = mlCodeTable[n]; BYTE const mlCode = mlCodeTable[n];
U32 const llBits = LL_bits[llCode]; U32 const llBits = LL_bits[llCode];
U32 const ofBits = ofCode; U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
U32 const mlBits = ML_bits[mlCode]; U32 const mlBits = ML_bits[mlCode];
DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u",
sequences[n].litLength,
sequences[n].matchLength + MINMATCH,
sequences[n].offset); /* 32b*/ /* 64b*/
/* (7)*/ /* (7)*/ /* (7)*/ /* (7)*/
FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */ FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */ FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
@@ -1485,18 +1447,14 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
entropy, cParams->strategy, op, dstCapacity, literals, litSize); entropy, cParams->strategy, op, dstCapacity, literals, litSize);
if (ZSTD_isError(cSize)) if (ZSTD_isError(cSize))
return cSize; return cSize;
assert(cSize <= dstCapacity);
op += cSize; op += cSize;
} }
/* Sequences Header */ /* Sequences Header */
if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/) return ERROR(dstSize_tooSmall); if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
if (nbSeq < 0x7F) if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
*op++ = (BYTE)nbSeq; else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
else if (nbSeq < LONGNBSEQ) else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
else
op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
if (nbSeq==0) return op - ostart; if (nbSeq==0) return op - ostart;
/* seqHead : flags for FSE encoding type */ /* seqHead : flags for FSE encoding type */
@@ -1504,10 +1462,9 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
/* convert length/distances into codes */ /* convert length/distances into codes */
ZSTD_seqToCodes(seqStorePtr); ZSTD_seqToCodes(seqStorePtr);
/* build CTable for Literal Lengths */ /* CTable for Literal Lengths */
{ U32 max = MaxLL; { U32 max = MaxLL;
size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, entropy->workspace); size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, entropy->workspace);
DEBUGLOG(5, "Building LL table");
LLtype = ZSTD_selectEncodingType(&entropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed); LLtype = ZSTD_selectEncodingType(&entropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed);
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL, count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
@@ -1515,12 +1472,11 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
if (ZSTD_isError(countSize)) return countSize; if (ZSTD_isError(countSize)) return countSize;
op += countSize; op += countSize;
} } } }
/* build CTable for Offsets */ /* CTable for Offsets */
{ U32 max = MaxOff; { U32 max = MaxOff;
size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, entropy->workspace); size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, entropy->workspace);
/* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; ZSTD_defaultPolicy_e const defaultPolicy = max <= DefaultMaxOff ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
DEBUGLOG(5, "Building OF table");
Offtype = ZSTD_selectEncodingType(&entropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy); Offtype = ZSTD_selectEncodingType(&entropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy);
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
@@ -1528,10 +1484,9 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
if (ZSTD_isError(countSize)) return countSize; if (ZSTD_isError(countSize)) return countSize;
op += countSize; op += countSize;
} } } }
/* build CTable for MatchLengths */ /* CTable for MatchLengths */
{ U32 max = MaxML; { U32 max = MaxML;
size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, entropy->workspace); size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, entropy->workspace);
DEBUGLOG(5, "Building ML table");
MLtype = ZSTD_selectEncodingType(&entropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed); MLtype = ZSTD_selectEncodingType(&entropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed);
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML, count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
@@ -1542,15 +1497,13 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
*seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
{ size_t const bitstreamSize = ZSTD_encodeSequences( { size_t const streamSize = ZSTD_encodeSequences(op, oend - op,
op, oend - op, CTable_MatchLength, mlCodeTable,
CTable_MatchLength, mlCodeTable, CTable_OffsetBits, ofCodeTable,
CTable_OffsetBits, ofCodeTable, CTable_LitLength, llCodeTable,
CTable_LitLength, llCodeTable, sequences, nbSeq, longOffsets);
sequences, nbSeq, if (ZSTD_isError(streamSize)) return streamSize;
longOffsets); op += streamSize;
if (ZSTD_isError(bitstreamSize)) return bitstreamSize;
op += bitstreamSize;
} }
return op - ostart; return op - ostart;
@@ -1564,33 +1517,27 @@ MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
{ {
size_t const cSize = ZSTD_compressSequences_internal(seqStorePtr, entropy, cParams, size_t const cSize = ZSTD_compressSequences_internal(seqStorePtr, entropy, cParams,
dst, dstCapacity); dst, dstCapacity);
size_t const minGain = ZSTD_minGain(srcSize);
size_t const maxCSize = srcSize - minGain;
/* If the srcSize <= dstCapacity, then there is enough space to write a /* If the srcSize <= dstCapacity, then there is enough space to write a
* raw uncompressed block. Since we ran out of space, the block must not * raw uncompressed block. Since we ran out of space, the block must not
* be compressible, so fall back to a raw uncompressed block. * be compressible, so fall back to a raw uncompressed block.
*/ */
int const uncompressibleError = (cSize == ERROR(dstSize_tooSmall)) && (srcSize <= dstCapacity); int const uncompressibleError = cSize == ERROR(dstSize_tooSmall) && srcSize <= dstCapacity;
if (ZSTD_isError(cSize) && !uncompressibleError) if (ZSTD_isError(cSize) && !uncompressibleError)
return cSize; return cSize;
/* We check that dictionaries have offset codes available for the first
* block. After the first block, the offcode table might not have large
* enough codes to represent the offsets in the data.
*/
if (entropy->offcode_repeatMode == FSE_repeat_valid)
entropy->offcode_repeatMode = FSE_repeat_check;
/* Check compressibility */ /* Check compressibility */
{ size_t const minGain = ZSTD_minGain(srcSize); /* note : fixed formula, maybe should depend on compression level, or strategy */ if (cSize >= maxCSize || uncompressibleError) {
size_t const maxCSize = srcSize - minGain; entropy->hufCTable_repeatMode = HUF_repeat_none;
if (cSize >= maxCSize || uncompressibleError) { entropy->offcode_repeatMode = FSE_repeat_none;
entropy->hufCTable_repeatMode = HUF_repeat_none; entropy->matchlength_repeatMode = FSE_repeat_none;
entropy->offcode_repeatMode = FSE_repeat_none; entropy->litlength_repeatMode = FSE_repeat_none;
entropy->matchlength_repeatMode = FSE_repeat_none; return 0;
entropy->litlength_repeatMode = FSE_repeat_none; }
return 0; /* block not compressed */
} }
assert(!ZSTD_isError(cSize)); assert(!ZSTD_isError(cSize));
/* block is compressed => confirm repcodes in history */ /* confirm repcodes */
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->rep[i] = seqStorePtr->repToConfirm[i]; } { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->rep[i] = seqStorePtr->repToConfirm[i]; }
return cSize; return cSize;
} }
@@ -1612,9 +1559,9 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict
ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict } ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict }
}; };
ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
assert((U32)strat >= (U32)ZSTD_fast); assert((U32)strat >= (U32)ZSTD_fast);
assert((U32)strat <= (U32)ZSTD_btultra); assert((U32)strat <= (U32)ZSTD_btultra);
return blockCompressor[extDict!=0][(U32)strat]; return blockCompressor[extDict!=0][(U32)strat];
} }
@@ -1625,38 +1572,30 @@ static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
seqStorePtr->lit += lastLLSize; seqStorePtr->lit += lastLLSize;
} }
static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
{
ssPtr->lit = ssPtr->litStart;
ssPtr->sequences = ssPtr->sequencesStart;
ssPtr->longLengthID = 0;
}
static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize) static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
{ {
DEBUGLOG(5, "ZSTD_compressBlock_internal : dstCapacity = %u", (U32)dstCapacity); const BYTE* const base = zc->base;
if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) const BYTE* const istart = (const BYTE*)src;
return 0; /* don't even attempt compression below a certain srcSize */ const U32 current = (U32)(istart-base);
size_t lastLLSize;
const BYTE* anchor;
U32 const extDict = zc->lowLimit < zc->dictLimit;
const ZSTD_blockCompressor blockCompressor =
zc->appliedParams.ldmParams.enableLdm
? (extDict ? ZSTD_compressBlock_ldm_extDict : ZSTD_compressBlock_ldm)
: ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */
ZSTD_resetSeqStore(&(zc->seqStore)); ZSTD_resetSeqStore(&(zc->seqStore));
if (current > zc->nextToUpdate + 384)
zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384)); /* limited update after finding a very long match */
lastLLSize = blockCompressor(zc, src, srcSize);
/* Last literals */
anchor = (const BYTE*)src + srcSize - lastLLSize;
ZSTD_storeLastLiterals(&zc->seqStore, anchor, lastLLSize);
/* limited update after a very long match */
{ const BYTE* const base = zc->base;
const BYTE* const istart = (const BYTE*)src;
const U32 current = (U32)(istart-base);
if (current > zc->nextToUpdate + 384)
zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384));
}
/* find and store sequences */
{ U32 const extDict = zc->lowLimit < zc->dictLimit;
const ZSTD_blockCompressor blockCompressor =
zc->appliedParams.ldmParams.enableLdm
? (extDict ? ZSTD_compressBlock_ldm_extDict : ZSTD_compressBlock_ldm)
: ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
size_t const lastLLSize = blockCompressor(zc, src, srcSize);
const BYTE* const anchor = (const BYTE*)src + srcSize - lastLLSize;
ZSTD_storeLastLiterals(&zc->seqStore, anchor, lastLLSize);
}
/* encode */
return ZSTD_compressSequences(&zc->seqStore, zc->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize); return ZSTD_compressSequences(&zc->seqStore, zc->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize);
} }
@@ -1679,14 +1618,13 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
BYTE* const ostart = (BYTE*)dst; BYTE* const ostart = (BYTE*)dst;
BYTE* op = ostart; BYTE* op = ostart;
U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog;
assert(cctx->appliedParams.cParams.windowLog <= 31);
DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (U32)blockSize);
if (cctx->appliedParams.fParams.checksumFlag && srcSize) if (cctx->appliedParams.fParams.checksumFlag && srcSize)
XXH64_update(&cctx->xxhState, src, srcSize); XXH64_update(&cctx->xxhState, src, srcSize);
while (remaining) { while (remaining) {
U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
size_t cSize;
if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */ return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
@@ -1728,39 +1666,34 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
else cctx->nextToUpdate -= correction; else cctx->nextToUpdate -= correction;
DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x\n", correction, cctx->lowLimit); DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x\n", correction, cctx->lowLimit);
} }
/* enforce maxDist */
if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) { if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
/* enforce maxDist */
U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist; U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit; if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit; if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
} }
{ size_t cSize = ZSTD_compressBlock_internal(cctx, cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, if (ZSTD_isError(cSize)) return cSize;
ip, blockSize);
if (ZSTD_isError(cSize)) return cSize;
if (cSize == 0) { /* block is not compressible */ if (cSize == 0) { /* block is not compressible */
U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3); U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall); if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
MEM_writeLE32(op, cBlockHeader24); /* 4th byte will be overwritten */ MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
memcpy(op + ZSTD_blockHeaderSize, ip, blockSize); memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
cSize = ZSTD_blockHeaderSize + blockSize; cSize = ZSTD_blockHeaderSize+blockSize;
} else { } else {
U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
MEM_writeLE24(op, cBlockHeader24); MEM_writeLE24(op, cBlockHeader24);
cSize += ZSTD_blockHeaderSize; cSize += ZSTD_blockHeaderSize;
} }
ip += blockSize; remaining -= blockSize;
assert(remaining >= blockSize); dstCapacity -= cSize;
remaining -= blockSize; ip += blockSize;
op += cSize; op += cSize;
assert(dstCapacity >= cSize); }
dstCapacity -= cSize;
DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u",
(U32)cSize);
} }
if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending; if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
return op-ostart; return op-ostart;
@@ -1786,6 +1719,7 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
!params.fParams.noDictIDFlag, dictID, dictIDSizeCode); !params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
if (params.format == ZSTD_f_zstd1) { if (params.format == ZSTD_f_zstd1) {
DEBUGLOG(4, "writing zstd magic number");
MEM_writeLE32(dst, ZSTD_MAGICNUMBER); MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
pos = 4; pos = 4;
} }
@@ -1819,7 +1753,8 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
const BYTE* const ip = (const BYTE*) src; const BYTE* const ip = (const BYTE*) src;
size_t fhSize = 0; size_t fhSize = 0;
DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u", cctx->stage); DEBUGLOG(5, "ZSTD_compressContinue_internal");
DEBUGLOG(5, "stage: %u", cctx->stage);
if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */ if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
if (frame && (cctx->stage==ZSTDcs_init)) { if (frame && (cctx->stage==ZSTDcs_init)) {
@@ -1831,21 +1766,17 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
cctx->stage = ZSTDcs_ongoing; cctx->stage = ZSTDcs_ongoing;
} }
if (!srcSize) return fhSize; /* do not generate an empty block if no input */
/* Check if blocks follow each other */ /* Check if blocks follow each other */
if (src != cctx->nextSrc) { if (src != cctx->nextSrc) {
/* not contiguous */ /* not contiguous */
size_t const distanceFromBase = (size_t)(cctx->nextSrc - cctx->base); ptrdiff_t const delta = cctx->nextSrc - ip;
cctx->lowLimit = cctx->dictLimit; cctx->lowLimit = cctx->dictLimit;
assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */ cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
cctx->dictLimit = (U32)distanceFromBase;
cctx->dictBase = cctx->base; cctx->dictBase = cctx->base;
cctx->base = ip - distanceFromBase; cctx->base -= delta;
cctx->nextToUpdate = cctx->dictLimit; cctx->nextToUpdate = cctx->dictLimit;
if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */ if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
} }
cctx->nextSrc = ip + srcSize;
/* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */ /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) { if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
@@ -1854,14 +1785,17 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
cctx->lowLimit = lowLimitMax; cctx->lowLimit = lowLimitMax;
} }
DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (U32)cctx->blockSize); cctx->nextSrc = ip + srcSize;
{ size_t const cSize = frame ?
if (srcSize) {
size_t const cSize = frame ?
ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize); ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
if (ZSTD_isError(cSize)) return cSize; if (ZSTD_isError(cSize)) return cSize;
cctx->consumedSrcSize += srcSize; cctx->consumedSrcSize += srcSize;
return cSize + fhSize; return cSize + fhSize;
} } else
return fhSize;
} }
size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
@@ -1898,7 +1832,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t
zc->lowLimit = zc->dictLimit; zc->lowLimit = zc->dictLimit;
zc->dictLimit = (U32)(zc->nextSrc - zc->base); zc->dictLimit = (U32)(zc->nextSrc - zc->base);
zc->dictBase = zc->base; zc->dictBase = zc->base;
zc->base = ip - zc->dictLimit; zc->base += ip - zc->nextSrc;
zc->nextToUpdate = zc->dictLimit; zc->nextToUpdate = zc->dictLimit;
zc->loadedDictEnd = zc->appliedParams.forceWindow ? 0 : (U32)(iend - zc->base); zc->loadedDictEnd = zc->appliedParams.forceWindow ? 0 : (U32)(iend - zc->base);
@@ -2049,7 +1983,7 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
const void* dict, size_t dictSize, const void* dict, size_t dictSize,
ZSTD_dictMode_e dictMode) ZSTD_dictMode_e dictMode)
{ {
DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); DEBUGLOG(5, "ZSTD_compress_insertDictionary");
if ((dict==NULL) || (dictSize<=8)) return 0; if ((dict==NULL) || (dictSize<=8)) return 0;
/* dict restricted modes */ /* dict restricted modes */
@@ -2058,7 +1992,7 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
if (dictMode == ZSTD_dm_auto) { if (dictMode == ZSTD_dm_auto) {
DEBUGLOG(4, "raw content dictionary detected"); DEBUGLOG(5, "raw content dictionary detected");
return ZSTD_loadDictionaryContent(cctx, dict, dictSize); return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
} }
if (dictMode == ZSTD_dm_fullDict) if (dictMode == ZSTD_dm_fullDict)
@@ -2072,22 +2006,21 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
/*! ZSTD_compressBegin_internal() : /*! ZSTD_compressBegin_internal() :
* @return : 0, or an error code */ * @return : 0, or an error code */
size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
const void* dict, size_t dictSize, const void* dict, size_t dictSize,
ZSTD_dictMode_e dictMode, ZSTD_dictMode_e dictMode,
const ZSTD_CDict* cdict, const ZSTD_CDict* cdict,
ZSTD_CCtx_params params, U64 pledgedSrcSize, ZSTD_CCtx_params params, U64 pledgedSrcSize,
ZSTD_buffered_policy_e zbuff) ZSTD_buffered_policy_e zbuff)
{ {
DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params.cParams.windowLog); DEBUGLOG(4, "ZSTD_compressBegin_internal");
/* params are supposed to be fully validated at this point */ /* params are supposed to be fully validated at this point */
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
assert(!((dict) && (cdict))); /* either dict or cdict, not both */ assert(!((dict) && (cdict))); /* either dict or cdict, not both */
if (cdict && cdict->dictContentSize>0) { if (cdict && cdict->dictContentSize>0) {
cctx->requestedParams = params;
return ZSTD_copyCCtx_internal(cctx, cdict->refContext, return ZSTD_copyCCtx_internal(cctx, cdict->refContext,
params.cParams.windowLog, params.fParams, pledgedSrcSize, params.fParams, pledgedSrcSize,
zbuff); zbuff);
} }
@@ -2096,19 +2029,16 @@ size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
return ZSTD_compress_insertDictionary(cctx, dict, dictSize, dictMode); return ZSTD_compress_insertDictionary(cctx, dict, dictSize, dictMode);
} }
size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, size_t ZSTD_compressBegin_advanced_internal(
ZSTD_CCtx* cctx,
const void* dict, size_t dictSize, const void* dict, size_t dictSize,
ZSTD_dictMode_e dictMode, ZSTD_dictMode_e dictMode,
const ZSTD_CDict* cdict,
ZSTD_CCtx_params params, ZSTD_CCtx_params params,
unsigned long long pledgedSrcSize) unsigned long long pledgedSrcSize)
{ {
DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params.cParams.windowLog);
/* compression parameters verification and optimization */ /* compression parameters verification and optimization */
CHECK_F( ZSTD_checkCParams(params.cParams) ); CHECK_F( ZSTD_checkCParams(params.cParams) );
return ZSTD_compressBegin_internal(cctx, return ZSTD_compressBegin_internal(cctx, dict, dictSize, dictMode, NULL,
dict, dictSize, dictMode,
cdict,
params, pledgedSrcSize, params, pledgedSrcSize,
ZSTDb_not_buffered); ZSTDb_not_buffered);
} }
@@ -2121,10 +2051,9 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
{ {
ZSTD_CCtx_params const cctxParams = ZSTD_CCtx_params const cctxParams =
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
return ZSTD_compressBegin_advanced_internal(cctx, return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, ZSTD_dm_auto,
dict, dictSize, ZSTD_dm_auto, cctxParams,
NULL /*cdict*/, pledgedSrcSize);
cctxParams, pledgedSrcSize);
} }
size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
@@ -2132,9 +2061,8 @@ size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t di
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
ZSTD_CCtx_params const cctxParams = ZSTD_CCtx_params const cctxParams =
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
DEBUGLOG(4, "ZSTD_compressBegin_usingDict");
return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); cctxParams, 0, ZSTDb_not_buffered);
} }
size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
@@ -2215,7 +2143,6 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
{ {
ZSTD_CCtx_params const cctxParams = ZSTD_CCtx_params const cctxParams =
ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
DEBUGLOG(4, "ZSTD_compress_internal");
return ZSTD_compress_advanced_internal(cctx, return ZSTD_compress_advanced_internal(cctx,
dst, dstCapacity, dst, dstCapacity,
src, srcSize, src, srcSize,
@@ -2229,7 +2156,6 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
const void* dict,size_t dictSize, const void* dict,size_t dictSize,
ZSTD_parameters params) ZSTD_parameters params)
{ {
DEBUGLOG(4, "ZSTD_compress_advanced");
CHECK_F(ZSTD_checkCParams(params.cParams)); CHECK_F(ZSTD_checkCParams(params.cParams));
return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params); return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
} }
@@ -2242,7 +2168,6 @@ size_t ZSTD_compress_advanced_internal(
const void* dict,size_t dictSize, const void* dict,size_t dictSize,
ZSTD_CCtx_params params) ZSTD_CCtx_params params)
{ {
DEBUGLOG(4, "ZSTD_compress_advanced_internal");
CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL, CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
params, srcSize, ZSTDb_not_buffered) ); params, srcSize, ZSTDb_not_buffered) );
return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
@@ -2251,10 +2176,8 @@ size_t ZSTD_compress_advanced_internal(
size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
const void* dict, size_t dictSize, int compressionLevel) const void* dict, size_t dictSize, int compressionLevel)
{ {
ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize ? srcSize : 1, dict ? dictSize : 0); ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
params.fParams.contentSizeFlag = 1; params.fParams.contentSizeFlag = 1;
DEBUGLOG(4, "ZSTD_compress_usingDict (level=%i, srcSize=%u, dictSize=%u)",
compressionLevel, (U32)srcSize, (U32)dictSize);
return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params); return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
} }
@@ -2311,7 +2234,7 @@ static size_t ZSTD_initCDict_internal(
ZSTD_dictMode_e dictMode, ZSTD_dictMode_e dictMode,
ZSTD_compressionParameters cParams) ZSTD_compressionParameters cParams)
{ {
DEBUGLOG(3, "ZSTD_initCDict_internal, mode %u", (U32)dictMode); DEBUGLOG(5, "ZSTD_initCDict_internal, mode %u", (U32)dictMode);
if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
cdict->dictBuffer = NULL; cdict->dictBuffer = NULL;
cdict->dictContent = dictBuffer; cdict->dictContent = dictBuffer;
@@ -2341,7 +2264,7 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
ZSTD_dictMode_e dictMode, ZSTD_dictMode_e dictMode,
ZSTD_compressionParameters cParams, ZSTD_customMem customMem) ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
{ {
DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode); DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode);
if (!customMem.customAlloc ^ !customMem.customFree) return NULL; if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
{ ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
@@ -2416,9 +2339,9 @@ ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
+ cctxSize; + cctxSize;
ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
void* ptr; void* ptr;
DEBUGLOG(4, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7); DEBUGLOG(5, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7);
if ((size_t)workspace & 7) return NULL; /* 8-aligned */ if ((size_t)workspace & 7) return NULL; /* 8-aligned */
DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u", DEBUGLOG(5, "(workspaceSize < neededSize) : (%u < %u) => %u",
(U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize)); (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
if (workspaceSize < neededSize) return NULL; if (workspaceSize < neededSize) return NULL;
@@ -2450,11 +2373,11 @@ size_t ZSTD_compressBegin_usingCDict_advanced(
ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
{ {
DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
if (cdict==NULL) return ERROR(dictionary_wrong); if (cdict==NULL) return ERROR(dictionary_wrong);
{ ZSTD_CCtx_params params = cctx->requestedParams; { ZSTD_CCtx_params params = cctx->requestedParams;
params.cParams = ZSTD_getCParamsFromCDict(cdict); params.cParams = ZSTD_getCParamsFromCDict(cdict);
params.fParams = fParams; params.fParams = fParams;
DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced");
return ZSTD_compressBegin_internal(cctx, return ZSTD_compressBegin_internal(cctx,
NULL, 0, ZSTD_dm_auto, NULL, 0, ZSTD_dm_auto,
cdict, cdict,
@@ -2469,7 +2392,7 @@ size_t ZSTD_compressBegin_usingCDict_advanced(
size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
{ {
ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); DEBUGLOG(5, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0); return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0);
} }
@@ -2504,7 +2427,6 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
ZSTD_CStream* ZSTD_createCStream(void) ZSTD_CStream* ZSTD_createCStream(void)
{ {
DEBUGLOG(3, "ZSTD_createCStream");
return ZSTD_createCStream_advanced(ZSTD_defaultCMem); return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
} }
@@ -2535,9 +2457,9 @@ size_t ZSTD_CStreamOutSize(void)
} }
static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs,
const void* const dict, size_t const dictSize, ZSTD_dictMode_e const dictMode, const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode,
const ZSTD_CDict* const cdict, const ZSTD_CDict* cdict,
ZSTD_CCtx_params const params, unsigned long long const pledgedSrcSize) const ZSTD_CCtx_params params, unsigned long long pledgedSrcSize)
{ {
DEBUGLOG(4, "ZSTD_resetCStream_internal"); DEBUGLOG(4, "ZSTD_resetCStream_internal");
/* params are supposed to be fully validated at this point */ /* params are supposed to be fully validated at this point */
@@ -2545,35 +2467,31 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs,
assert(!((dict) && (cdict))); /* either dict or cdict, not both */ assert(!((dict) && (cdict))); /* either dict or cdict, not both */
CHECK_F( ZSTD_compressBegin_internal(zcs, CHECK_F( ZSTD_compressBegin_internal(zcs,
dict, dictSize, dictMode, dict, dictSize, dictMode,
cdict, cdict,
params, pledgedSrcSize, params, pledgedSrcSize,
ZSTDb_buffered) ); ZSTDb_buffered) );
zcs->inToCompress = 0; zcs->inToCompress = 0;
zcs->inBuffPos = 0; zcs->inBuffPos = 0;
zcs->inBuffTarget = zcs->blockSize zcs->inBuffTarget = zcs->blockSize;
+ (zcs->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */
zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
zcs->streamStage = zcss_load; zcs->streamStage = zcss_load;
zcs->frameEnded = 0; zcs->frameEnded = 0;
return 0; /* ready to go */ return 0; /* ready to go */
} }
/* ZSTD_resetCStream():
* pledgedSrcSize == 0 means "unknown" */
size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
{ {
ZSTD_CCtx_params params = zcs->requestedParams; ZSTD_CCtx_params params = zcs->requestedParams;
DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (U32)pledgedSrcSize); params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
params.fParams.contentSizeFlag = 1;
params.cParams = ZSTD_getCParamsFromCCtxParams(params, pledgedSrcSize, 0); params.cParams = ZSTD_getCParamsFromCCtxParams(params, pledgedSrcSize, 0);
DEBUGLOG(4, "ZSTD_resetCStream");
return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize); return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize);
} }
/*! ZSTD_initCStream_internal() : /*! ZSTD_initCStream_internal() :
* Note : for lib/compress only. Used by zstdmt_compress.c. * Note : not static, but hidden (not exposed). Used by zstdmt_compress.c
* Assumption 1 : params are valid * Assumption 1 : params are valid
* Assumption 2 : either dict, or cdict, is defined, not both */ * Assumption 2 : either dict, or cdict, is defined, not both */
size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
@@ -2585,7 +2503,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
assert(!((dict) && (cdict))); /* either dict or cdict, not both */ assert(!((dict) && (cdict))); /* either dict or cdict, not both */
if (dict && dictSize >= 8) { if (dict && dictSize >= 8) {
DEBUGLOG(4, "loading dictionary of size %u", (U32)dictSize); DEBUGLOG(5, "loading dictionary of size %u", (U32)dictSize);
if (zcs->staticSize) { /* static CCtx : never uses malloc */ if (zcs->staticSize) { /* static CCtx : never uses malloc */
/* incompatible with internal cdict creation */ /* incompatible with internal cdict creation */
return ERROR(memory_allocation); return ERROR(memory_allocation);
@@ -2598,14 +2516,14 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
} else { } else {
if (cdict) { if (cdict) {
params.cParams = ZSTD_getCParamsFromCDict(cdict); /* cParams are enforced from cdict; it includes windowLog */ params.cParams = ZSTD_getCParamsFromCDict(cdict); /* cParams are enforced from cdict */
} }
ZSTD_freeCDict(zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal);
zcs->cdictLocal = NULL; zcs->cdictLocal = NULL;
zcs->cdict = cdict; zcs->cdict = cdict;
} }
params.compressionLevel = ZSTD_CLEVEL_CUSTOM; /* enforce usage of cParams, instead of a dynamic derivation from cLevel (but does that happen ?) */ params.compressionLevel = ZSTD_CLEVEL_CUSTOM;
zcs->requestedParams = params; zcs->requestedParams = params;
return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize); return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize);
@@ -2617,9 +2535,8 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
const ZSTD_CDict* cdict, const ZSTD_CDict* cdict,
ZSTD_frameParameters fParams, ZSTD_frameParameters fParams,
unsigned long long pledgedSrcSize) unsigned long long pledgedSrcSize)
{ { /* cannot handle NULL cdict (does not know what to do) */
DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced"); if (!cdict) return ERROR(dictionary_wrong);
if (!cdict) return ERROR(dictionary_wrong); /* cannot handle NULL cdict (does not know what to do) */
{ ZSTD_CCtx_params params = zcs->requestedParams; { ZSTD_CCtx_params params = zcs->requestedParams;
params.cParams = ZSTD_getCParamsFromCDict(cdict); params.cParams = ZSTD_getCParamsFromCDict(cdict);
params.fParams = fParams; params.fParams = fParams;
@@ -2632,25 +2549,18 @@ size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
/* note : cdict must outlive compression session */ /* note : cdict must outlive compression session */
size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
{ {
ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksum */, 0 /* hideDictID */ }; ZSTD_frameParameters const fParams = { 0 /* contentSize */, 0 /* checksum */, 0 /* hideDictID */ };
DEBUGLOG(4, "ZSTD_initCStream_usingCDict"); return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, 0); /* note : will check that cdict != NULL */
return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); /* note : will check that cdict != NULL */
} }
/* ZSTD_initCStream_advanced() :
* pledgedSrcSize must be correct.
* if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
* dict is loaded with default parameters ZSTD_dm_auto and ZSTD_dlm_byCopy. */
size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
const void* dict, size_t dictSize, const void* dict, size_t dictSize,
ZSTD_parameters params, unsigned long long pledgedSrcSize) ZSTD_parameters params, unsigned long long pledgedSrcSize)
{ {
ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); ZSTD_CCtx_params const cctxParams =
DEBUGLOG(4, "ZSTD_initCStream_advanced: pledgedSrcSize=%u, flag=%u", ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
(U32)pledgedSrcSize, params.fParams.contentSizeFlag);
CHECK_F( ZSTD_checkCParams(params.cParams) ); CHECK_F( ZSTD_checkCParams(params.cParams) );
if ((pledgedSrcSize==0) && (params.fParams.contentSizeFlag==0)) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* for compatibility with older programs relying on this behavior. Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. This line will be removed in the future. */ return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, pledgedSrcSize);
return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL /*cdict*/, cctxParams, pledgedSrcSize);
} }
size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
@@ -2658,21 +2568,21 @@ size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t di
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
ZSTD_CCtx_params const cctxParams = ZSTD_CCtx_params const cctxParams =
ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN); return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, 0);
} }
size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss) size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
{ {
U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; /* temporary : 0 interpreted as "unknown" during transition period. Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. `0` will be interpreted as "empty" in the future */ ZSTD_CCtx_params cctxParams;
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0); ZSTD_parameters const params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
cctxParams.fParams.contentSizeFlag = (pledgedSrcSize>0);
return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, cctxParams, pledgedSrcSize); return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, cctxParams, pledgedSrcSize);
} }
size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
{ {
DEBUGLOG(4, "ZSTD_initCStream"); return ZSTD_initCStream_srcSize(zcs, compressionLevel, 0);
return ZSTD_initCStream_srcSize(zcs, compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN);
} }
/*====== Compression ======*/ /*====== Compression ======*/
@@ -2705,9 +2615,9 @@ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
/* check expectations */ /* check expectations */
DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (U32)flushMode); DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (U32)flushMode);
assert(zcs->inBuff != NULL); assert(zcs->inBuff != NULL);
assert(zcs->inBuffSize > 0); assert(zcs->inBuffSize>0);
assert(zcs->outBuff != NULL); assert(zcs->outBuff!= NULL);
assert(zcs->outBuffSize > 0); assert(zcs->outBuffSize>0);
assert(output->pos <= output->size); assert(output->pos <= output->size);
assert(input->pos <= input->size); assert(input->pos <= input->size);
@@ -2847,7 +2757,7 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
ZSTD_inBuffer* input, ZSTD_inBuffer* input,
ZSTD_EndDirective endOp) ZSTD_EndDirective endOp)
{ {
DEBUGLOG(5, "ZSTD_compress_generic, endOp=%u ", (U32)endOp); DEBUGLOG(5, "ZSTD_compress_generic");
/* check conditions */ /* check conditions */
if (output->pos > output->size) return ERROR(GENERIC); if (output->pos > output->size) return ERROR(GENERIC);
if (input->pos > input->size) return ERROR(GENERIC); if (input->pos > input->size) return ERROR(GENERIC);
@@ -2855,47 +2765,42 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
/* transparent initialization stage */ /* transparent initialization stage */
if (cctx->streamStage == zcss_init) { if (cctx->streamStage == zcss_init) {
ZSTD_CCtx_params params = cctx->requestedParams;
ZSTD_prefixDict const prefixDict = cctx->prefixDict; ZSTD_prefixDict const prefixDict = cctx->prefixDict;
ZSTD_CCtx_params params = cctx->requestedParams;
params.cParams = ZSTD_getCParamsFromCCtxParams(
cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
DEBUGLOG(4, "ZSTD_compress_generic : transparent init stage"); DEBUGLOG(4, "ZSTD_compress_generic : transparent init stage");
if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */
params.cParams = ZSTD_getCParamsFromCCtxParams(
cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
#ifdef ZSTD_MULTITHREAD #ifdef ZSTD_MULTITHREAD
if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN)
params.nbThreads = 1; /* do not invoke multi-threading when src size is too small */
if (params.nbThreads > 1) { if (params.nbThreads > 1) {
if (cctx->mtctx == NULL || (params.nbThreads != ZSTDMT_getNbThreads(cctx->mtctx))) { if (cctx->mtctx == NULL || cctx->appliedParams.nbThreads != params.nbThreads) {
DEBUGLOG(4, "ZSTD_compress_generic: creating new mtctx for nbThreads=%u (previous: %u)",
params.nbThreads, ZSTDMT_getNbThreads(cctx->mtctx));
ZSTDMT_freeCCtx(cctx->mtctx); ZSTDMT_freeCCtx(cctx->mtctx);
cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbThreads, cctx->customMem); cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbThreads, cctx->customMem);
if (cctx->mtctx == NULL) return ERROR(memory_allocation); if (cctx->mtctx == NULL) return ERROR(memory_allocation);
} }
DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads); DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads);
CHECK_F( ZSTDMT_initCStream_internal( CHECK_F( ZSTDMT_initCStream_internal(
cctx->mtctx, cctx->mtctx,
prefixDict.dict, prefixDict.dictSize, ZSTD_dm_rawContent, prefixDict.dict, prefixDict.dictSize, ZSTD_dm_rawContent,
cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
cctx->streamStage = zcss_load; cctx->streamStage = zcss_load;
cctx->appliedParams.nbThreads = params.nbThreads; cctx->appliedParams.nbThreads = params.nbThreads;
} else } else
#endif #endif
{ CHECK_F( ZSTD_resetCStream_internal( {
CHECK_F( ZSTD_resetCStream_internal(
cctx, prefixDict.dict, prefixDict.dictSize, cctx, prefixDict.dict, prefixDict.dictSize,
prefixDict.dictMode, cctx->cdict, params, prefixDict.dictMode, cctx->cdict, params,
cctx->pledgedSrcSizePlusOne-1) ); cctx->pledgedSrcSizePlusOne-1) );
assert(cctx->streamStage == zcss_load);
assert(cctx->appliedParams.nbThreads <= 1);
} } } }
/* compression stage */ /* compression stage */
#ifdef ZSTD_MULTITHREAD #ifdef ZSTD_MULTITHREAD
if (cctx->appliedParams.nbThreads > 1) { if (cctx->appliedParams.nbThreads > 1) {
size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
DEBUGLOG(5, "ZSTDMT_compressStream_generic result : %u", (U32)flushMin);
if ( ZSTD_isError(flushMin) if ( ZSTD_isError(flushMin)
|| (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
ZSTD_startNewCompression(cctx); ZSTD_startNewCompression(cctx);
@@ -2945,7 +2850,8 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
{ size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE;
size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4; size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4;
size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize + lastBlockSize + checksumSize; size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize + lastBlockSize + checksumSize;
DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (U32)toFlush); DEBUGLOG(5, "ZSTD_endStream : remaining to flush : %u",
(unsigned)toFlush);
return toFlush; return toFlush;
} }
} }
@@ -2974,12 +2880,12 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
{ 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
{ 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */ { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
{ 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */ { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
{ 22, 21, 22, 4, 5, 16, ZSTD_btlazy2 }, /* level 15 */ { 22, 21, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
{ 22, 21, 22, 4, 5, 48, ZSTD_btopt }, /* level 16 */ { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
{ 23, 22, 22, 4, 4, 48, ZSTD_btopt }, /* level 17 */ { 23, 22, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
{ 23, 22, 22, 5, 3, 64, ZSTD_btopt }, /* level 18 */ { 23, 22, 22, 5, 4, 32, ZSTD_btopt }, /* level 18 */
{ 23, 23, 22, 7, 3,128, ZSTD_btopt }, /* level 19 */ { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
{ 25, 25, 23, 7, 3,128, ZSTD_btultra }, /* level 20 */ { 25, 25, 23, 7, 3, 64, ZSTD_btultra }, /* level 20 */
{ 26, 26, 24, 7, 3,256, ZSTD_btultra }, /* level 21 */ { 26, 26, 24, 7, 3,256, ZSTD_btultra }, /* level 21 */
{ 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */ { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */
}, },
@@ -3098,8 +3004,6 @@ ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long l
} }
#endif #endif
DEBUGLOG(4, "ZSTD_getCParams: cLevel=%i, srcSize=%u, dictSize=%u => table %u",
compressionLevel, (U32)srcSizeHint, (U32)dictSize, tableID);
if (compressionLevel <= 0) compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default; no negative compressionLevel yet */ if (compressionLevel <= 0) compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default; no negative compressionLevel yet */
if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL; if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
{ ZSTD_compressionParameters const cp = ZSTD_defaultCParameters[tableID][compressionLevel]; { ZSTD_compressionParameters const cp = ZSTD_defaultCParameters[tableID][compressionLevel];
@@ -3115,6 +3019,5 @@ ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeH
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize); ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
params.cParams = cParams; params.cParams = cParams;
params.fParams.contentSizeFlag = 1;
return params; return params;
} }
@@ -8,9 +8,6 @@
* You may select, at your option, one of the above-listed licenses. * You may select, at your option, one of the above-listed licenses.
*/ */
/* This header contains definitions
* that shall **only** be used by modules within lib/compress.
*/
#ifndef ZSTD_COMPRESS_H #ifndef ZSTD_COMPRESS_H
#define ZSTD_COMPRESS_H #define ZSTD_COMPRESS_H
@@ -46,95 +43,6 @@ typedef struct ZSTD_prefixDict_s {
ZSTD_dictMode_e dictMode; ZSTD_dictMode_e dictMode;
} ZSTD_prefixDict; } ZSTD_prefixDict;
typedef struct {
U32 hufCTable[HUF_CTABLE_SIZE_U32(255)];
FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
U32 workspace[HUF_WORKSPACE_SIZE_U32];
HUF_repeat hufCTable_repeatMode;
FSE_repeat offcode_repeatMode;
FSE_repeat matchlength_repeatMode;
FSE_repeat litlength_repeatMode;
} ZSTD_entropyCTables_t;
typedef struct {
U32 off;
U32 len;
} ZSTD_match_t;
typedef struct {
int price;
U32 off;
U32 mlen;
U32 litlen;
U32 rep[ZSTD_REP_NUM];
} ZSTD_optimal_t;
typedef struct {
/* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */
U32* litFreq; /* table of literals statistics, of size 256 */
U32* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
U32* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
U32* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
U32 litSum; /* nb of literals */
U32 litLengthSum; /* nb of litLength codes */
U32 matchLengthSum; /* nb of matchLength codes */
U32 offCodeSum; /* nb of offset codes */
/* begin updated by ZSTD_setLog2Prices */
U32 log2litSum; /* pow2 to compare log2(litfreq) to */
U32 log2litLengthSum; /* pow2 to compare log2(llfreq) to */
U32 log2matchLengthSum; /* pow2 to compare log2(mlfreq) to */
U32 log2offCodeSum; /* pow2 to compare log2(offreq) to */
/* end : updated by ZSTD_setLog2Prices */
U32 staticPrices; /* prices follow a pre-defined cost structure, statistics are irrelevant */
} optState_t;
typedef struct {
U32 offset;
U32 checksum;
} ldmEntry_t;
typedef struct {
ldmEntry_t* hashTable;
BYTE* bucketOffsets; /* Next position in bucket to insert entry */
U64 hashPower; /* Used to compute the rolling hash.
* Depends on ldmParams.minMatchLength */
} ldmState_t;
typedef struct {
U32 enableLdm; /* 1 if enable long distance matching */
U32 hashLog; /* Log size of hashTable */
U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */
U32 minMatchLength; /* Minimum match length */
U32 hashEveryLog; /* Log number of entries to skip */
} ldmParams_t;
struct ZSTD_CCtx_params_s {
ZSTD_format_e format;
ZSTD_compressionParameters cParams;
ZSTD_frameParameters fParams;
int compressionLevel;
U32 forceWindow; /* force back-references to respect limit of
* 1<<wLog, even for dictionary */
/* Multithreading: used to pass parameters to mtctx */
U32 nbThreads;
unsigned jobSize;
unsigned overlapSizeLog;
/* Long distance matching parameters */
ldmParams_t ldmParams;
/* For use with createCCtxParams() and freeCCtxParams() only */
ZSTD_customMem customMem;
}; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */
struct ZSTD_CCtx_s { struct ZSTD_CCtx_s {
const BYTE* nextSrc; /* next block here to continue on current prefix */ const BYTE* nextSrc; /* next block here to continue on current prefix */
const BYTE* base; /* All regular indexes relative to this position */ const BYTE* base; /* All regular indexes relative to this position */
@@ -191,51 +99,38 @@ struct ZSTD_CCtx_s {
}; };
MEM_STATIC U32 ZSTD_LLcode(U32 litLength) static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
{ 8, 9, 10, 11, 12, 13, 14, 15,
static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7, 16, 16, 17, 17, 18, 18, 19, 19,
8, 9, 10, 11, 12, 13, 14, 15, 20, 20, 20, 20, 21, 21, 21, 21,
16, 16, 17, 17, 18, 18, 19, 19, 22, 22, 22, 22, 22, 22, 22, 22,
20, 20, 20, 20, 21, 21, 21, 21, 23, 23, 23, 23, 23, 23, 23, 23,
22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, 24, 24, 24, 24,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24 };
24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24 };
static const U32 LL_deltaCode = 19;
return (litLength > 63) ? ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
}
/* ZSTD_MLcode() : static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
* note : mlBase = matchLength - MINMATCH; 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
* because it's the format it's stored in seqStore->sequences */ 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
MEM_STATIC U32 ZSTD_MLcode(U32 mlBase) 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
{ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
static const U32 ML_deltaCode = 36;
return (mlBase > 127) ? ZSTD_highbit32(mlBase) + ML_deltaCode : ML_Code[mlBase];
}
/*! ZSTD_storeSeq() : /*! ZSTD_storeSeq() :
* Store a sequence (literal length, literals, offset code and match length code) into seqStore_t. Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
* `offsetCode` : distance to match + 3 (values 1-3 are repCodes). `offsetCode` : distance to match, or 0 == repCode.
* `mlBase` : matchLength - MINMATCH `matchCode` : matchLength - MINMATCH
*/ */
MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t mlBase) MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
{ {
#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6) #if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
static const BYTE* g_start = NULL; static const BYTE* g_start = NULL;
if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */ U32 const pos = (U32)((const BYTE*)literals - g_start);
{ U32 const pos = (U32)((const BYTE*)literals - g_start); if (g_start==NULL) g_start = (const BYTE*)literals;
DEBUGLOG(6, "Cpos%7u :%3u literals, match%3u bytes at dist.code%7u", if ((pos > 0) && (pos < 1000000000))
pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offsetCode); DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u",
} pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
#endif #endif
/* copy Literals */ /* copy Literals */
assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB); assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB);
@@ -244,7 +139,6 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const v
/* literal Length */ /* literal Length */
if (litLength>0xFFFF) { if (litLength>0xFFFF) {
assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
seqStorePtr->longLengthID = 1; seqStorePtr->longLengthID = 1;
seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
} }
@@ -254,12 +148,11 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const v
seqStorePtr->sequences[0].offset = offsetCode + 1; seqStorePtr->sequences[0].offset = offsetCode + 1;
/* match Length */ /* match Length */
if (mlBase>0xFFFF) { if (matchCode>0xFFFF) {
assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */
seqStorePtr->longLengthID = 2; seqStorePtr->longLengthID = 2;
seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
} }
seqStorePtr->sequences[0].matchLength = (U16)mlBase; seqStorePtr->sequences[0].matchLength = (U16)matchCode;
seqStorePtr->sequences++; seqStorePtr->sequences++;
} }
@@ -268,7 +161,7 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const v
/*-************************************* /*-*************************************
* Match length counter * Match length counter
***************************************/ ***************************************/
static unsigned ZSTD_NbCommonBytes (size_t val) static unsigned ZSTD_NbCommonBytes (register size_t val)
{ {
if (MEM_isLittleEndian()) { if (MEM_isLittleEndian()) {
if (MEM_64bits()) { if (MEM_64bits()) {
@@ -342,17 +235,13 @@ MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* co
const BYTE* const pStart = pIn; const BYTE* const pStart = pIn;
const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1); const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
if (pIn < pInLoopLimit) { while (pIn < pInLoopLimit) {
{ size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn); size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
if (diff) return ZSTD_NbCommonBytes(diff); } if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
pIn+=sizeof(size_t); pMatch+=sizeof(size_t); pIn += ZSTD_NbCommonBytes(diff);
while (pIn < pInLoopLimit) { return (size_t)(pIn - pStart);
size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn); }
if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; } if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
pIn += ZSTD_NbCommonBytes(diff);
return (size_t)(pIn - pStart);
} }
if (MEM_64bits() && (pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; } if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++; if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
return (size_t)(pIn - pStart); return (size_t)(pIn - pStart);
@@ -415,48 +304,4 @@ MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
} }
#endif #endif
/* ==============================================================
* Private declarations
* These prototypes shall only be called from within lib/compress
* ============================================================== */
/*! ZSTD_initCStream_internal() :
* Private use only. Init streaming operation.
* expects params to be valid.
* must receive dict, or cdict, or none, but not both.
* @return : 0, or an error code */
size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
const void* dict, size_t dictSize,
const ZSTD_CDict* cdict,
ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
/*! ZSTD_compressStream_generic() :
* Private use only. To be called from zstdmt_compress.c in single-thread mode. */
size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
ZSTD_outBuffer* output,
ZSTD_inBuffer* input,
ZSTD_EndDirective const flushMode);
/*! ZSTD_getCParamsFromCDict() :
* as the name implies */
ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict);
/* ZSTD_compressBegin_advanced_internal() :
* Private use only. To be called from zstdmt_compress.c. */
size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
const void* dict, size_t dictSize,
ZSTD_dictMode_e dictMode,
const ZSTD_CDict* cdict,
ZSTD_CCtx_params params,
unsigned long long pledgedSrcSize);
/* ZSTD_compress_advanced_internal() :
* Private use only. To be called from zstdmt_compress.c. */
size_t ZSTD_compress_advanced_internal(ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
const void* dict,size_t dictSize,
ZSTD_CCtx_params params);
#endif /* ZSTD_COMPRESS_H */ #endif /* ZSTD_COMPRESS_H */
-1
View File
@@ -8,7 +8,6 @@
* You may select, at your option, one of the above-listed licenses. * You may select, at your option, one of the above-listed licenses.
*/ */
#include "zstd_compress_internal.h"
#include "zstd_double_fast.h" #include "zstd_double_fast.h"
+2 -3
View File
@@ -11,13 +11,12 @@
#ifndef ZSTD_DOUBLE_FAST_H #ifndef ZSTD_DOUBLE_FAST_H
#define ZSTD_DOUBLE_FAST_H #define ZSTD_DOUBLE_FAST_H
#include "zstd_compress.h"
#if defined (__cplusplus) #if defined (__cplusplus)
extern "C" { extern "C" {
#endif #endif
#include "mem.h" /* U32 */
#include "zstd.h" /* ZSTD_CCtx, size_t */
void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls); void ZSTD_fillDoubleHashTable(ZSTD_CCtx* cctx, const void* end, const U32 mls);
size_t ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize); size_t ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
size_t ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize); size_t ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
-1
View File
@@ -8,7 +8,6 @@
* You may select, at your option, one of the above-listed licenses. * You may select, at your option, one of the above-listed licenses.
*/ */
#include "zstd_compress_internal.h"
#include "zstd_fast.h" #include "zstd_fast.h"
+2 -3
View File
@@ -11,13 +11,12 @@
#ifndef ZSTD_FAST_H #ifndef ZSTD_FAST_H
#define ZSTD_FAST_H #define ZSTD_FAST_H
#include "zstd_compress.h"
#if defined (__cplusplus) #if defined (__cplusplus)
extern "C" { extern "C" {
#endif #endif
#include "mem.h" /* U32 */
#include "zstd.h" /* ZSTD_CCtx, size_t */
void ZSTD_fillHashTable(ZSTD_CCtx* zc, const void* end, const U32 mls); void ZSTD_fillHashTable(ZSTD_CCtx* zc, const void* end, const U32 mls);
size_t ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, size_t ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
const void* src, size_t srcSize); const void* src, size_t srcSize);
+50 -66
View File
@@ -8,7 +8,6 @@
* You may select, at your option, one of the above-listed licenses. * You may select, at your option, one of the above-listed licenses.
*/ */
#include "zstd_compress_internal.h"
#include "zstd_lazy.h" #include "zstd_lazy.h"
@@ -16,11 +15,10 @@
* Binary Tree search * Binary Tree search
***************************************/ ***************************************/
/** ZSTD_insertBt1() : add one or multiple positions to tree. /** ZSTD_insertBt1() : add one or multiple positions to tree.
* ip : assumed <= iend-8 . * ip : assumed <= iend-8 .
* @return : nb of positions added */ * @return : nb of positions added */
static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
const BYTE* const ip, const BYTE* const iend, U32 extDict)
U32 nbCompares, U32 const mls, U32 const extDict)
{ {
U32* const hashTable = zc->hashTable; U32* const hashTable = zc->hashTable;
U32 const hashLog = zc->appliedParams.cParams.hashLog; U32 const hashLog = zc->appliedParams.cParams.hashLog;
@@ -42,7 +40,7 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
U32* largerPtr = smallerPtr + 1; U32* largerPtr = smallerPtr + 1;
U32 dummy32; /* to be nullified at the end */ U32 dummy32; /* to be nullified at the end */
U32 const windowLow = zc->lowLimit; U32 const windowLow = zc->lowLimit;
U32 matchEndIdx = current+8+1; U32 matchEndIdx = current+8;
size_t bestLength = 8; size_t bestLength = 8;
#ifdef ZSTD_C_PREDICT #ifdef ZSTD_C_PREDICT
U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0); U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
@@ -51,15 +49,12 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
predictedLarge += (predictedLarge>0); predictedLarge += (predictedLarge>0);
#endif /* ZSTD_C_PREDICT */ #endif /* ZSTD_C_PREDICT */
DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
assert(ip <= iend-8); /* required for h calculation */ assert(ip <= iend-8); /* required for h calculation */
hashTable[h] = current; /* Update Hash Table */ hashTable[h] = current; /* Update Hash Table */
while (nbCompares-- && (matchIndex > windowLow)) { while (nbCompares-- && (matchIndex > windowLow)) {
U32* const nextPtr = bt + 2*(matchIndex & btMask); U32* const nextPtr = bt + 2*(matchIndex & btMask);
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
assert(matchIndex < current);
#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */ #ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */ const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
@@ -81,11 +76,10 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
continue; continue;
} }
#endif #endif
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) { if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
assert(matchIndex+matchLength >= dictLimit); /* might be wrong if extDict is incorrectly set to 0 */
match = base + matchIndex; match = base + matchIndex;
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend); if (match[matchLength] == ip[matchLength])
matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
} else { } else {
match = dictBase + matchIndex; match = dictBase + matchIndex;
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart); matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
@@ -99,17 +93,16 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
matchEndIdx = matchIndex + (U32)matchLength; matchEndIdx = matchIndex + (U32)matchLength;
} }
if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */ if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
}
if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */ if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
/* match is smaller than current */ /* match+1 is smaller than current */
*smallerPtr = matchIndex; /* update smaller idx */ *smallerPtr = matchIndex; /* update smaller idx */
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
} else { } else {
/* match is larger than current */ /* match is larger than current */
*largerPtr = matchIndex; *largerPtr = matchIndex;
@@ -121,38 +114,8 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
*smallerPtr = *largerPtr = 0; *smallerPtr = *largerPtr = 0;
if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */ if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
assert(matchEndIdx > current + 8); if (matchEndIdx > current + 8) return matchEndIdx - (current + 8);
return matchEndIdx - (current + 8); return 1;
}
FORCE_INLINE_TEMPLATE
void ZSTD_updateTree_internal(ZSTD_CCtx* zc,
const BYTE* const ip, const BYTE* const iend,
const U32 nbCompares, const U32 mls, const U32 extDict)
{
const BYTE* const base = zc->base;
U32 const target = (U32)(ip - base);
U32 idx = zc->nextToUpdate;
DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u (extDict:%u)",
idx, target, extDict);
while(idx < target)
idx += ZSTD_insertBt1(zc, base+idx, iend, nbCompares, mls, extDict);
zc->nextToUpdate = target;
}
void ZSTD_updateTree(ZSTD_CCtx* zc,
const BYTE* const ip, const BYTE* const iend,
const U32 nbCompares, const U32 mls)
{
ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 0 /*extDict*/);
}
void ZSTD_updateTree_extDict(ZSTD_CCtx* zc,
const BYTE* const ip, const BYTE* const iend,
const U32 nbCompares, const U32 mls)
{
ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 1 /*extDict*/);
} }
@@ -181,7 +144,7 @@ static size_t ZSTD_insertBtAndFindBestMatch (
const U32 windowLow = zc->lowLimit; const U32 windowLow = zc->lowLimit;
U32* smallerPtr = bt + 2*(current&btMask); U32* smallerPtr = bt + 2*(current&btMask);
U32* largerPtr = bt + 2*(current&btMask) + 1; U32* largerPtr = bt + 2*(current&btMask) + 1;
U32 matchEndIdx = current+8+1; U32 matchEndIdx = current+8;
U32 dummy32; /* to be nullified at the end */ U32 dummy32; /* to be nullified at the end */
size_t bestLength = 0; size_t bestLength = 0;
@@ -195,7 +158,8 @@ static size_t ZSTD_insertBtAndFindBestMatch (
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) { if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
match = base + matchIndex; match = base + matchIndex;
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend); if (match[matchLength] == ip[matchLength])
matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
} else { } else {
match = dictBase + matchIndex; match = dictBase + matchIndex;
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart); matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
@@ -208,9 +172,8 @@ static size_t ZSTD_insertBtAndFindBestMatch (
matchEndIdx = matchIndex + (U32)matchLength; matchEndIdx = matchIndex + (U32)matchLength;
if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */ if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
break; /* drop, to guarantee consistency (miss a little bit of compression) */ break; /* drop, to guarantee consistency (miss a little bit of compression) */
}
} }
if (match[matchLength] < ip[matchLength]) { if (match[matchLength] < ip[matchLength]) {
@@ -231,12 +194,21 @@ static size_t ZSTD_insertBtAndFindBestMatch (
*smallerPtr = *largerPtr = 0; *smallerPtr = *largerPtr = 0;
assert(matchEndIdx > current+8); zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
zc->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
return bestLength; return bestLength;
} }
void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
{
const BYTE* const base = zc->base;
const U32 target = (U32)(ip - base);
U32 idx = zc->nextToUpdate;
while(idx < target)
idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
}
/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */ /** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
static size_t ZSTD_BtFindBestMatch ( static size_t ZSTD_BtFindBestMatch (
ZSTD_CCtx* zc, ZSTD_CCtx* zc,
@@ -267,6 +239,16 @@ static size_t ZSTD_BtFindBestMatch_selectMLS (
} }
void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
{
const BYTE* const base = zc->base;
const U32 target = (U32)(ip - base);
U32 idx = zc->nextToUpdate;
while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
}
/** Tree updater, providing best match */ /** Tree updater, providing best match */
static size_t ZSTD_BtFindBestMatch_extDict ( static size_t ZSTD_BtFindBestMatch_extDict (
ZSTD_CCtx* zc, ZSTD_CCtx* zc,
@@ -353,14 +335,14 @@ size_t ZSTD_HcFindBestMatch_generic (
U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls); U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) { for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
const BYTE* match;
size_t currentMl=0; size_t currentMl=0;
if ((!extDict) || matchIndex >= dictLimit) { if ((!extDict) || matchIndex >= dictLimit) {
const BYTE* const match = base + matchIndex; match = base + matchIndex;
if (match[ml] == ip[ml]) /* potentially better */ if (match[ml] == ip[ml]) /* potentially better */
currentMl = ZSTD_count(ip, match, iLimit); currentMl = ZSTD_count(ip, match, iLimit);
} else { } else {
const BYTE* const match = dictBase + matchIndex; match = dictBase + matchIndex;
assert(match+4 <= dictEnd);
if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4; currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
} }
@@ -398,10 +380,10 @@ FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS ( FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
ZSTD_CCtx* const zc, ZSTD_CCtx* zc,
const BYTE* ip, const BYTE* const iLimit, const BYTE* ip, const BYTE* const iLimit,
size_t* const offsetPtr, size_t* offsetPtr,
U32 const maxNbAttempts, U32 const matchLengthSearch) const U32 maxNbAttempts, const U32 matchLengthSearch)
{ {
switch(matchLengthSearch) switch(matchLengthSearch)
{ {
@@ -520,8 +502,9 @@ size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
*/ */
/* catch up */ /* catch up */
if (offset) { if (offset) {
while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > base)) while ( (start > anchor)
&& (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */ && (start > base+offset-ZSTD_REP_MOVE)
&& (start[-1] == (start-offset+ZSTD_REP_MOVE)[-1]) ) /* only search for offset within prefix */
{ start--; matchLength++; } { start--; matchLength++; }
offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
} }
@@ -533,8 +516,9 @@ _storeSequence:
} }
/* check immediate repcode */ /* check immediate repcode */
while ( ((ip <= ilimit) & (offset_2>0)) while ( (ip <= ilimit)
&& (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { && ((offset_2>0)
& (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
/* store sequence */ /* store sequence */
matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */ offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
+2 -3
View File
@@ -11,13 +11,12 @@
#ifndef ZSTD_LAZY_H #ifndef ZSTD_LAZY_H
#define ZSTD_LAZY_H #define ZSTD_LAZY_H
#include "zstd_compress.h"
#if defined (__cplusplus) #if defined (__cplusplus)
extern "C" { extern "C" {
#endif #endif
#include "mem.h" /* U32 */
#include "zstd.h" /* ZSTD_CCtx, size_t */
U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls); U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls);
void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls); void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls); void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls);
+2 -3
View File
@@ -10,13 +10,12 @@
#ifndef ZSTD_LDM_H #ifndef ZSTD_LDM_H
#define ZSTD_LDM_H #define ZSTD_LDM_H
#include "zstd_compress.h"
#if defined (__cplusplus) #if defined (__cplusplus)
extern "C" { extern "C" {
#endif #endif
#include "zstd_compress_internal.h" /* ldmParams_t, U32 */
#include "zstd.h" /* ZSTD_CCtx, size_t */
/*-************************************* /*-*************************************
* Long distance matching * Long distance matching
***************************************/ ***************************************/
+684 -512
View File
@@ -8,35 +8,36 @@
* You may select, at your option, one of the above-listed licenses. * You may select, at your option, one of the above-listed licenses.
*/ */
#include "zstd_compress_internal.h"
#include "zstd_opt.h" #include "zstd_opt.h"
#include "zstd_lazy.h" /* ZSTD_updateTree, ZSTD_updateTree_extDict */ #include "zstd_lazy.h"
#define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats. Also used for matchSum (?) */ #define ZSTD_LITFREQ_ADD 2
#define ZSTD_FREQ_DIV 4 /* log factor when using previous stats to init next stats */ #define ZSTD_FREQ_DIV 4
#define ZSTD_MAX_PRICE (1<<30) #define ZSTD_MAX_PRICE (1<<30)
/*-************************************* /*-*************************************
* Price functions for optimal parser * Price functions for optimal parser
***************************************/ ***************************************/
static void ZSTD_setLog2Prices(optState_t* optPtr) static void ZSTD_setLog2Prices(optState_t* optPtr)
{ {
optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1);
optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1);
optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1); optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1);
optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1);
optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1);
optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1); optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1);
optPtr->factor = 1 + ((optPtr->litSum>>5) / optPtr->litLengthSum) + ((optPtr->litSum<<1) / (optPtr->litSum + optPtr->matchSum));
} }
static void ZSTD_rescaleFreqs(optState_t* const optPtr, static void ZSTD_rescaleFreqs(optState_t* optPtr, const BYTE* src, size_t srcSize)
const BYTE* const src, size_t const srcSize)
{ {
unsigned u;
optPtr->cachedLiterals = NULL;
optPtr->cachedPrice = optPtr->cachedLitLength = 0;
optPtr->staticPrices = 0; optPtr->staticPrices = 0;
if (optPtr->litLengthSum == 0) { /* first init */ if (optPtr->litLengthSum == 0) {
unsigned u;
if (srcSize <= 1024) optPtr->staticPrices = 1; if (srcSize <= 1024) optPtr->staticPrices = 1;
assert(optPtr->litFreq!=NULL); assert(optPtr->litFreq!=NULL);
@@ -44,41 +45,44 @@ static void ZSTD_rescaleFreqs(optState_t* const optPtr,
optPtr->litFreq[u] = 0; optPtr->litFreq[u] = 0;
for (u=0; u<srcSize; u++) for (u=0; u<srcSize; u++)
optPtr->litFreq[src[u]]++; optPtr->litFreq[src[u]]++;
optPtr->litSum = 0; optPtr->litSum = 0;
optPtr->litLengthSum = MaxLL+1;
optPtr->matchLengthSum = MaxML+1;
optPtr->offCodeSum = (MaxOff+1);
optPtr->matchSum = (ZSTD_LITFREQ_ADD<<Litbits);
for (u=0; u<=MaxLit; u++) { for (u=0; u<=MaxLit; u++) {
optPtr->litFreq[u] = 1 + (optPtr->litFreq[u] >> ZSTD_FREQ_DIV); optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>ZSTD_FREQ_DIV);
optPtr->litSum += optPtr->litFreq[u]; optPtr->litSum += optPtr->litFreq[u];
} }
for (u=0; u<=MaxLL; u++) for (u=0; u<=MaxLL; u++)
optPtr->litLengthFreq[u] = 1; optPtr->litLengthFreq[u] = 1;
optPtr->litLengthSum = MaxLL+1;
for (u=0; u<=MaxML; u++) for (u=0; u<=MaxML; u++)
optPtr->matchLengthFreq[u] = 1; optPtr->matchLengthFreq[u] = 1;
optPtr->matchLengthSum = MaxML+1;
for (u=0; u<=MaxOff; u++) for (u=0; u<=MaxOff; u++)
optPtr->offCodeFreq[u] = 1; optPtr->offCodeFreq[u] = 1;
optPtr->offCodeSum = (MaxOff+1);
} else { } else {
unsigned u; optPtr->matchLengthSum = 0;
optPtr->litLengthSum = 0;
optPtr->offCodeSum = 0;
optPtr->matchSum = 0;
optPtr->litSum = 0; optPtr->litSum = 0;
for (u=0; u<=MaxLit; u++) { for (u=0; u<=MaxLit; u++) {
optPtr->litFreq[u] = 1 + (optPtr->litFreq[u] >> (ZSTD_FREQ_DIV+1)); optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>(ZSTD_FREQ_DIV+1));
optPtr->litSum += optPtr->litFreq[u]; optPtr->litSum += optPtr->litFreq[u];
} }
optPtr->litLengthSum = 0;
for (u=0; u<=MaxLL; u++) { for (u=0; u<=MaxLL; u++) {
optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1)); optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1));
optPtr->litLengthSum += optPtr->litLengthFreq[u]; optPtr->litLengthSum += optPtr->litLengthFreq[u];
} }
optPtr->matchLengthSum = 0;
for (u=0; u<=MaxML; u++) { for (u=0; u<=MaxML; u++) {
optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV); optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV);
optPtr->matchLengthSum += optPtr->matchLengthFreq[u]; optPtr->matchLengthSum += optPtr->matchLengthFreq[u];
optPtr->matchSum += optPtr->matchLengthFreq[u] * (u + 3);
} }
optPtr->offCodeSum = 0; optPtr->matchSum *= ZSTD_LITFREQ_ADD;
for (u=0; u<=MaxOff; u++) { for (u=0; u<=MaxOff; u++) {
optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV); optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV);
optPtr->offCodeSum += optPtr->offCodeFreq[u]; optPtr->offCodeSum += optPtr->offCodeFreq[u];
@@ -89,146 +93,114 @@ static void ZSTD_rescaleFreqs(optState_t* const optPtr,
} }
/* ZSTD_rawLiteralsCost() : static U32 ZSTD_getLiteralPrice(optState_t* optPtr, U32 litLength, const BYTE* literals)
* cost of literals (only) in given segment (which length can be null)
* does not include cost of literalLength symbol */
static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
const optState_t* const optPtr)
{ {
if (optPtr->staticPrices) return (litLength*6); /* 6 bit per literal - no statistic used */ U32 price, u;
if (litLength == 0) return 0;
if (optPtr->staticPrices)
return ZSTD_highbit32((U32)litLength+1) + (litLength*6);
if (litLength == 0)
return optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[0]+1);
/* literals */ /* literals */
{ U32 u; if (optPtr->cachedLiterals == literals) {
U32 cost = litLength * optPtr->log2litSum; U32 const additional = litLength - optPtr->cachedLitLength;
const BYTE* literals2 = optPtr->cachedLiterals + optPtr->cachedLitLength;
price = optPtr->cachedPrice + additional * optPtr->log2litSum;
for (u=0; u < additional; u++)
price -= ZSTD_highbit32(optPtr->litFreq[literals2[u]]+1);
optPtr->cachedPrice = price;
optPtr->cachedLitLength = litLength;
} else {
price = litLength * optPtr->log2litSum;
for (u=0; u < litLength; u++) for (u=0; u < litLength; u++)
cost -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1); price -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1);
return cost;
}
}
/* ZSTD_litLengthPrice() : if (litLength >= 12) {
* cost of literalLength symbol */ optPtr->cachedLiterals = literals;
static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr) optPtr->cachedPrice = price;
{ optPtr->cachedLitLength = litLength;
if (optPtr->staticPrices) return ZSTD_highbit32((U32)litLength+1); }
}
/* literal Length */ /* literal Length */
{ U32 const llCode = ZSTD_LLcode(litLength); { const BYTE LL_deltaCode = 19;
U32 const price = LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1); const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
return price; price += LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
}
}
/* ZSTD_litLengthPrice() :
* cost of the literal part of a sequence,
* including literals themselves, and literalLength symbol */
static U32 ZSTD_fullLiteralsCost(const BYTE* const literals, U32 const litLength,
const optState_t* const optPtr)
{
return ZSTD_rawLiteralsCost(literals, litLength, optPtr)
+ ZSTD_litLengthPrice(litLength, optPtr);
}
/* ZSTD_litLengthContribution() :
* @return ( cost(litlength) - cost(0) )
* this value can then be added to rawLiteralsCost()
* to provide a cost which is directly comparable to a match ending at same position */
static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr)
{
if (optPtr->staticPrices) return ZSTD_highbit32(litLength+1);
/* literal Length */
{ U32 const llCode = ZSTD_LLcode(litLength);
int const contribution = LL_bits[llCode]
+ ZSTD_highbit32(optPtr->litLengthFreq[0]+1)
- ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
#if 1
return contribution;
#else
return MAX(0, contribution); /* sometimes better, sometimes not ... */
#endif
}
}
/* ZSTD_literalsContribution() :
* creates a fake cost for the literals part of a sequence
* which can be compared to the ending cost of a match
* should a new match start at this position */
static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLength,
const optState_t* const optPtr)
{
int const contribution = ZSTD_rawLiteralsCost(literals, litLength, optPtr)
+ ZSTD_litLengthContribution(litLength, optPtr);
return contribution;
}
/* ZSTD_getMatchPrice() :
* Provides the cost of the match part (offset + matchLength) of a sequence
* Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence.
* optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */
FORCE_INLINE_TEMPLATE U32 ZSTD_getMatchPrice(
U32 const offset, U32 const matchLength,
const optState_t* const optPtr,
int const optLevel)
{
U32 price;
U32 const offCode = ZSTD_highbit32(offset+1);
U32 const mlBase = matchLength - MINMATCH;
assert(matchLength >= MINMATCH);
if (optPtr->staticPrices) /* fixed scheme, do not use statistics */
return ZSTD_highbit32((U32)mlBase+1) + 16 + offCode;
price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1);
if ((optLevel<2) /*static*/ && offCode >= 20) price += (offCode-19)*2; /* handicap for long distance offsets, favor decompression speed */
/* match Length */
{ U32 const mlCode = ZSTD_MLcode(mlBase);
price += ML_bits[mlCode] + optPtr->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1);
} }
DEBUGLOG(8, "ZSTD_getMatchPrice(ml:%u) = %u", matchLength, price);
return price; return price;
} }
static void ZSTD_updateStats(optState_t* const optPtr,
U32 litLength, const BYTE* literals, FORCE_INLINE_TEMPLATE U32 ZSTD_getPrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength, const int ultra)
U32 offsetCode, U32 matchLength)
{ {
/* literals */ /* offset */
{ U32 u; U32 price;
for (u=0; u < litLength; u++) BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
optPtr->litSum += litLength*ZSTD_LITFREQ_ADD; if (optPtr->staticPrices)
return ZSTD_getLiteralPrice(optPtr, litLength, literals) + ZSTD_highbit32((U32)matchLength+1) + 16 + offCode;
price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1);
if (!ultra && offCode >= 20) price += (offCode-19)*2;
/* match Length */
{ const BYTE ML_deltaCode = 36;
const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
price += ML_bits[mlCode] + optPtr->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1);
} }
return price + ZSTD_getLiteralPrice(optPtr, litLength, literals) + optPtr->factor;
}
static void ZSTD_updatePrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength)
{
U32 u;
/* literals */
optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
for (u=0; u < litLength; u++)
optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
/* literal Length */ /* literal Length */
{ U32 const llCode = ZSTD_LLcode(litLength); { const BYTE LL_deltaCode = 19;
const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
optPtr->litLengthFreq[llCode]++; optPtr->litLengthFreq[llCode]++;
optPtr->litLengthSum++; optPtr->litLengthSum++;
} }
/* match offset code (0-2=>repCode; 3+=>offset+2) */ /* match offset */
{ U32 const offCode = ZSTD_highbit32(offsetCode+1); { BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
assert(offCode <= MaxOff);
optPtr->offCodeFreq[offCode]++;
optPtr->offCodeSum++; optPtr->offCodeSum++;
optPtr->offCodeFreq[offCode]++;
} }
/* match Length */ /* match Length */
{ U32 const mlBase = matchLength - MINMATCH; { const BYTE ML_deltaCode = 36;
U32 const mlCode = ZSTD_MLcode(mlBase); const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
optPtr->matchLengthFreq[mlCode]++; optPtr->matchLengthFreq[mlCode]++;
optPtr->matchLengthSum++; optPtr->matchLengthSum++;
} }
ZSTD_setLog2Prices(optPtr);
} }
/* ZSTD_readMINMATCH() : #define SET_PRICE(pos, mlen_, offset_, litlen_, price_) \
* function safe only for comparisons { \
* assumption : memPtr must be at least 4 bytes before end of buffer */ while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } \
MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length) opt[pos].mlen = mlen_; \
opt[pos].off = offset_; \
opt[pos].litlen = litlen_; \
opt[pos].price = price_; \
}
/* function safe only for comparisons */
static U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
{ {
switch (length) switch (length)
{ {
@@ -244,14 +216,15 @@ MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
/* Update hashTable3 up to ip (excluded) /* Update hashTable3 up to ip (excluded)
Assumption : always within prefix (i.e. not within extDict) */ Assumption : always within prefix (i.e. not within extDict) */
static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* const cctx, const BYTE* const ip) static
U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* zc, const BYTE* ip)
{ {
U32* const hashTable3 = cctx->hashTable3; U32* const hashTable3 = zc->hashTable3;
U32 const hashLog3 = cctx->hashLog3; U32 const hashLog3 = zc->hashLog3;
const BYTE* const base = cctx->base; const BYTE* const base = zc->base;
U32 idx = cctx->nextToUpdate3; U32 idx = zc->nextToUpdate3;
U32 const target = cctx->nextToUpdate3 = (U32)(ip - base); const U32 target = zc->nextToUpdate3 = (U32)(ip - base);
size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3); const size_t hash3 = ZSTD_hash3Ptr(ip, hashLog3);
while(idx < target) { while(idx < target) {
hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx; hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
@@ -265,147 +238,102 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* const cctx, const BYTE*
/*-************************************* /*-*************************************
* Binary Tree search * Binary Tree search
***************************************/ ***************************************/
FORCE_INLINE_TEMPLATE static U32 ZSTD_insertBtAndGetAllMatches (
U32 ZSTD_insertBtAndGetAllMatches ( ZSTD_CCtx* zc,
ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iLimit,
const BYTE* const ip, const BYTE* const iLimit, int const extDict, U32 nbCompares, const U32 mls,
U32 nbCompares, U32 const mls, U32 const sufficient_len, U32 extDict, ZSTD_match_t* matches, const U32 minMatchLen)
U32 rep[ZSTD_REP_NUM], U32 const ll0,
ZSTD_match_t* matches, const U32 lengthToBeat)
{ {
const BYTE* const base = zc->base; const BYTE* const base = zc->base;
U32 const current = (U32)(ip-base); const U32 current = (U32)(ip-base);
U32 const hashLog = zc->appliedParams.cParams.hashLog; const U32 hashLog = zc->appliedParams.cParams.hashLog;
U32 const minMatch = (mls==3) ? 3 : 4; const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
U32* const hashTable = zc->hashTable; U32* const hashTable = zc->hashTable;
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
U32 matchIndex = hashTable[h]; U32 matchIndex = hashTable[h];
U32* const bt = zc->chainTable; U32* const bt = zc->chainTable;
U32 const btLog = zc->appliedParams.cParams.chainLog - 1; const U32 btLog = zc->appliedParams.cParams.chainLog - 1;
U32 const btMask= (1U << btLog) - 1; const U32 btMask= (1U << btLog) - 1;
size_t commonLengthSmaller=0, commonLengthLarger=0; size_t commonLengthSmaller=0, commonLengthLarger=0;
const BYTE* const dictBase = zc->dictBase; const BYTE* const dictBase = zc->dictBase;
U32 const dictLimit = zc->dictLimit; const U32 dictLimit = zc->dictLimit;
const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit;
const BYTE* const prefixStart = base + dictLimit; const BYTE* const prefixStart = base + dictLimit;
U32 const btLow = btMask >= current ? 0 : current - btMask; const U32 btLow = btMask >= current ? 0 : current - btMask;
U32 const windowLow = zc->lowLimit; const U32 windowLow = zc->lowLimit;
U32* smallerPtr = bt + 2*(current&btMask); U32* smallerPtr = bt + 2*(current&btMask);
U32* largerPtr = bt + 2*(current&btMask) + 1; U32* largerPtr = bt + 2*(current&btMask) + 1;
U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */ U32 matchEndIdx = current+8;
U32 dummy32; /* to be nullified at the end */ U32 dummy32; /* to be nullified at the end */
U32 mnum = 0; U32 mnum = 0;
size_t bestLength = lengthToBeat-1; const U32 minMatch = (mls == 3) ? 3 : 4;
DEBUGLOG(7, "ZSTD_insertBtAndGetAllMatches"); size_t bestLength = minMatchLen-1;
/* check repCode */ if (minMatch == 3) { /* HC3 match finder */
{ U32 const lastR = ZSTD_REP_NUM + ll0;
U32 repCode;
for (repCode = ll0; repCode < lastR; repCode++) {
U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
U32 const repIndex = current - repOffset;
U32 repLen = 0;
assert(current >= dictLimit);
if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) { /* equivalent to `current > repIndex >= dictLimit` */
if (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch)) {
repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
}
} else { /* repIndex < dictLimit || repIndex >= current */
const BYTE* const repMatch = dictBase + repIndex;
assert(current >= windowLow);
if ( extDict /* this case only valid in extDict mode */
&& ( ((repOffset-1) /*intentional overflow*/ < current - windowLow) /* equivalent to `current > repIndex >= windowLow` */
& (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */)
&& (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch;
} }
/* save longer solution */
if (repLen > bestLength) {
DEBUGLOG(8, "found rep-match %u of length %u",
repCode - ll0, (U32)repLen);
bestLength = repLen;
matches[mnum].off = repCode - ll0;
matches[mnum].len = (U32)repLen;
mnum++;
if ( (repLen > sufficient_len)
| (ip+repLen == iLimit) ) { /* best possible */
return mnum;
} } } }
/* HC3 match finder */
if ((mls == 3) /*static*/ && (bestLength < mls)) {
U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip); U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip);
if ((matchIndex3 > windowLow) if (matchIndex3>windowLow && (current - matchIndex3 < (1<<18))) {
& (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) { const BYTE* match;
size_t mlen; size_t currentMl=0;
if ((!extDict) /*static*/ || (matchIndex3 >= dictLimit)) { if ((!extDict) || matchIndex3 >= dictLimit) {
const BYTE* const match = base + matchIndex3; match = base + matchIndex3;
mlen = ZSTD_count(ip, match, iLimit); if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit);
} else { } else {
const BYTE* const match = dictBase + matchIndex3; match = dictBase + matchIndex3;
mlen = ZSTD_count_2segments(ip, match, iLimit, dictEnd, prefixStart); if (ZSTD_readMINMATCH(match, MINMATCH) == ZSTD_readMINMATCH(ip, MINMATCH)) /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
} }
/* save best solution */ /* save best solution */
if (mlen >= mls /* == 3 > bestLength */) { if (currentMl > bestLength) {
DEBUGLOG(8, "found small match with hlog3, of length %u", bestLength = currentMl;
(U32)mlen); matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex3;
bestLength = mlen; matches[mnum].len = (U32)currentMl;
assert(current > matchIndex3); mnum++;
assert(mnum==0); /* no prior solution */ if (currentMl > ZSTD_OPT_NUM) goto update;
matches[0].off = (current - matchIndex3) + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) goto update; /* best possible, and avoid read overflow*/
matches[0].len = (U32)mlen; }
mnum = 1; }
if ( (mlen > sufficient_len) | }
(ip+mlen == iLimit) ) { /* best possible length */
zc->nextToUpdate = current+1; /* skip insertion */
return 1;
} } } }
hashTable[h] = current; /* Update Hash Table */ hashTable[h] = current; /* Update Hash Table */
while (nbCompares-- && (matchIndex > windowLow)) { while (nbCompares-- && (matchIndex > windowLow)) {
U32* const nextPtr = bt + 2*(matchIndex & btMask); U32* nextPtr = bt + 2*(matchIndex & btMask);
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
const BYTE* match; const BYTE* match;
assert(current > matchIndex);
if ((!extDict) || (matchIndex+matchLength >= dictLimit)) { if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */
match = base + matchIndex; match = base + matchIndex;
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit); if (match[matchLength] == ip[matchLength]) {
matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iLimit) +1;
}
} else { } else {
match = dictBase + matchIndex; match = dictBase + matchIndex;
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart); matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
if (matchIndex+matchLength >= dictLimit) if (matchIndex+matchLength >= dictLimit)
match = base + matchIndex; /* prepare for match[matchLength] */ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
} }
if (matchLength > bestLength) { if (matchLength > bestLength) {
DEBUGLOG(8, "found match of length %u at distance %u", if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength;
(U32)matchLength, current - matchIndex);
assert(matchEndIdx > matchIndex);
if (matchLength > matchEndIdx - matchIndex)
matchEndIdx = matchIndex + (U32)matchLength;
bestLength = matchLength; bestLength = matchLength;
matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE; matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex;
matches[mnum].len = (U32)matchLength; matches[mnum].len = (U32)matchLength;
mnum++; mnum++;
if (matchLength > ZSTD_OPT_NUM) break; if (matchLength > ZSTD_OPT_NUM) break;
if (ip+matchLength == iLimit) { /* equal : no way to know if inf or sup */ if (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */
break; /* drop, to preserve bt consistency (miss a little bit of compression) */ break; /* drop, to guarantee consistency (miss a little bit of compression) */
}
} }
if (match[matchLength] < ip[matchLength]) { if (match[matchLength] < ip[matchLength]) {
/* match smaller than current */ /* match is smaller than current */
*smallerPtr = matchIndex; /* update smaller idx */ *smallerPtr = matchIndex; /* update smaller idx */
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
smallerPtr = nextPtr+1; /* new candidate => larger than match, which was smaller than current */ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
matchIndex = nextPtr[1]; /* new matchIndex, larger than previous, closer to current */ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
} else { } else {
/* match is larger than current */
*largerPtr = matchIndex; *largerPtr = matchIndex;
commonLengthLarger = matchLength; commonLengthLarger = matchLength;
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
@@ -415,31 +343,65 @@ U32 ZSTD_insertBtAndGetAllMatches (
*smallerPtr = *largerPtr = 0; *smallerPtr = *largerPtr = 0;
assert(matchEndIdx > current+8); update:
zc->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */ zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
return mnum; return mnum;
} }
FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches ( /** Tree updater, providing best match */
ZSTD_CCtx* zc, /* Index table will be updated */ static U32 ZSTD_BtGetAllMatches (
const BYTE* ip, const BYTE* const iHighLimit, int const extDict, ZSTD_CCtx* zc,
U32 const maxNbAttempts, U32 const matchLengthSearch, U32 const sufficient_len, const BYTE* const ip, const BYTE* const iLimit,
U32 rep[ZSTD_REP_NUM], U32 const ll0, const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
ZSTD_match_t* matches, U32 const lengthToBeat)
{ {
DEBUGLOG(7, "ZSTD_BtGetAllMatches");
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
if (extDict) ZSTD_updateTree_extDict(zc, ip, iHighLimit, maxNbAttempts, matchLengthSearch); ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
else ZSTD_updateTree(zc, ip, iHighLimit, maxNbAttempts, matchLengthSearch); return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minMatchLen);
}
static U32 ZSTD_BtGetAllMatches_selectMLS (
ZSTD_CCtx* zc, /* Index table will be updated */
const BYTE* ip, const BYTE* const iHighLimit,
const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
{
switch(matchLengthSearch) switch(matchLengthSearch)
{ {
case 3 : return ZSTD_insertBtAndGetAllMatches(zc, ip, iHighLimit, extDict, maxNbAttempts, 3, sufficient_len, rep, ll0, matches, lengthToBeat); case 3 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
default : default :
case 4 : return ZSTD_insertBtAndGetAllMatches(zc, ip, iHighLimit, extDict, maxNbAttempts, 4, sufficient_len, rep, ll0, matches, lengthToBeat); case 4 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
case 5 : return ZSTD_insertBtAndGetAllMatches(zc, ip, iHighLimit, extDict, maxNbAttempts, 5, sufficient_len, rep, ll0, matches, lengthToBeat); case 5 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
case 7 : case 7 :
case 6 : return ZSTD_insertBtAndGetAllMatches(zc, ip, iHighLimit, extDict, maxNbAttempts, 6, sufficient_len, rep, ll0, matches, lengthToBeat); case 6 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
}
}
/** Tree updater, providing best match */
static U32 ZSTD_BtGetAllMatches_extDict (
ZSTD_CCtx* zc,
const BYTE* const ip, const BYTE* const iLimit,
const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
{
if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minMatchLen);
}
static U32 ZSTD_BtGetAllMatches_selectMLS_extDict (
ZSTD_CCtx* zc, /* Index table will be updated */
const BYTE* ip, const BYTE* const iHighLimit,
const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
{
switch(matchLengthSearch)
{
case 3 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
default :
case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
case 7 :
case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
} }
} }
@@ -447,92 +409,12 @@ FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
/*-******************************* /*-*******************************
* Optimal parser * Optimal parser
*********************************/ *********************************/
typedef struct repcodes_s {
U32 rep[3];
} repcodes_t;
repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0)
{
repcodes_t newReps;
if (offset >= ZSTD_REP_NUM) { /* full offset */
newReps.rep[2] = rep[1];
newReps.rep[1] = rep[0];
newReps.rep[0] = offset - ZSTD_REP_MOVE;
} else { /* repcode */
U32 const repCode = offset + ll0;
if (repCode > 0) { /* note : if repCode==0, no change */
U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
newReps.rep[2] = (repCode >= 2) ? rep[1] : rep[2];
newReps.rep[1] = rep[0];
newReps.rep[0] = currentOffset;
} else { /* repCode == 0 */
memcpy(&newReps, rep, sizeof(newReps));
}
}
return newReps;
}
typedef struct {
const BYTE* anchor;
U32 litlen;
U32 rawLitCost;
} cachedLiteralPrice_t;
static U32 ZSTD_rawLiteralsCost_cached(
cachedLiteralPrice_t* const cachedLitPrice,
const BYTE* const anchor, U32 const litlen,
const optState_t* const optStatePtr)
{
U32 startCost;
U32 remainingLength;
const BYTE* startPosition;
if (anchor == cachedLitPrice->anchor) {
startCost = cachedLitPrice->rawLitCost;
startPosition = anchor + cachedLitPrice->litlen;
assert(litlen >= cachedLitPrice->litlen);
remainingLength = litlen - cachedLitPrice->litlen;
} else {
startCost = 0;
startPosition = anchor;
remainingLength = litlen;
}
{ U32 const rawLitCost = startCost + ZSTD_rawLiteralsCost(startPosition, remainingLength, optStatePtr);
cachedLitPrice->anchor = anchor;
cachedLitPrice->litlen = litlen;
cachedLitPrice->rawLitCost = rawLitCost;
return rawLitCost;
}
}
static U32 ZSTD_fullLiteralsCost_cached(
cachedLiteralPrice_t* const cachedLitPrice,
const BYTE* const anchor, U32 const litlen,
const optState_t* const optStatePtr)
{
return ZSTD_rawLiteralsCost_cached(cachedLitPrice, anchor, litlen, optStatePtr)
+ ZSTD_litLengthPrice(litlen, optStatePtr);
}
static int ZSTD_literalsContribution_cached(
cachedLiteralPrice_t* const cachedLitPrice,
const BYTE* const anchor, U32 const litlen,
const optState_t* const optStatePtr)
{
int const contribution = ZSTD_rawLiteralsCost_cached(cachedLitPrice, anchor, litlen, optStatePtr)
+ ZSTD_litLengthContribution(litlen, optStatePtr);
return contribution;
}
FORCE_INLINE_TEMPLATE FORCE_INLINE_TEMPLATE
size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
const void* src, size_t srcSize, const void* src, size_t srcSize, const int ultra)
const int optLevel, const int extDict)
{ {
seqStore_t* const seqStorePtr = &(ctx->seqStore); seqStore_t* seqStorePtr = &(ctx->seqStore);
optState_t* const optStatePtr = &(ctx->optState); optState_t* optStatePtr = &(ctx->optState);
const BYTE* const istart = (const BYTE*)src; const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart; const BYTE* ip = istart;
const BYTE* anchor = istart; const BYTE* anchor = istart;
@@ -541,219 +423,237 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
const BYTE* const base = ctx->base; const BYTE* const base = ctx->base;
const BYTE* const prefixStart = base + ctx->dictLimit; const BYTE* const prefixStart = base + ctx->dictLimit;
U32 const maxSearches = 1U << ctx->appliedParams.cParams.searchLog; const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
U32 const sufficient_len = MIN(ctx->appliedParams.cParams.targetLength, ZSTD_OPT_NUM -1); const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
U32 const mls = ctx->appliedParams.cParams.searchLength; const U32 mls = ctx->appliedParams.cParams.searchLength;
U32 const minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4; const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
ZSTD_optimal_t* const opt = optStatePtr->priceTable; ZSTD_optimal_t* opt = optStatePtr->priceTable;
ZSTD_match_t* const matches = optStatePtr->matchTable; ZSTD_match_t* matches = optStatePtr->matchTable;
cachedLiteralPrice_t cachedLitPrice; const BYTE* inr;
U32 rep[ZSTD_REP_NUM]; U32 offset, rep[ZSTD_REP_NUM];
/* init */ /* init */
DEBUGLOG(5, "ZSTD_compressBlock_opt_generic");
ctx->nextToUpdate3 = ctx->nextToUpdate; ctx->nextToUpdate3 = ctx->nextToUpdate;
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize); ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
ip += (ip==prefixStart); ip += (ip==prefixStart);
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; } { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; }
memset(&cachedLitPrice, 0, sizeof(cachedLitPrice));
/* Match Loop */ /* Match Loop */
while (ip < ilimit) { while (ip < ilimit) {
U32 cur, last_pos = 0; U32 cur, match_num, last_pos, litlen, price;
U32 best_mlen, best_off; U32 u, mlen, best_mlen, best_off, litLength;
memset(opt, 0, sizeof(ZSTD_optimal_t));
last_pos = 0;
litlen = (U32)(ip - anchor);
/* find first match */ /* check repCode */
{ U32 const litlen = (U32)(ip - anchor); { U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
U32 const ll0 = !litlen; for (i=(ip == anchor); i<last_i; i++) {
U32 const nbMatches = ZSTD_BtGetAllMatches(ctx, ip, iend, extDict, maxSearches, mls, sufficient_len, rep, ll0, matches, minMatch); const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
if (!nbMatches) { ip++; continue; } if ( (repCur > 0) && (repCur < (S32)(ip-prefixStart))
&& (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repCur, minMatch))) {
mlen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repCur, iend) + minMatch;
if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
goto _storeSequence;
}
best_off = i - (ip == anchor);
do {
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
if (mlen > last_pos || price < opt[mlen].price)
SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
mlen--;
} while (mlen >= minMatch);
} } }
/* initialize opt[0] */ match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, ip, iend, maxSearches, mls, matches, minMatch);
{ U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
opt[0].mlen = 1;
opt[0].litlen = litlen;
/* large match -> immediate encoding */ if (!last_pos && !match_num) { ip++; continue; }
{ U32 const maxML = matches[nbMatches-1].len;
DEBUGLOG(7, "found %u matches of maxLength=%u and offset=%u at cPos=%u => start new serie",
nbMatches, maxML, matches[nbMatches-1].off, (U32)(ip-prefixStart));
if (maxML > sufficient_len) { if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
best_mlen = maxML; best_mlen = matches[match_num-1].len;
best_off = matches[nbMatches-1].off; best_off = matches[match_num-1].off;
DEBUGLOG(7, "large match (%u>%u), immediate encoding", cur = 0;
best_mlen, sufficient_len); last_pos = 1;
cur = 0; goto _storeSequence;
last_pos = 1;
goto _shortestPath;
} }
/* set prices for first matches starting position == 0 */
{ U32 const literalsPrice = ZSTD_fullLiteralsCost_cached(&cachedLitPrice, anchor, litlen, optStatePtr);
U32 pos;
U32 matchNb;
for (pos = 0; pos < minMatch; pos++) {
opt[pos].mlen = 1;
opt[pos].price = ZSTD_MAX_PRICE;
}
for (matchNb = 0; matchNb < nbMatches; matchNb++) {
U32 const offset = matches[matchNb].off;
U32 const end = matches[matchNb].len;
repcodes_t const repHistory = ZSTD_updateRep(rep, offset, ll0);
for ( ; pos <= end ; pos++ ) {
U32 const matchPrice = literalsPrice + ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel);
DEBUGLOG(7, "rPos:%u => set initial price : %u",
pos, matchPrice);
opt[pos].mlen = pos;
opt[pos].off = offset;
opt[pos].litlen = litlen;
opt[pos].price = matchPrice;
memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
} }
last_pos = pos-1;
}
} }
/* check further positions */ /* set prices using matches at position = 0 */
best_mlen = (last_pos) ? last_pos : minMatch;
for (u = 0; u < match_num; u++) {
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
best_mlen = matches[u].len;
while (mlen <= best_mlen) {
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
if (mlen > last_pos || price < opt[mlen].price)
SET_PRICE(mlen, mlen, matches[u].off, litlen, price); /* note : macro modifies last_pos */
mlen++;
} }
if (last_pos < minMatch) { ip++; continue; }
/* initialize opt[0] */
{ U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
opt[0].mlen = 1;
opt[0].litlen = litlen;
/* check further positions */
for (cur = 1; cur <= last_pos; cur++) { for (cur = 1; cur <= last_pos; cur++) {
const BYTE* const inr = ip + cur; inr = ip + cur;
assert(cur < ZSTD_OPT_NUM);
/* Fix current position with one literal if cheaper */ if (opt[cur-1].mlen == 1) {
{ U32 const litlen = (opt[cur-1].mlen == 1) ? opt[cur-1].litlen + 1 : 1; litlen = opt[cur-1].litlen + 1;
int price; /* note : contribution can be negative */
if (cur > litlen) { if (cur > litlen) {
price = opt[cur - litlen].price + ZSTD_literalsContribution(inr-litlen, litlen, optStatePtr); price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
} else { } else
price = ZSTD_literalsContribution_cached(&cachedLitPrice, anchor, litlen, optStatePtr); price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
} } else {
assert(price < 1000000000); /* overflow check */ litlen = 1;
if (price <= opt[cur].price) { price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
DEBUGLOG(7, "rPos:%u : better price (%u<%u) using literal", }
cur, price, opt[cur].price);
opt[cur].mlen = 1;
opt[cur].off = 0;
opt[cur].litlen = litlen;
opt[cur].price = price;
memcpy(opt[cur].rep, opt[cur-1].rep, sizeof(opt[cur].rep));
} }
/* last match must start at a minimum distance of 8 from oend */ if (cur > last_pos || price <= opt[cur].price)
if (inr > ilimit) continue; SET_PRICE(cur, 1, 0, litlen, price);
if (cur == last_pos) break; if (cur == last_pos) break;
if ( (optLevel==0) /*static*/ if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
&& (opt[cur+1].price <= opt[cur].price) ) continue;
continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
{ U32 const ll0 = (opt[cur].mlen != 1); mlen = opt[cur].mlen;
U32 const litlen = (opt[cur].mlen == 1) ? opt[cur].litlen : 0; if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
U32 const previousPrice = (cur > litlen) ? opt[cur-litlen].price : 0; opt[cur].rep[2] = opt[cur-mlen].rep[1];
U32 const basePrice = previousPrice + ZSTD_fullLiteralsCost(inr-litlen, litlen, optStatePtr); opt[cur].rep[1] = opt[cur-mlen].rep[0];
U32 const nbMatches = ZSTD_BtGetAllMatches(ctx, inr, iend, extDict, maxSearches, mls, sufficient_len, opt[cur].rep, ll0, matches, minMatch); opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
U32 matchNb; } else {
if (!nbMatches) continue; opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
/* If opt[cur].off == ZSTD_REP_MOVE_OPT, then mlen != 1.
* offset ZSTD_REP_MOVE_OPT is used for the special case
* litLength == 0, where offset 0 means something special.
* mlen == 1 means the previous byte was stored as a literal,
* so they are mutually exclusive.
*/
assert(!(opt[cur].off == ZSTD_REP_MOVE_OPT && mlen == 1));
opt[cur].rep[0] = (opt[cur].off == ZSTD_REP_MOVE_OPT) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
}
{ U32 const maxML = matches[nbMatches-1].len; best_mlen = minMatch;
DEBUGLOG(7, "rPos:%u, found %u matches, of maxLength=%u", { U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
cur, nbMatches, maxML); for (i=(opt[cur].mlen != 1); i<last_i; i++) { /* check rep */
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
if ( (repCur > 0) && (repCur < (S32)(inr-prefixStart))
&& (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(inr - repCur, minMatch))) {
mlen = (U32)ZSTD_count(inr+minMatch, inr+minMatch - repCur, iend) + minMatch;
if ( (maxML > sufficient_len) if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
| (cur + maxML >= ZSTD_OPT_NUM) ) { best_mlen = mlen; best_off = i; last_pos = cur + 1;
best_mlen = maxML; goto _storeSequence;
best_off = matches[nbMatches-1].off; }
last_pos = cur + 1;
goto _shortestPath;
}
}
/* set prices using matches found at position == cur */ best_off = i - (opt[cur].mlen != 1);
for (matchNb = 0; matchNb < nbMatches; matchNb++) { if (mlen > best_mlen) best_mlen = mlen;
U32 const offset = matches[matchNb].off;
repcodes_t const repHistory = ZSTD_updateRep(opt[cur].rep, offset, ll0);
U32 const lastML = matches[matchNb].len;
U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch;
U32 mlen;
DEBUGLOG(7, "testing match %u => offCode=%u, mlen=%u, llen=%u", do {
matchNb, matches[matchNb].off, lastML, litlen); if (opt[cur].mlen == 1) {
litlen = opt[cur].litlen;
if (cur > litlen) {
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
} else
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
} else {
litlen = 0;
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
}
for (mlen = lastML; mlen >= startML; mlen--) { if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
U32 const pos = cur + mlen; SET_PRICE(cur + mlen, mlen, i, litlen, price);
int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel); mlen--;
} while (mlen >= minMatch);
if ((pos > last_pos) || (price < opt[pos].price)) {
DEBUGLOG(7, "rPos:%u => new better price (%u<%u)",
pos, price, opt[pos].price);
while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; }
opt[pos].mlen = mlen;
opt[pos].off = offset;
opt[pos].litlen = litlen;
opt[pos].price = price;
memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
} else {
if (optLevel==0) break; /* gets ~+10% speed for about -0.01 ratio loss */
}
} } } } } }
} /* for (cur = 1; cur <= last_pos; cur++) */
match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, inr, iend, maxSearches, mls, matches, best_mlen);
if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
best_mlen = matches[match_num-1].len;
best_off = matches[match_num-1].off;
last_pos = cur + 1;
goto _storeSequence;
}
/* set prices using matches at position = cur */
for (u = 0; u < match_num; u++) {
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
best_mlen = matches[u].len;
while (mlen <= best_mlen) {
if (opt[cur].mlen == 1) {
litlen = opt[cur].litlen;
if (cur > litlen)
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
else
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
} else {
litlen = 0;
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
}
if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
mlen++;
} } }
best_mlen = opt[last_pos].mlen; best_mlen = opt[last_pos].mlen;
best_off = opt[last_pos].off; best_off = opt[last_pos].off;
cur = last_pos - best_mlen; cur = last_pos - best_mlen;
_shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */ /* store sequence */
assert(opt[0].mlen == 1); _storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
opt[0].mlen = 1;
/* reverse traversal */ while (1) {
DEBUGLOG(7, "start reverse traversal (last_pos:%u, cur:%u)", mlen = opt[cur].mlen;
last_pos, cur); offset = opt[cur].off;
{ U32 selectedMatchLength = best_mlen; opt[cur].mlen = best_mlen;
U32 selectedOffset = best_off; opt[cur].off = best_off;
U32 pos = cur; best_mlen = mlen;
while (1) { best_off = offset;
U32 const mlen = opt[pos].mlen; if (mlen > cur) break;
U32 const off = opt[pos].off; cur -= mlen;
opt[pos].mlen = selectedMatchLength; }
opt[pos].off = selectedOffset;
selectedMatchLength = mlen;
selectedOffset = off;
if (mlen > pos) break;
pos -= mlen;
} }
/* save sequences */ for (u = 0; u <= last_pos;) {
{ U32 pos; u += opt[u].mlen;
for (pos=0; pos < last_pos; ) { }
U32 const llen = (U32)(ip - anchor);
U32 const mlen = opt[pos].mlen;
U32 const offset = opt[pos].off;
if (mlen == 1) { ip++; pos++; continue; } /* literal position => move on */
pos += mlen; ip += mlen;
/* repcodes update : like ZSTD_updateRep(), but update in place */ for (cur=0; cur < last_pos; ) {
if (offset >= ZSTD_REP_NUM) { /* full offset */ mlen = opt[cur].mlen;
rep[2] = rep[1]; if (mlen == 1) { ip++; cur++; continue; }
offset = opt[cur].off;
cur += mlen;
litLength = (U32)(ip - anchor);
if (offset > ZSTD_REP_MOVE_OPT) {
rep[2] = rep[1];
rep[1] = rep[0];
rep[0] = offset - ZSTD_REP_MOVE_OPT;
offset--;
} else {
if (offset != 0) {
best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
if (offset != 1) rep[2] = rep[1];
rep[1] = rep[0]; rep[1] = rep[0];
rep[0] = offset - ZSTD_REP_MOVE; rep[0] = best_off;
} else { /* repcode */
U32 const repCode = offset + (llen==0);
if (repCode) { /* note : if repCode==0, no change */
U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
if (repCode >= 2) rep[2] = rep[1];
rep[1] = rep[0];
rep[0] = currentOffset;
}
} }
if (litLength==0) offset--;
}
ZSTD_updateStats(optStatePtr, llen, anchor, offset, mlen); ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
ZSTD_storeSeq(seqStorePtr, llen, anchor, offset, mlen-MINMATCH); ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
anchor = ip; anchor = ip = ip + mlen;
} } } } /* for (cur=0; cur < last_pos; ) */
ZSTD_setLog2Prices(optStatePtr);
} /* while (ip < ilimit) */
/* Save reps for next block */ /* Save reps for next block */
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; } { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; }
@@ -765,21 +665,293 @@ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize) size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
{ {
DEBUGLOG(5, "ZSTD_compressBlock_btopt"); return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0 /*optLevel*/, 0 /*extDict*/);
} }
size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize) size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
{ {
return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 2 /*optLevel*/, 0 /*extDict*/); return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
} }
FORCE_INLINE_TEMPLATE
size_t ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
const void* src, size_t srcSize, const int ultra)
{
seqStore_t* seqStorePtr = &(ctx->seqStore);
optState_t* optStatePtr = &(ctx->optState);
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - 8;
const BYTE* const base = ctx->base;
const U32 lowestIndex = ctx->lowLimit;
const U32 dictLimit = ctx->dictLimit;
const BYTE* const prefixStart = base + dictLimit;
const BYTE* const dictBase = ctx->dictBase;
const BYTE* const dictEnd = dictBase + dictLimit;
const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
const U32 mls = ctx->appliedParams.cParams.searchLength;
const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
ZSTD_optimal_t* opt = optStatePtr->priceTable;
ZSTD_match_t* matches = optStatePtr->matchTable;
const BYTE* inr;
/* init */
U32 offset, rep[ZSTD_REP_NUM];
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; }
ctx->nextToUpdate3 = ctx->nextToUpdate;
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
ip += (ip==prefixStart);
/* Match Loop */
while (ip < ilimit) {
U32 cur, match_num, last_pos, litlen, price;
U32 u, mlen, best_mlen, best_off, litLength;
U32 current = (U32)(ip-base);
memset(opt, 0, sizeof(ZSTD_optimal_t));
last_pos = 0;
opt[0].litlen = (U32)(ip - anchor);
/* check repCode */
{ U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
for (i = (ip==anchor); i<last_i; i++) {
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
const U32 repIndex = (U32)(current - repCur);
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
const BYTE* const repMatch = repBase + repIndex;
if ( (repCur > 0 && repCur <= (S32)current)
&& (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */
&& (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
/* repcode detected we should take it */
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
mlen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
goto _storeSequence;
}
best_off = i - (ip==anchor);
litlen = opt[0].litlen;
do {
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
if (mlen > last_pos || price < opt[mlen].price)
SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
mlen--;
} while (mlen >= minMatch);
} } }
match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch); /* first search (depth 0) */
if (!last_pos && !match_num) { ip++; continue; }
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
opt[0].mlen = 1;
if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
best_mlen = matches[match_num-1].len;
best_off = matches[match_num-1].off;
cur = 0;
last_pos = 1;
goto _storeSequence;
}
best_mlen = (last_pos) ? last_pos : minMatch;
/* set prices using matches at position = 0 */
for (u = 0; u < match_num; u++) {
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
best_mlen = matches[u].len;
litlen = opt[0].litlen;
while (mlen <= best_mlen) {
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
if (mlen > last_pos || price < opt[mlen].price)
SET_PRICE(mlen, mlen, matches[u].off, litlen, price);
mlen++;
} }
if (last_pos < minMatch) {
ip++; continue;
}
/* check further positions */
for (cur = 1; cur <= last_pos; cur++) {
inr = ip + cur;
if (opt[cur-1].mlen == 1) {
litlen = opt[cur-1].litlen + 1;
if (cur > litlen) {
price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
} else
price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
} else {
litlen = 1;
price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
}
if (cur > last_pos || price <= opt[cur].price)
SET_PRICE(cur, 1, 0, litlen, price);
if (cur == last_pos) break;
if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
continue;
mlen = opt[cur].mlen;
if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
opt[cur].rep[2] = opt[cur-mlen].rep[1];
opt[cur].rep[1] = opt[cur-mlen].rep[0];
opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
} else {
opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
assert(!(opt[cur].off == ZSTD_REP_MOVE_OPT && mlen == 1));
opt[cur].rep[0] = (opt[cur].off == ZSTD_REP_MOVE_OPT) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
}
best_mlen = minMatch;
{ U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
for (i = (mlen != 1); i<last_i; i++) {
const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
const U32 repIndex = (U32)(current+cur - repCur);
const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
const BYTE* const repMatch = repBase + repIndex;
if ( (repCur > 0 && repCur <= (S32)(current+cur))
&& (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */
&& (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
/* repcode detected */
const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
mlen = (U32)ZSTD_count_2segments(inr+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
best_mlen = mlen; best_off = i; last_pos = cur + 1;
goto _storeSequence;
}
best_off = i - (opt[cur].mlen != 1);
if (mlen > best_mlen) best_mlen = mlen;
do {
if (opt[cur].mlen == 1) {
litlen = opt[cur].litlen;
if (cur > litlen) {
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
} else
price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
} else {
litlen = 0;
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
}
if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
SET_PRICE(cur + mlen, mlen, i, litlen, price);
mlen--;
} while (mlen >= minMatch);
} } }
match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, inr, iend, maxSearches, mls, matches, minMatch);
if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
best_mlen = matches[match_num-1].len;
best_off = matches[match_num-1].off;
last_pos = cur + 1;
goto _storeSequence;
}
/* set prices using matches at position = cur */
for (u = 0; u < match_num; u++) {
mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
best_mlen = matches[u].len;
while (mlen <= best_mlen) {
if (opt[cur].mlen == 1) {
litlen = opt[cur].litlen;
if (cur > litlen)
price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
else
price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
} else {
litlen = 0;
price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
}
if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
mlen++;
} } } /* for (cur = 1; cur <= last_pos; cur++) */
best_mlen = opt[last_pos].mlen;
best_off = opt[last_pos].off;
cur = last_pos - best_mlen;
/* store sequence */
_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
opt[0].mlen = 1;
while (1) {
mlen = opt[cur].mlen;
offset = opt[cur].off;
opt[cur].mlen = best_mlen;
opt[cur].off = best_off;
best_mlen = mlen;
best_off = offset;
if (mlen > cur) break;
cur -= mlen;
}
for (u = 0; u <= last_pos; ) {
u += opt[u].mlen;
}
for (cur=0; cur < last_pos; ) {
mlen = opt[cur].mlen;
if (mlen == 1) { ip++; cur++; continue; }
offset = opt[cur].off;
cur += mlen;
litLength = (U32)(ip - anchor);
if (offset > ZSTD_REP_MOVE_OPT) {
rep[2] = rep[1];
rep[1] = rep[0];
rep[0] = offset - ZSTD_REP_MOVE_OPT;
offset--;
} else {
if (offset != 0) {
best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
if (offset != 1) rep[2] = rep[1];
rep[1] = rep[0];
rep[0] = best_off;
}
if (litLength==0) offset--;
}
ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
anchor = ip = ip + mlen;
} } /* for (cur=0; cur < last_pos; ) */
/* Save reps for next block */
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; }
/* Return the last literals size */
return iend - anchor;
}
size_t ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) size_t ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
{ {
return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0 /*optLevel*/, 1 /*extDict*/); return ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
} }
size_t ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) size_t ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
{ {
return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 2 /*optLevel*/, 1 /*extDict*/); return ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
} }
+2 -2
View File
@@ -11,12 +11,12 @@
#ifndef ZSTD_OPT_H #ifndef ZSTD_OPT_H
#define ZSTD_OPT_H #define ZSTD_OPT_H
#include "zstd_compress.h"
#if defined (__cplusplus) #if defined (__cplusplus)
extern "C" { extern "C" {
#endif #endif
#include "zstd.h" /* ZSTD_CCtx, size_t */
size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize); size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize); size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize);
+80 -130
View File
@@ -24,7 +24,7 @@
#include <string.h> /* memcpy, memset */ #include <string.h> /* memcpy, memset */
#include "pool.h" /* threadpool */ #include "pool.h" /* threadpool */
#include "threading.h" /* mutex */ #include "threading.h" /* mutex */
#include "zstd_compress_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */ #include "zstd_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */
#include "zstdmt_compress.h" #include "zstdmt_compress.h"
@@ -140,12 +140,9 @@ static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool)
return poolSize + totalBufferSize; return poolSize + totalBufferSize;
} }
static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const bSize) static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* bufPool, size_t bSize)
{ {
ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
DEBUGLOG(4, "ZSTDMT_setBufferSize: bSize = %u", (U32)bSize);
bufPool->bufferSize = bSize; bufPool->bufferSize = bSize;
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
} }
/** ZSTDMT_getBuffer() : /** ZSTDMT_getBuffer() :
@@ -153,31 +150,28 @@ static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const
static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool) static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool)
{ {
size_t const bSize = bufPool->bufferSize; size_t const bSize = bufPool->bufferSize;
DEBUGLOG(5, "ZSTDMT_getBuffer: bSize = %u", (U32)bufPool->bufferSize); DEBUGLOG(5, "ZSTDMT_getBuffer");
ZSTD_pthread_mutex_lock(&bufPool->poolMutex); ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
if (bufPool->nbBuffers) { /* try to use an existing buffer */ if (bufPool->nbBuffers) { /* try to use an existing buffer */
buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)]; buffer_t const buf = bufPool->bTable[--(bufPool->nbBuffers)];
size_t const availBufferSize = buf.size; size_t const availBufferSize = buf.size;
bufPool->bTable[bufPool->nbBuffers] = g_nullBuffer; bufPool->bTable[bufPool->nbBuffers] = g_nullBuffer;
if ((availBufferSize >= bSize) & ((availBufferSize>>3) <= bSize)) { if ((availBufferSize >= bSize) & (availBufferSize <= 10*bSize)) {
/* large enough, but not too much */ /* large enough, but not too much */
DEBUGLOG(5, "ZSTDMT_getBuffer: provide buffer %u of size %u",
bufPool->nbBuffers, (U32)buf.size);
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
return buf; return buf;
} }
/* size conditions not respected : scratch this buffer, create new one */ /* size conditions not respected : scratch this buffer, create new one */
DEBUGLOG(5, "ZSTDMT_getBuffer: existing buffer does not meet size conditions => freeing"); DEBUGLOG(5, "existing buffer does not meet size conditions => freeing");
ZSTD_free(buf.start, bufPool->cMem); ZSTD_free(buf.start, bufPool->cMem);
} }
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
/* create new buffer */ /* create new buffer */
DEBUGLOG(5, "ZSTDMT_getBuffer: create a new buffer"); DEBUGLOG(5, "create a new buffer");
{ buffer_t buffer; { buffer_t buffer;
void* const start = ZSTD_malloc(bSize, bufPool->cMem); void* const start = ZSTD_malloc(bSize, bufPool->cMem);
buffer.start = start; /* note : start can be NULL if malloc fails ! */ buffer.start = start; /* note : start can be NULL if malloc fails ! */
buffer.size = (start==NULL) ? 0 : bSize; buffer.size = (start==NULL) ? 0 : bSize;
DEBUGLOG(5, "ZSTDMT_getBuffer: created buffer of size %u", (U32)bSize);
return buffer; return buffer;
} }
} }
@@ -190,14 +184,12 @@ static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf)
ZSTD_pthread_mutex_lock(&bufPool->poolMutex); ZSTD_pthread_mutex_lock(&bufPool->poolMutex);
if (bufPool->nbBuffers < bufPool->totalBuffers) { if (bufPool->nbBuffers < bufPool->totalBuffers) {
bufPool->bTable[bufPool->nbBuffers++] = buf; /* stored for later use */ bufPool->bTable[bufPool->nbBuffers++] = buf; /* stored for later use */
DEBUGLOG(5, "ZSTDMT_releaseBuffer: stored buffer of size %u in slot %u",
(U32)buf.size, (U32)(bufPool->nbBuffers-1));
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
return; return;
} }
ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); ZSTD_pthread_mutex_unlock(&bufPool->poolMutex);
/* Reached bufferPool capacity (should not happen) */ /* Reached bufferPool capacity (should not happen) */
DEBUGLOG(5, "ZSTDMT_releaseBuffer: pool capacity reached => freeing "); DEBUGLOG(5, "buffer pool capacity reached => freeing ");
ZSTD_free(buf.start, bufPool->cMem); ZSTD_free(buf.start, bufPool->cMem);
} }
@@ -310,7 +302,7 @@ static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx)
typedef struct { typedef struct {
buffer_t src; buffer_t src;
const void* srcStart; const void* srcStart;
size_t prefixSize; size_t dictSize;
size_t srcSize; size_t srcSize;
buffer_t dstBuff; buffer_t dstBuff;
size_t cSize; size_t cSize;
@@ -332,11 +324,11 @@ typedef struct {
void ZSTDMT_compressChunk(void* jobDescription) void ZSTDMT_compressChunk(void* jobDescription)
{ {
ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription; ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription;
ZSTD_CCtx* const cctx = ZSTDMT_getCCtx(job->cctxPool); ZSTD_CCtx* cctx = ZSTDMT_getCCtx(job->cctxPool);
const void* const src = (const char*)job->srcStart + job->prefixSize; const void* const src = (const char*)job->srcStart + job->dictSize;
buffer_t dstBuff = job->dstBuff; buffer_t dstBuff = job->dstBuff;
DEBUGLOG(5, "ZSTDMT_compressChunk: job (first:%u) (last:%u) : prefixSize %u, srcSize %u ", DEBUGLOG(5, "job (first:%u) (last:%u) : dictSize %u, srcSize %u",
job->firstChunk, job->lastChunk, (U32)job->prefixSize, (U32)job->srcSize); job->firstChunk, job->lastChunk, (U32)job->dictSize, (U32)job->srcSize);
if (cctx==NULL) { if (cctx==NULL) {
job->cSize = ERROR(memory_allocation); job->cSize = ERROR(memory_allocation);
@@ -350,48 +342,38 @@ void ZSTDMT_compressChunk(void* jobDescription)
goto _endJob; goto _endJob;
} }
job->dstBuff = dstBuff; job->dstBuff = dstBuff;
DEBUGLOG(5, "ZSTDMT_compressChunk: received dstBuff of size %u", (U32)dstBuff.size);
} }
if (job->cdict) { if (job->cdict) { /* should only happen for first segment */
size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, NULL, 0, ZSTD_dm_auto, job->cdict, job->params, job->fullFrameSize); size_t const initError = ZSTD_compressBegin_usingCDict_advanced(cctx, job->cdict, job->params.fParams, job->fullFrameSize);
DEBUGLOG(4, "ZSTDMT_compressChunk: init using CDict (windowLog=%u)", job->params.cParams.windowLog); DEBUGLOG(5, "using CDict");
assert(job->firstChunk); /* only allowed for first job */
if (ZSTD_isError(initError)) { job->cSize = initError; goto _endJob; } if (ZSTD_isError(initError)) { job->cSize = initError; goto _endJob; }
} else { /* srcStart points at reloaded section */ } else { /* srcStart points at reloaded section */
U64 const pledgedSrcSize = job->firstChunk ? job->fullFrameSize : ZSTD_CONTENTSIZE_UNKNOWN; if (!job->firstChunk) job->params.fParams.contentSizeFlag = 0; /* ensure no srcSize control */
ZSTD_CCtx_params jobParams = job->params; /* do not modify job->params ! copy it, modify the copy */ { ZSTD_CCtx_params jobParams = job->params;
size_t const forceWindowError = ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk); size_t const forceWindowError =
if (ZSTD_isError(forceWindowError)) { ZSTD_CCtxParam_setParameter(&jobParams, ZSTD_p_forceMaxWindow, !job->firstChunk);
DEBUGLOG(5, "ZSTD_CCtxParam_setParameter error : %s ", ZSTD_getErrorName(forceWindowError)); /* Force loading dictionary in "content-only" mode (no header analysis) */
job->cSize = forceWindowError; size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, job->srcStart, job->dictSize, ZSTD_dm_rawContent, jobParams, job->fullFrameSize);
goto _endJob; if (ZSTD_isError(initError) || ZSTD_isError(forceWindowError)) {
}
DEBUGLOG(5, "ZSTDMT_compressChunk: invoking ZSTD_compressBegin_advanced_internal with windowLog = %u ", jobParams.cParams.windowLog);
{ size_t const initError = ZSTD_compressBegin_advanced_internal(cctx,
job->srcStart, job->prefixSize, ZSTD_dm_rawContent, /* load dictionary in "content-only" mode (no header analysis) */
NULL,
jobParams, pledgedSrcSize);
if (ZSTD_isError(initError)) {
DEBUGLOG(5, "ZSTD_compressBegin_advanced_internal error : %s ", ZSTD_getErrorName(initError));
job->cSize = initError; job->cSize = initError;
goto _endJob; goto _endJob;
} } }
} } }
if (!job->firstChunk) { /* flush and overwrite frame header when it's not first job */ if (!job->firstChunk) { /* flush and overwrite frame header when it's not first segment */
size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, 0); size_t const hSize = ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, 0);
if (ZSTD_isError(hSize)) { job->cSize = hSize; /* save error code */ goto _endJob; } if (ZSTD_isError(hSize)) { job->cSize = hSize; goto _endJob; }
ZSTD_invalidateRepCodes(cctx); ZSTD_invalidateRepCodes(cctx);
} }
DEBUGLOG(5, "Compressing into dstBuff of size %u", (U32)dstBuff.size); DEBUGLOG(5, "Compressing : ");
DEBUG_PRINTHEX(6, job->srcStart, 12); DEBUG_PRINTHEX(4, job->srcStart, 12);
job->cSize = (job->lastChunk) ? job->cSize = (job->lastChunk) ?
ZSTD_compressEnd (cctx, dstBuff.start, dstBuff.size, src, job->srcSize) : ZSTD_compressEnd (cctx, dstBuff.start, dstBuff.size, src, job->srcSize) :
ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, job->srcSize); ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, job->srcSize);
DEBUGLOG(5, "compressed %u bytes into %u bytes (first:%u) (last:%u) ", DEBUGLOG(5, "compressed %u bytes into %u bytes (first:%u) (last:%u)",
(unsigned)job->srcSize, (unsigned)job->cSize, job->firstChunk, job->lastChunk); (unsigned)job->srcSize, (unsigned)job->cSize, job->firstChunk, job->lastChunk);
DEBUGLOG(5, "dstBuff.size : %u ; => %s ", (U32)dstBuff.size, ZSTD_getErrorName(job->cSize)); DEBUGLOG(5, "dstBuff.size : %u ; => %s", (U32)dstBuff.size, ZSTD_getErrorName(job->cSize));
_endJob: _endJob:
ZSTDMT_releaseCCtx(job->cctxPool, cctx); ZSTDMT_releaseCCtx(job->cctxPool, cctx);
@@ -421,14 +403,13 @@ struct ZSTDMT_CCtx_s {
ZSTDMT_CCtxPool* cctxPool; ZSTDMT_CCtxPool* cctxPool;
ZSTD_pthread_mutex_t jobCompleted_mutex; ZSTD_pthread_mutex_t jobCompleted_mutex;
ZSTD_pthread_cond_t jobCompleted_cond; ZSTD_pthread_cond_t jobCompleted_cond;
ZSTD_CCtx_params params;
size_t targetSectionSize; size_t targetSectionSize;
size_t inBuffSize; size_t inBuffSize;
size_t dictSize; size_t dictSize;
size_t targetDictSize; size_t targetDictSize;
inBuff_t inBuff; inBuff_t inBuff;
ZSTD_CCtx_params params;
XXH64_state_t xxhState; XXH64_state_t xxhState;
unsigned singleThreaded;
unsigned jobIDMask; unsigned jobIDMask;
unsigned doneJobID; unsigned doneJobID;
unsigned nextJobID; unsigned nextJobID;
@@ -449,32 +430,20 @@ static ZSTDMT_jobDescription* ZSTDMT_allocJobsTable(U32* nbJobsPtr, ZSTD_customM
nbJobs * sizeof(ZSTDMT_jobDescription), cMem); nbJobs * sizeof(ZSTDMT_jobDescription), cMem);
} }
/* ZSTDMT_CCtxParam_setNbThreads(): /* Internal only */
* Internal use only */ size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads)
size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThreads)
{ {
if (nbThreads > ZSTDMT_NBTHREADS_MAX) nbThreads = ZSTDMT_NBTHREADS_MAX;
if (nbThreads < 1) nbThreads = 1;
params->nbThreads = nbThreads; params->nbThreads = nbThreads;
params->overlapSizeLog = ZSTDMT_OVERLAPLOG_DEFAULT; params->overlapSizeLog = ZSTDMT_OVERLAPLOG_DEFAULT;
params->jobSize = 0; params->jobSize = 0;
return nbThreads; return 0;
}
/* ZSTDMT_getNbThreads():
* @return nb threads currently active in mtctx.
* mtctx must be valid */
size_t ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx)
{
assert(mtctx != NULL);
return mtctx->params.nbThreads;
} }
ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem) ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
{ {
ZSTDMT_CCtx* mtctx; ZSTDMT_CCtx* mtctx;
U32 nbJobs = nbThreads + 2; U32 nbJobs = nbThreads + 2;
DEBUGLOG(3, "ZSTDMT_createCCtx_advanced (nbThreads = %u)", nbThreads); DEBUGLOG(3, "ZSTDMT_createCCtx_advanced");
if (nbThreads < 1) return NULL; if (nbThreads < 1) return NULL;
nbThreads = MIN(nbThreads , ZSTDMT_NBTHREADS_MAX); nbThreads = MIN(nbThreads , ZSTDMT_NBTHREADS_MAX);
@@ -484,7 +453,7 @@ ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem); mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem);
if (!mtctx) return NULL; if (!mtctx) return NULL;
ZSTDMT_CCtxParam_setNbThreads(&mtctx->params, nbThreads); ZSTDMT_initializeCCtxParameters(&mtctx->params, nbThreads);
mtctx->cMem = cMem; mtctx->cMem = cMem;
mtctx->allJobsCompleted = 1; mtctx->allJobsCompleted = 1;
mtctx->factory = POOL_create_advanced(nbThreads, 0, cMem); mtctx->factory = POOL_create_advanced(nbThreads, 0, cMem);
@@ -576,23 +545,17 @@ size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx)
} }
/* Internal only */ /* Internal only */
size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, size_t ZSTDMT_CCtxParam_setMTCtxParameter(
ZSTDMT_parameter parameter, unsigned value) { ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value) {
DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter");
switch(parameter) switch(parameter)
{ {
case ZSTDMT_p_jobSize : case ZSTDMT_p_sectionSize :
DEBUGLOG(4, "ZSTDMT_CCtxParam_setMTCtxParameter : set jobSize to %u", value);
if ( (value > 0) /* value==0 => automatic job size */
& (value < ZSTDMT_JOBSIZE_MIN) )
value = ZSTDMT_JOBSIZE_MIN;
params->jobSize = value; params->jobSize = value;
return value; return 0;
case ZSTDMT_p_overlapSectionLog : case ZSTDMT_p_overlapSectionLog :
if (value > 9) value = 9;
DEBUGLOG(4, "ZSTDMT_p_overlapSectionLog : %u", value); DEBUGLOG(4, "ZSTDMT_p_overlapSectionLog : %u", value);
params->overlapSizeLog = (value >= 9) ? 9 : value; params->overlapSizeLog = (value >= 9) ? 9 : value;
return value; return 0;
default : default :
return ERROR(parameter_unsupported); return ERROR(parameter_unsupported);
} }
@@ -600,10 +563,9 @@ size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params,
size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned value) size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned value)
{ {
DEBUGLOG(4, "ZSTDMT_setMTCtxParameter");
switch(parameter) switch(parameter)
{ {
case ZSTDMT_p_jobSize : case ZSTDMT_p_sectionSize :
return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value); return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value);
case ZSTDMT_p_overlapSectionLog : case ZSTDMT_p_overlapSectionLog :
return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value); return ZSTDMT_CCtxParam_setMTCtxParameter(&mtctx->params, parameter, value);
@@ -639,7 +601,7 @@ static size_t ZSTDMT_compress_advanced_internal(
size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (params.cParams.windowLog - overlapRLog); size_t const overlapSize = (overlapRLog>=9) ? 0 : (size_t)1 << (params.cParams.windowLog - overlapRLog);
unsigned nbChunks = computeNbChunks(srcSize, params.cParams.windowLog, params.nbThreads); unsigned nbChunks = computeNbChunks(srcSize, params.cParams.windowLog, params.nbThreads);
size_t const proposedChunkSize = (srcSize + (nbChunks-1)) / nbChunks; size_t const proposedChunkSize = (srcSize + (nbChunks-1)) / nbChunks;
size_t const avgChunkSize = (((proposedChunkSize-1) & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */ size_t const avgChunkSize = ((proposedChunkSize & 0x1FFFF) < 0x7FFF) ? proposedChunkSize + 0xFFFF : proposedChunkSize; /* avoid too small last block */
const char* const srcStart = (const char*)src; const char* const srcStart = (const char*)src;
size_t remainingSrcSize = srcSize; size_t remainingSrcSize = srcSize;
unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbChunks : (unsigned)(dstCapacity / ZSTD_compressBound(avgChunkSize)); /* presumes avgChunkSize >= 256 KB, which should be the case */ unsigned const compressWithinDst = (dstCapacity >= ZSTD_compressBound(srcSize)) ? nbChunks : (unsigned)(dstCapacity / ZSTD_compressBound(avgChunkSize)); /* presumes avgChunkSize >= 256 KB, which should be the case */
@@ -648,8 +610,7 @@ static size_t ZSTDMT_compress_advanced_internal(
assert(jobParams.nbThreads == 0); assert(jobParams.nbThreads == 0);
assert(mtctx->cctxPool->totalCCtx == params.nbThreads); assert(mtctx->cctxPool->totalCCtx == params.nbThreads);
DEBUGLOG(4, "ZSTDMT_compress_advanced_internal: nbChunks=%2u (rawSize=%u bytes; fixedSize=%u) ", DEBUGLOG(4, "nbChunks : %2u (chunkSize : %u bytes) ", nbChunks, (U32)avgChunkSize);
nbChunks, (U32)proposedChunkSize, (U32)avgChunkSize);
if (nbChunks==1) { /* fallback to single-thread mode */ if (nbChunks==1) { /* fallback to single-thread mode */
ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0]; ZSTD_CCtx* const cctx = mtctx->cctxPool->cctx[0];
if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, jobParams.fParams); if (cdict) return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, jobParams.fParams);
@@ -678,9 +639,9 @@ static size_t ZSTDMT_compress_advanced_internal(
mtctx->jobs[u].src = g_nullBuffer; mtctx->jobs[u].src = g_nullBuffer;
mtctx->jobs[u].srcStart = srcStart + frameStartPos - dictSize; mtctx->jobs[u].srcStart = srcStart + frameStartPos - dictSize;
mtctx->jobs[u].prefixSize = dictSize; mtctx->jobs[u].dictSize = dictSize;
mtctx->jobs[u].srcSize = chunkSize; mtctx->jobs[u].srcSize = chunkSize;
mtctx->jobs[u].cdict = (u==0) ? cdict : NULL; mtctx->jobs[u].cdict = mtctx->nextJobID==0 ? cdict : NULL;
mtctx->jobs[u].fullFrameSize = srcSize; mtctx->jobs[u].fullFrameSize = srcSize;
mtctx->jobs[u].params = jobParams; mtctx->jobs[u].params = jobParams;
/* do not calculate checksum within sections, but write it in header for first section */ /* do not calculate checksum within sections, but write it in header for first section */
@@ -698,7 +659,7 @@ static size_t ZSTDMT_compress_advanced_internal(
XXH64_update(&xxh64, srcStart + frameStartPos, chunkSize); XXH64_update(&xxh64, srcStart + frameStartPos, chunkSize);
} }
DEBUGLOG(5, "ZSTDMT_compress_advanced_internal: posting job %u (%u bytes)", u, (U32)chunkSize); DEBUGLOG(5, "posting job %u (%u bytes)", u, (U32)chunkSize);
DEBUG_PRINTHEX(6, mtctx->jobs[u].srcStart, 12); DEBUG_PRINTHEX(6, mtctx->jobs[u].srcStart, 12);
POOL_add(mtctx->factory, ZSTDMT_compressChunk, &mtctx->jobs[u]); POOL_add(mtctx->factory, ZSTDMT_compressChunk, &mtctx->jobs[u]);
@@ -792,14 +753,13 @@ size_t ZSTDMT_initCStream_internal(
const ZSTD_CDict* cdict, ZSTD_CCtx_params params, const ZSTD_CDict* cdict, ZSTD_CCtx_params params,
unsigned long long pledgedSrcSize) unsigned long long pledgedSrcSize)
{ {
DEBUGLOG(4, "ZSTDMT_initCStream_internal (pledgedSrcSize=%u)", (U32)pledgedSrcSize); DEBUGLOG(4, "ZSTDMT_initCStream_internal");
/* params are supposed to be fully validated at this point */ /* params are supposed to be fully validated at this point */
assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
assert(!((dict) && (cdict))); /* either dict or cdict, not both */ assert(!((dict) && (cdict))); /* either dict or cdict, not both */
assert(zcs->cctxPool->totalCCtx == params.nbThreads); assert(zcs->cctxPool->totalCCtx == params.nbThreads);
zcs->singleThreaded = (params.nbThreads==1) | (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN); /* do not trigger multi-threading when srcSize is too small */
if (zcs->singleThreaded) { if (params.nbThreads==1) {
ZSTD_CCtx_params const singleThreadParams = ZSTDMT_makeJobCCtxParams(params); ZSTD_CCtx_params const singleThreadParams = ZSTDMT_makeJobCCtxParams(params);
DEBUGLOG(4, "single thread mode"); DEBUGLOG(4, "single thread mode");
assert(singleThreadParams.nbThreads == 0); assert(singleThreadParams.nbThreads == 0);
@@ -807,7 +767,6 @@ size_t ZSTDMT_initCStream_internal(
dict, dictSize, cdict, dict, dictSize, cdict,
singleThreadParams, pledgedSrcSize); singleThreadParams, pledgedSrcSize);
} }
DEBUGLOG(4, "multi-threading mode (%u threads)", params.nbThreads);
if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */ if (zcs->allJobsCompleted == 0) { /* previous compression not correctly finished */
ZSTDMT_waitForAllJobsCompleted(zcs); ZSTDMT_waitForAllJobsCompleted(zcs);
@@ -818,6 +777,7 @@ size_t ZSTDMT_initCStream_internal(
zcs->params = params; zcs->params = params;
zcs->frameContentSize = pledgedSrcSize; zcs->frameContentSize = pledgedSrcSize;
if (dict) { if (dict) {
DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal);
ZSTD_freeCDict(zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal);
zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
ZSTD_dlm_byCopy, dictMode, /* note : a loadPrefix becomes an internal CDict */ ZSTD_dlm_byCopy, dictMode, /* note : a loadPrefix becomes an internal CDict */
@@ -825,20 +785,20 @@ size_t ZSTDMT_initCStream_internal(
zcs->cdict = zcs->cdictLocal; zcs->cdict = zcs->cdictLocal;
if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
} else { } else {
DEBUGLOG(4,"cdictLocal: %08X", (U32)(size_t)zcs->cdictLocal);
ZSTD_freeCDict(zcs->cdictLocal); ZSTD_freeCDict(zcs->cdictLocal);
zcs->cdictLocal = NULL; zcs->cdictLocal = NULL;
zcs->cdict = cdict; zcs->cdict = cdict;
} }
assert(params.overlapSizeLog <= 9);
zcs->targetDictSize = (params.overlapSizeLog==0) ? 0 : (size_t)1 << (params.cParams.windowLog - (9 - params.overlapSizeLog)); zcs->targetDictSize = (params.overlapSizeLog==0) ? 0 : (size_t)1 << (params.cParams.windowLog - (9 - params.overlapSizeLog));
DEBUGLOG(4, "overlapLog=%u => %u KB", params.overlapSizeLog, (U32)(zcs->targetDictSize>>10)); DEBUGLOG(4, "overlapLog : %u ", params.overlapSizeLog);
DEBUGLOG(4, "overlap Size : %u KB", (U32)(zcs->targetDictSize>>10));
zcs->targetSectionSize = params.jobSize ? params.jobSize : (size_t)1 << (params.cParams.windowLog + 2); zcs->targetSectionSize = params.jobSize ? params.jobSize : (size_t)1 << (params.cParams.windowLog + 2);
if (zcs->targetSectionSize < ZSTDMT_JOBSIZE_MIN) zcs->targetSectionSize = ZSTDMT_JOBSIZE_MIN; zcs->targetSectionSize = MAX(ZSTDMT_SECTION_SIZE_MIN, zcs->targetSectionSize);
if (zcs->targetSectionSize < zcs->targetDictSize) zcs->targetSectionSize = zcs->targetDictSize; /* job size must be >= overlap size */ zcs->targetSectionSize = MAX(zcs->targetDictSize, zcs->targetSectionSize);
DEBUGLOG(4, "Job Size : %u KB (note : set to %u)", (U32)(zcs->targetSectionSize>>10), params.jobSize); DEBUGLOG(4, "Section Size : %u KB", (U32)(zcs->targetSectionSize>>10));
zcs->inBuffSize = zcs->targetDictSize + zcs->targetSectionSize; zcs->inBuffSize = zcs->targetDictSize + zcs->targetSectionSize;
DEBUGLOG(4, "inBuff Size : %u KB", (U32)(zcs->inBuffSize>>10));
ZSTDMT_setBufferSize(zcs->bufPool, MAX(zcs->inBuffSize, ZSTD_compressBound(zcs->targetSectionSize)) ); ZSTDMT_setBufferSize(zcs->bufPool, MAX(zcs->inBuffSize, ZSTD_compressBound(zcs->targetSectionSize)) );
zcs->inBuff.buffer = g_nullBuffer; zcs->inBuff.buffer = g_nullBuffer;
zcs->dictSize = 0; zcs->dictSize = 0;
@@ -856,7 +816,7 @@ size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
unsigned long long pledgedSrcSize) unsigned long long pledgedSrcSize)
{ {
ZSTD_CCtx_params cctxParams = mtctx->params; ZSTD_CCtx_params cctxParams = mtctx->params;
DEBUGLOG(5, "ZSTDMT_initCStream_advanced (pledgedSrcSize=%u)", (U32)pledgedSrcSize); DEBUGLOG(5, "ZSTDMT_initCStream_advanced");
cctxParams.cParams = params.cParams; cctxParams.cParams = params.cParams;
cctxParams.fParams = params.fParams; cctxParams.fParams = params.fParams;
return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dm_auto, NULL, return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dm_auto, NULL,
@@ -878,12 +838,9 @@ size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
/* ZSTDMT_resetCStream() : /* ZSTDMT_resetCStream() :
* pledgedSrcSize can be zero == unknown (for the time being) * pledgedSrcSize is optional and can be zero == unknown */
* prefer using ZSTD_CONTENTSIZE_UNKNOWN,
* as `0` might mean "empty" in the future */
size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize) size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* zcs, unsigned long long pledgedSrcSize)
{ {
if (!pledgedSrcSize) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
if (zcs->params.nbThreads==1) if (zcs->params.nbThreads==1)
return ZSTD_resetCStream(zcs->cctxPool->cctx[0], pledgedSrcSize); return ZSTD_resetCStream(zcs->cctxPool->cctx[0], pledgedSrcSize);
return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, 0, zcs->params, return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, 0, zcs->params,
@@ -895,7 +852,7 @@ size_t ZSTDMT_initCStream(ZSTDMT_CCtx* zcs, int compressionLevel) {
ZSTD_CCtx_params cctxParams = zcs->params; ZSTD_CCtx_params cctxParams = zcs->params;
cctxParams.cParams = params.cParams; cctxParams.cParams = params.cParams;
cctxParams.fParams = params.fParams; cctxParams.fParams = params.fParams;
return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN); return ZSTDMT_initCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, NULL, cctxParams, 0);
} }
@@ -903,12 +860,12 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
{ {
unsigned const jobID = zcs->nextJobID & zcs->jobIDMask; unsigned const jobID = zcs->nextJobID & zcs->jobIDMask;
DEBUGLOG(5, "ZSTDMT_createCompressionJob: preparing job %u to compress %u bytes with %u preload ", DEBUGLOG(4, "preparing job %u to compress %u bytes with %u preload ",
zcs->nextJobID, (U32)srcSize, (U32)zcs->dictSize); zcs->nextJobID, (U32)srcSize, (U32)zcs->dictSize);
zcs->jobs[jobID].src = zcs->inBuff.buffer; zcs->jobs[jobID].src = zcs->inBuff.buffer;
zcs->jobs[jobID].srcStart = zcs->inBuff.buffer.start; zcs->jobs[jobID].srcStart = zcs->inBuff.buffer.start;
zcs->jobs[jobID].srcSize = srcSize; zcs->jobs[jobID].srcSize = srcSize;
zcs->jobs[jobID].prefixSize = zcs->dictSize; zcs->jobs[jobID].dictSize = zcs->dictSize;
assert(zcs->inBuff.filled >= srcSize + zcs->dictSize); assert(zcs->inBuff.filled >= srcSize + zcs->dictSize);
zcs->jobs[jobID].params = zcs->params; zcs->jobs[jobID].params = zcs->params;
/* do not calculate checksum within sections, but write it in header for first section */ /* do not calculate checksum within sections, but write it in header for first section */
@@ -954,7 +911,7 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
zcs->params.fParams.checksumFlag = 0; zcs->params.fParams.checksumFlag = 0;
} } } }
DEBUGLOG(5, "ZSTDMT_createCompressionJob: posting job %u : %u bytes (end:%u) (note : doneJob = %u=>%u)", DEBUGLOG(4, "posting job %u : %u bytes (end:%u) (note : doneJob = %u=>%u)",
zcs->nextJobID, zcs->nextJobID,
(U32)zcs->jobs[jobID].srcSize, (U32)zcs->jobs[jobID].srcSize,
zcs->jobs[jobID].lastChunk, zcs->jobs[jobID].lastChunk,
@@ -973,7 +930,6 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsigned blockToFlush) static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsigned blockToFlush)
{ {
unsigned const wJobID = zcs->doneJobID & zcs->jobIDMask; unsigned const wJobID = zcs->doneJobID & zcs->jobIDMask;
DEBUGLOG(5, "ZSTDMT_flushNextJob");
if (zcs->doneJobID == zcs->nextJobID) return 0; /* all flushed ! */ if (zcs->doneJobID == zcs->nextJobID) return 0; /* all flushed ! */
ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex); ZSTD_PTHREAD_MUTEX_LOCK(&zcs->jobCompleted_mutex);
while (zcs->jobs[wJobID].jobCompleted==0) { while (zcs->jobs[wJobID].jobCompleted==0) {
@@ -986,8 +942,7 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi
{ ZSTDMT_jobDescription job = zcs->jobs[wJobID]; { ZSTDMT_jobDescription job = zcs->jobs[wJobID];
if (!job.jobScanned) { if (!job.jobScanned) {
if (ZSTD_isError(job.cSize)) { if (ZSTD_isError(job.cSize)) {
DEBUGLOG(5, "job %u : compression error detected : %s", DEBUGLOG(5, "compression error detected ");
zcs->doneJobID, ZSTD_getErrorName(job.cSize));
ZSTDMT_waitForAllJobsCompleted(zcs); ZSTDMT_waitForAllJobsCompleted(zcs);
ZSTDMT_releaseAllJobResources(zcs); ZSTDMT_releaseAllJobResources(zcs);
return job.cSize; return job.cSize;
@@ -1036,18 +991,15 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
{ {
size_t const newJobThreshold = mtctx->dictSize + mtctx->targetSectionSize; size_t const newJobThreshold = mtctx->dictSize + mtctx->targetSectionSize;
unsigned forwardInputProgress = 0; unsigned forwardInputProgress = 0;
DEBUGLOG(5, "ZSTDMT_compressStream_generic ");
assert(output->pos <= output->size); assert(output->pos <= output->size);
assert(input->pos <= input->size); assert(input->pos <= input->size);
if (mtctx->singleThreaded) { /* delegate to single-thread (synchronous) */
return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
}
if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) { if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) {
/* current frame being ended. Only flush/end are allowed */ /* current frame being ended. Only flush/end are allowed */
return ERROR(stage_wrong); return ERROR(stage_wrong);
} }
if (mtctx->params.nbThreads==1) { /* delegate to single-thread (synchronous) */
return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
}
/* single-pass shortcut (note : synchronous-mode) */ /* single-pass shortcut (note : synchronous-mode) */
if ( (mtctx->nextJobID == 0) /* just started */ if ( (mtctx->nextJobID == 0) /* just started */
@@ -1116,34 +1068,32 @@ size_t ZSTDMT_compressStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, ZSTD_inBu
} }
static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, unsigned endFrame) static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsigned endFrame)
{ {
size_t const srcSize = mtctx->inBuff.filled - mtctx->dictSize; size_t const srcSize = zcs->inBuff.filled - zcs->dictSize;
DEBUGLOG(5, "ZSTDMT_flushStream_internal");
if ( ((srcSize > 0) || (endFrame && !mtctx->frameEnded)) if ( ((srcSize > 0) || (endFrame && !zcs->frameEnded))
&& (mtctx->nextJobID <= mtctx->doneJobID + mtctx->jobIDMask) ) { && (zcs->nextJobID <= zcs->doneJobID + zcs->jobIDMask) ) {
DEBUGLOG(5, "ZSTDMT_flushStream_internal : create a new job"); CHECK_F( ZSTDMT_createCompressionJob(zcs, srcSize, endFrame) );
CHECK_F( ZSTDMT_createCompressionJob(mtctx, srcSize, endFrame) );
} }
/* check if there is any data available to flush */ /* check if there is any data available to flush */
return ZSTDMT_flushNextJob(mtctx, output, 1 /* blockToFlush */); return ZSTDMT_flushNextJob(zcs, output, 1 /* blockToFlush */);
} }
size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output) size_t ZSTDMT_flushStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output)
{ {
DEBUGLOG(5, "ZSTDMT_flushStream"); DEBUGLOG(5, "ZSTDMT_flushStream");
if (mtctx->singleThreaded) if (zcs->params.nbThreads==1)
return ZSTD_flushStream(mtctx->cctxPool->cctx[0], output); return ZSTD_flushStream(zcs->cctxPool->cctx[0], output);
return ZSTDMT_flushStream_internal(mtctx, output, 0 /* endFrame */); return ZSTDMT_flushStream_internal(zcs, output, 0 /* endFrame */);
} }
size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output) size_t ZSTDMT_endStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output)
{ {
DEBUGLOG(4, "ZSTDMT_endStream"); DEBUGLOG(4, "ZSTDMT_endStream");
if (mtctx->singleThreaded) if (zcs->params.nbThreads==1)
return ZSTD_endStream(mtctx->cctxPool->cctx[0], output); return ZSTD_endStream(zcs->cctxPool->cctx[0], output);
return ZSTDMT_flushStream_internal(mtctx, output, 1 /* endFrame */); return ZSTDMT_flushStream_internal(zcs, output, 1 /* endFrame */);
} }
+7 -15
View File
@@ -50,7 +50,7 @@ ZSTDLIB_API size_t ZSTDMT_compressCCtx(ZSTDMT_CCtx* mtctx,
/* === Streaming functions === */ /* === Streaming functions === */
ZSTDLIB_API size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel); ZSTDLIB_API size_t ZSTDMT_initCStream(ZSTDMT_CCtx* mtctx, int compressionLevel);
ZSTDLIB_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize); /**< if srcSize is not known at reset time, use ZSTD_CONTENTSIZE_UNKNOWN. Note: for compatibility with older programs, 0 means the same as ZSTD_CONTENTSIZE_UNKNOWN, but it may change in the future, to mean "empty" */ ZSTDLIB_API size_t ZSTDMT_resetCStream(ZSTDMT_CCtx* mtctx, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be zero == unknown */
ZSTDLIB_API size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input); ZSTDLIB_API size_t ZSTDMT_compressStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
@@ -60,8 +60,8 @@ ZSTDLIB_API size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output);
/* === Advanced functions and parameters === */ /* === Advanced functions and parameters === */
#ifndef ZSTDMT_JOBSIZE_MIN #ifndef ZSTDMT_SECTION_SIZE_MIN
# define ZSTDMT_JOBSIZE_MIN (1U << 20) /* 1 MB - Minimum size of each compression job */ # define ZSTDMT_SECTION_SIZE_MIN (1U << 20) /* 1 MB - Minimum size of each compression job */
#endif #endif
ZSTDLIB_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx, ZSTDLIB_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
@@ -84,13 +84,13 @@ ZSTDLIB_API size_t ZSTDMT_initCStream_usingCDict(ZSTDMT_CCtx* mtctx,
/* ZSTDMT_parameter : /* ZSTDMT_parameter :
* List of parameters that can be set using ZSTDMT_setMTCtxParameter() */ * List of parameters that can be set using ZSTDMT_setMTCtxParameter() */
typedef enum { typedef enum {
ZSTDMT_p_jobSize, /* Each job is compressed in parallel. By default, this value is dynamically determined depending on compression parameters. Can be set explicitly here. */ ZSTDMT_p_sectionSize, /* size of input "section". Each section is compressed in parallel. 0 means default, which is dynamically determined within compression functions */
ZSTDMT_p_overlapSectionLog /* Each job may reload a part of previous job to enhance compressionr ratio; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window */ ZSTDMT_p_overlapSectionLog /* Log of overlapped section; 0 == no overlap, 6(default) == use 1/8th of window, >=9 == use full window */
} ZSTDMT_parameter; } ZSTDMT_parameter;
/* ZSTDMT_setMTCtxParameter() : /* ZSTDMT_setMTCtxParameter() :
* allow setting individual parameters, one at a time, among a list of enums defined in ZSTDMT_parameter. * allow setting individual parameters, one at a time, among a list of enums defined in ZSTDMT_parameter.
* The function must be called typically after ZSTD_createCCtx() but __before ZSTDMT_init*() !__ * The function must be called typically after ZSTD_createCCtx().
* Parameters not explicitly reset by ZSTDMT_init*() remain the same in consecutive compression sessions. * Parameters not explicitly reset by ZSTDMT_init*() remain the same in consecutive compression sessions.
* @return : 0, or an error code (which can be tested using ZSTD_isError()) */ * @return : 0, or an error code (which can be tested using ZSTD_isError()) */
ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned value); ZSTDLIB_API size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter, unsigned value);
@@ -112,15 +112,7 @@ ZSTDLIB_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value); size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value);
/* ZSTDMT_CCtxParam_setNbThreads() size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads);
* Set nbThreads, and clamp it correctly,
* also reset jobSize and overlapLog */
size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThreads);
/* ZSTDMT_getNbThreads():
* @return nb threads currently active in mtctx.
* mtctx must be valid */
size_t ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx);
/*! ZSTDMT_initCStream_internal() : /*! ZSTDMT_initCStream_internal() :
* Private use only. Init streaming operation. * Private use only. Init streaming operation.
+31 -41
View File
@@ -827,9 +827,9 @@ typedef struct {
FSE_DState_t stateOffb; FSE_DState_t stateOffb;
FSE_DState_t stateML; FSE_DState_t stateML;
size_t prevOffset[ZSTD_REP_NUM]; size_t prevOffset[ZSTD_REP_NUM];
const BYTE* prefixStart; const BYTE* base;
const BYTE* dictEnd;
size_t pos; size_t pos;
uPtrDiff gotoDict;
} seqState_t; } seqState_t;
@@ -1224,9 +1224,8 @@ seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, ZSTD_longOffset_e const long
BIT_reloadDStream(&seqState->DStream); BIT_reloadDStream(&seqState->DStream);
{ size_t const pos = seqState->pos + seq.litLength; { size_t const pos = seqState->pos + seq.litLength;
const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart; seq.match = seqState->base + pos - seq.offset; /* single memory segment */
seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. if (seq.offset > pos) seq.match += seqState->gotoDict; /* separate memory segment */
* No consequence though : no memory access will occur, overly large offset will be detected in ZSTD_execSequenceLong() */
seqState->pos = pos + seq.matchLength; seqState->pos = pos + seq.matchLength;
} }
@@ -1244,7 +1243,7 @@ HINT_INLINE
size_t ZSTD_execSequenceLong(BYTE* op, size_t ZSTD_execSequenceLong(BYTE* op,
BYTE* const oend, seq_t sequence, BYTE* const oend, seq_t sequence,
const BYTE** litPtr, const BYTE* const litLimit, const BYTE** litPtr, const BYTE* const litLimit,
const BYTE* const prefixStart, const BYTE* const dictStart, const BYTE* const dictEnd) const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
{ {
BYTE* const oLitEnd = op + sequence.litLength; BYTE* const oLitEnd = op + sequence.litLength;
size_t const sequenceLength = sequence.litLength + sequence.matchLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength;
@@ -1254,21 +1253,21 @@ size_t ZSTD_execSequenceLong(BYTE* op,
const BYTE* match = sequence.match; const BYTE* match = sequence.match;
/* check */ /* check */
if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */ if (oMatchEnd>oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */ if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */
if (oLitEnd > oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, prefixStart, dictStart, dictEnd); if (oLitEnd>oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd);
/* copy Literals */ /* copy Literals */
ZSTD_copy8(op, *litPtr); /* note : op <= oLitEnd <= oend_w == oend - 8 */ ZSTD_copy8(op, *litPtr);
if (sequence.litLength > 8) if (sequence.litLength > 8)
ZSTD_wildcopy(op+8, (*litPtr)+8, sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */ ZSTD_wildcopy(op+8, (*litPtr)+8, sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
op = oLitEnd; op = oLitEnd;
*litPtr = iLitEnd; /* update for next sequence */ *litPtr = iLitEnd; /* update for next sequence */
/* copy Match */ /* copy Match */
if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { if (sequence.offset > (size_t)(oLitEnd - base)) {
/* offset beyond prefix */ /* offset beyond prefix */
if (sequence.offset > (size_t)(oLitEnd - dictStart)) return ERROR(corruption_detected); if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected);
if (match + sequence.matchLength <= dictEnd) { if (match + sequence.matchLength <= dictEnd) {
memmove(oLitEnd, match, sequence.matchLength); memmove(oLitEnd, match, sequence.matchLength);
return sequenceLength; return sequenceLength;
@@ -1278,7 +1277,7 @@ size_t ZSTD_execSequenceLong(BYTE* op,
memmove(oLitEnd, match, length1); memmove(oLitEnd, match, length1);
op = oLitEnd + length1; op = oLitEnd + length1;
sequence.matchLength -= length1; sequence.matchLength -= length1;
match = prefixStart; match = base;
if (op > oend_w || sequence.matchLength < MINMATCH) { if (op > oend_w || sequence.matchLength < MINMATCH) {
U32 i; U32 i;
for (i = 0; i < sequence.matchLength; ++i) op[i] = match[i]; for (i = 0; i < sequence.matchLength; ++i) op[i] = match[i];
@@ -1332,8 +1331,8 @@ static size_t ZSTD_decompressSequencesLong(
BYTE* op = ostart; BYTE* op = ostart;
const BYTE* litPtr = dctx->litPtr; const BYTE* litPtr = dctx->litPtr;
const BYTE* const litEnd = litPtr + dctx->litSize; const BYTE* const litEnd = litPtr + dctx->litSize;
const BYTE* const prefixStart = (const BYTE*) (dctx->base); const BYTE* const base = (const BYTE*) (dctx->base);
const BYTE* const dictStart = (const BYTE*) (dctx->vBase); const BYTE* const vBase = (const BYTE*) (dctx->vBase);
const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
int nbSeq; int nbSeq;
@@ -1354,9 +1353,9 @@ static size_t ZSTD_decompressSequencesLong(
int seqNb; int seqNb;
dctx->fseEntropy = 1; dctx->fseEntropy = 1;
{ U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; } { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; }
seqState.prefixStart = prefixStart; seqState.base = base;
seqState.pos = (size_t)(op-prefixStart); seqState.pos = (size_t)(op-base);
seqState.dictEnd = dictEnd; seqState.gotoDict = (uPtrDiff)dictEnd - (uPtrDiff)base; /* cast to avoid undefined behaviour */
CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected); CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected);
FSE_initDState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); FSE_initDState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
FSE_initDState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); FSE_initDState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
@@ -1371,9 +1370,9 @@ static size_t ZSTD_decompressSequencesLong(
/* decode and decompress */ /* decode and decompress */
for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && seqNb<nbSeq ; seqNb++) { for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && seqNb<nbSeq ; seqNb++) {
seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, isLongOffset); seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, isLongOffset);
size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STOSEQ_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd); size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[(seqNb-ADVANCED_SEQS) & STOSEQ_MASK], &litPtr, litEnd, base, vBase, dictEnd);
if (ZSTD_isError(oneSeqSize)) return oneSeqSize; if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
PREFETCH(sequence.match); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ PREFETCH(sequence.match);
sequences[seqNb&STOSEQ_MASK] = sequence; sequences[seqNb&STOSEQ_MASK] = sequence;
op += oneSeqSize; op += oneSeqSize;
} }
@@ -1382,7 +1381,7 @@ static size_t ZSTD_decompressSequencesLong(
/* finish queue */ /* finish queue */
seqNb -= seqAdvance; seqNb -= seqAdvance;
for ( ; seqNb<nbSeq ; seqNb++) { for ( ; seqNb<nbSeq ; seqNb++) {
size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[seqNb&STOSEQ_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd); size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[seqNb&STOSEQ_MASK], &litPtr, litEnd, base, vBase, dictEnd);
if (ZSTD_isError(oneSeqSize)) return oneSeqSize; if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
op += oneSeqSize; op += oneSeqSize;
} }
@@ -2451,16 +2450,14 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
return ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input); return ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);
} }
#endif #endif
return hSize; /* error */ return hSize; /* error */
} }
if (hSize != 0) { /* need more input */ if (hSize != 0) { /* need more input */
size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */ size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */
size_t const remainingInput = (size_t)(iend-ip); if (toLoad > (size_t)(iend-ip)) { /* not enough input to load full header */
assert(iend >= ip); if (iend-ip > 0) {
if (toLoad > remainingInput) { /* not enough input to load full header */ memcpy(zds->headerBuffer + zds->lhSize, ip, iend-ip);
if (remainingInput > 0) { zds->lhSize += iend-ip;
memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);
zds->lhSize += remainingInput;
} }
input->pos = input->size; input->pos = input->size;
return (MAX(ZSTD_frameHeaderSize_min, hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ return (MAX(ZSTD_frameHeaderSize_min, hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
@@ -2475,10 +2472,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
&& (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) { && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart); size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart);
if (cSize <= (size_t)(iend-istart)) { if (cSize <= (size_t)(iend-istart)) {
/* shortcut : using single-pass mode */
size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, zds->ddict); size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, zds->ddict);
if (ZSTD_isError(decompressedSize)) return decompressedSize; if (ZSTD_isError(decompressedSize)) return decompressedSize;
DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
ip = istart + cSize; ip = istart + cSize;
op += decompressedSize; op += decompressedSize;
zds->expected = 0; zds->expected = 0;
@@ -2501,9 +2496,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
} }
/* control buffer memory usage */ /* control buffer memory usage */
DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)", DEBUGLOG(4, "Control max buffer memory usage (max %u KB)",
(U32)(zds->fParams.windowSize >>10), (U32)(zds->maxWindowSize >> 10));
(U32)(zds->maxWindowSize >> 10) );
zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge); if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge);
@@ -2561,21 +2555,17 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
/* fall-through */ /* fall-through */
case zdss_load: case zdss_load:
{ size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
size_t const toLoad = neededInSize - zds->inPos; size_t const toLoad = neededInSize - zds->inPos; /* should always be <= remaining space within inBuff */
int const isSkipFrame = ZSTD_isSkipFrame(zds);
size_t loadedSize; size_t loadedSize;
if (isSkipFrame) { if (toLoad > zds->inBuffSize - zds->inPos) return ERROR(corruption_detected); /* should never happen */
loadedSize = MIN(toLoad, (size_t)(iend-ip)); loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip);
} else {
if (toLoad > zds->inBuffSize - zds->inPos) return ERROR(corruption_detected); /* should never happen */
loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip);
}
ip += loadedSize; ip += loadedSize;
zds->inPos += loadedSize; zds->inPos += loadedSize;
if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */ if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */
/* decode loaded input */ /* decode loaded input */
{ size_t const decodedSize = ZSTD_decompressContinue(zds, { const int isSkipFrame = ZSTD_isSkipFrame(zds);
size_t const decodedSize = ZSTD_decompressContinue(zds,
zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart, zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart,
zds->inBuff, neededInSize); zds->inBuff, neededInSize);
if (ZSTD_isError(decodedSize)) return decodedSize; if (ZSTD_isError(decodedSize)) return decodedSize;
-1
View File
@@ -72,7 +72,6 @@ size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc,
const void* dict, size_t dictSize, const void* dict, size_t dictSize,
ZSTD_parameters params, unsigned long long pledgedSrcSize) ZSTD_parameters params, unsigned long long pledgedSrcSize)
{ {
if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* preserve "0 == unknown" behavior */
return ZSTD_initCStream_advanced(zbc, dict, dictSize, params, pledgedSrcSize); return ZSTD_initCStream_advanced(zbc, dict, dictSize, params, pledgedSrcSize);
} }
+1 -1
View File
@@ -103,7 +103,7 @@ unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize)
/*-******************************************************** /*-********************************************************
* Dictionary training functions * Dictionary training functions
**********************************************************/ **********************************************************/
static unsigned ZDICT_NbCommonBytes (size_t val) static unsigned ZDICT_NbCommonBytes (register size_t val)
{ {
if (MEM_isLittleEndian()) { if (MEM_isLittleEndian()) {
if (MEM_64bits()) { if (MEM_64bits()) {
+1 -1
View File
@@ -339,7 +339,7 @@ typedef U32 DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
/**************************************************************** /****************************************************************
* Internal functions * Internal functions
****************************************************************/ ****************************************************************/
FORCE_INLINE unsigned FSE_highbit32 (U32 val) FORCE_INLINE unsigned FSE_highbit32 (register U32 val)
{ {
# if defined(_MSC_VER) /* Visual */ # if defined(_MSC_VER) /* Visual */
unsigned long r; unsigned long r;
+74 -1
View File
@@ -330,6 +330,18 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
/*
* Start by invoking BIT_initDStream().
* A chunk of the bitStream is then stored into a local register.
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
* You can then retrieve bitFields stored into the local register, **in reverse order**.
* Local register is manually filled from memory by the BIT_reloadDStream() method.
* A reload guarantee a minimum of ((8*sizeof(size_t))-7) bits when its result is BIT_DStream_unfinished.
* Otherwise, it can be less than that, so proceed accordingly.
* Checking if DStream has reached its end can be performed with BIT_endOfDStream()
*/
/****************************************** /******************************************
* unsafe API * unsafe API
******************************************/ ******************************************/
@@ -341,7 +353,7 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
/**************************************************************** /****************************************************************
* Helper functions * Helper functions
****************************************************************/ ****************************************************************/
MEM_STATIC unsigned BIT_highbit32 (U32 val) MEM_STATIC unsigned BIT_highbit32 (register U32 val)
{ {
# if defined(_MSC_VER) /* Visual */ # if defined(_MSC_VER) /* Visual */
unsigned long r=0; unsigned long r=0;
@@ -415,6 +427,13 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
return srcSize; return srcSize;
} }
/*!BIT_lookBits
* Provides next n bits from local register
* local register is not modified (bits are still present for next read/look)
* On 32-bits, maxNbBits==25
* On 64-bits, maxNbBits==57
* @return : value extracted
*/
MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits)
{ {
const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1;
@@ -434,6 +453,11 @@ MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
bitD->bitsConsumed += nbBits; bitD->bitsConsumed += nbBits;
} }
/*!BIT_readBits
* Read next n bits from local register.
* pay attention to not read more than nbBits contained into local register.
* @return : extracted value.
*/
MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits)
{ {
size_t value = BIT_lookBits(bitD, nbBits); size_t value = BIT_lookBits(bitD, nbBits);
@@ -671,6 +695,55 @@ static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bi
static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr); static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
/*
Let's now decompose FSE_decompress_usingDTable() into its unitary components.
You will decode FSE-encoded symbols from the bitStream,
and also any other bitFields you put in, **in reverse order**.
You will need a few variables to track your bitStream. They are :
BIT_DStream_t DStream; // Stream context
FSE_DState_t DState; // State context. Multiple ones are possible
FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
The first thing to do is to init the bitStream.
errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
You should then retrieve your initial state(s)
(in reverse flushing order if you have several ones) :
errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
You can then decode your data, symbol after symbol.
For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
Note : maximum allowed nbBits is 25, for 32-bits compatibility
size_t bitField = BIT_readBits(&DStream, nbBits);
All above operations only read from local register (which size depends on size_t).
Refueling the register from memory is manually performed by the reload method.
endSignal = FSE_reloadDStream(&DStream);
BIT_reloadDStream() result tells if there is still some more data to read from DStream.
BIT_DStream_unfinished : there is still some data left into the DStream.
BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
to properly detect the exact end of stream.
After each decoded symbol, check if DStream is fully consumed using this simple test :
BIT_reloadDStream(&DStream) >= BIT_DStream_completed
When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
Checking if DStream has reached its end is performed by :
BIT_endOfDStream(&DStream);
Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
FSE_endOfDState(&DState);
*/
/****************************************** /******************************************
* FSE unsafe API * FSE unsafe API
+74 -1
View File
@@ -332,6 +332,17 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
/*
* Start by invoking BIT_initDStream().
* A chunk of the bitStream is then stored into a local register.
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
* You can then retrieve bitFields stored into the local register, **in reverse order**.
* Local register is manually filled from memory by the BIT_reloadDStream() method.
* A reload guarantee a minimum of ((8*sizeof(size_t))-7) bits when its result is BIT_DStream_unfinished.
* Otherwise, it can be less than that, so proceed accordingly.
* Checking if DStream has reached its end can be performed with BIT_endOfDStream()
*/
/****************************************** /******************************************
* unsafe API * unsafe API
@@ -344,7 +355,7 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
/**************************************************************** /****************************************************************
* Helper functions * Helper functions
****************************************************************/ ****************************************************************/
MEM_STATIC unsigned BIT_highbit32 (U32 val) MEM_STATIC unsigned BIT_highbit32 (register U32 val)
{ {
# if defined(_MSC_VER) /* Visual */ # if defined(_MSC_VER) /* Visual */
unsigned long r=0; unsigned long r=0;
@@ -417,6 +428,14 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
return srcSize; return srcSize;
} }
/*!BIT_lookBits
* Provides next n bits from local register
* local register is not modified (bits are still present for next read/look)
* On 32-bits, maxNbBits==25
* On 64-bits, maxNbBits==57
* @return : value extracted
*/
MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits)
{ {
const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1;
@@ -436,6 +455,11 @@ MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
bitD->bitsConsumed += nbBits; bitD->bitsConsumed += nbBits;
} }
/*!BIT_readBits
* Read next n bits from local register.
* pay attention to not read more than nbBits contained into local register.
* @return : extracted value.
*/
MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits)
{ {
size_t value = BIT_lookBits(bitD, nbBits); size_t value = BIT_lookBits(bitD, nbBits);
@@ -673,6 +697,55 @@ static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bi
static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr); static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
/*
Let's now decompose FSE_decompress_usingDTable() into its unitary components.
You will decode FSE-encoded symbols from the bitStream,
and also any other bitFields you put in, **in reverse order**.
You will need a few variables to track your bitStream. They are :
BIT_DStream_t DStream; // Stream context
FSE_DState_t DState; // State context. Multiple ones are possible
FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
The first thing to do is to init the bitStream.
errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
You should then retrieve your initial state(s)
(in reverse flushing order if you have several ones) :
errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
You can then decode your data, symbol after symbol.
For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
Note : maximum allowed nbBits is 25, for 32-bits compatibility
size_t bitField = BIT_readBits(&DStream, nbBits);
All above operations only read from local register (which size depends on size_t).
Refueling the register from memory is manually performed by the reload method.
endSignal = FSE_reloadDStream(&DStream);
BIT_reloadDStream() result tells if there is still some more data to read from DStream.
BIT_DStream_unfinished : there is still some data left into the DStream.
BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
to properly detect the exact end of stream.
After each decoded symbol, check if DStream is fully consumed using this simple test :
BIT_reloadDStream(&DStream) >= BIT_DStream_completed
When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
Checking if DStream has reached its end is performed by :
BIT_endOfDStream(&DStream);
Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
FSE_endOfDState(&DState);
*/
/****************************************** /******************************************
* FSE unsafe API * FSE unsafe API
+72 -1
View File
@@ -738,6 +738,16 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
/*
* Start by invoking BIT_initDStream().
* A chunk of the bitStream is then stored into a local register.
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
* You can then retrieve bitFields stored into the local register, **in reverse order**.
* Local register is manually filled from memory by the BIT_reloadDStream() method.
* A reload guarantee a minimum of ((8*sizeof(size_t))-7) bits when its result is BIT_DStream_unfinished.
* Otherwise, it can be less than that, so proceed accordingly.
* Checking if DStream has reached its end can be performed with BIT_endOfDStream()
*/
/****************************************** /******************************************
@@ -751,7 +761,7 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
/**************************************************************** /****************************************************************
* Helper functions * Helper functions
****************************************************************/ ****************************************************************/
MEM_STATIC unsigned BIT_highbit32 (U32 val) MEM_STATIC unsigned BIT_highbit32 (register U32 val)
{ {
# if defined(_MSC_VER) /* Visual */ # if defined(_MSC_VER) /* Visual */
unsigned long r=0; unsigned long r=0;
@@ -824,6 +834,13 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si
return srcSize; return srcSize;
} }
/*!BIT_lookBits
* Provides next n bits from local register
* local register is not modified (bits are still present for next read/look)
* On 32-bits, maxNbBits==25
* On 64-bits, maxNbBits==57
* @return : value extracted
*/
MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits)
{ {
const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1;
@@ -843,6 +860,11 @@ MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
bitD->bitsConsumed += nbBits; bitD->bitsConsumed += nbBits;
} }
/*!BIT_readBits
* Read next n bits from local register.
* pay attention to not read more than nbBits contained into local register.
* @return : extracted value.
*/
MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits)
{ {
size_t value = BIT_lookBits(bitD, nbBits); size_t value = BIT_lookBits(bitD, nbBits);
@@ -989,6 +1011,55 @@ static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bi
static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr); static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
/*!
Let's now decompose FSE_decompress_usingDTable() into its unitary components.
You will decode FSE-encoded symbols from the bitStream,
and also any other bitFields you put in, **in reverse order**.
You will need a few variables to track your bitStream. They are :
BIT_DStream_t DStream; // Stream context
FSE_DState_t DState; // State context. Multiple ones are possible
FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
The first thing to do is to init the bitStream.
errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
You should then retrieve your initial state(s)
(in reverse flushing order if you have several ones) :
errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
You can then decode your data, symbol after symbol.
For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
Note : maximum allowed nbBits is 25, for 32-bits compatibility
size_t bitField = BIT_readBits(&DStream, nbBits);
All above operations only read from local register (which size depends on size_t).
Refueling the register from memory is manually performed by the reload method.
endSignal = FSE_reloadDStream(&DStream);
BIT_reloadDStream() result tells if there is still some more data to read from DStream.
BIT_DStream_unfinished : there is still some data left into the DStream.
BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
to properly detect the exact end of stream.
After each decoded symbol, check if DStream is fully consumed using this simple test :
BIT_reloadDStream(&DStream) >= BIT_DStream_completed
When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
Checking if DStream has reached its end is performed by :
BIT_endOfDStream(&DStream);
Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
FSE_endOfDState(&DState);
*/
/* ***************************************** /* *****************************************
* FSE unsafe API * FSE unsafe API
+73 -1
View File
@@ -736,6 +736,18 @@ MEM_STATIC BITv05_DStream_status BITv05_reloadDStream(BITv05_DStream_t* bitD);
MEM_STATIC unsigned BITv05_endOfDStream(const BITv05_DStream_t* bitD); MEM_STATIC unsigned BITv05_endOfDStream(const BITv05_DStream_t* bitD);
/*!
* Start by invoking BITv05_initDStream().
* A chunk of the bitStream is then stored into a local register.
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
* You can then retrieve bitFields stored into the local register, **in reverse order**.
* Local register is explicitly reloaded from memory by the BITv05_reloadDStream() method.
* A reload guarantee a minimum of ((8*sizeof(size_t))-7) bits when its result is BITv05_DStream_unfinished.
* Otherwise, it can be less than that, so proceed accordingly.
* Checking if DStream has reached its end can be performed with BITv05_endOfDStream()
*/
/*-**************************************** /*-****************************************
* unsafe API * unsafe API
******************************************/ ******************************************/
@@ -747,7 +759,7 @@ MEM_STATIC size_t BITv05_readBitsFast(BITv05_DStream_t* bitD, unsigned nbBits);
/*-************************************************************** /*-**************************************************************
* Helper functions * Helper functions
****************************************************************/ ****************************************************************/
MEM_STATIC unsigned BITv05_highbit32 (U32 val) MEM_STATIC unsigned BITv05_highbit32 (register U32 val)
{ {
# if defined(_MSC_VER) /* Visual */ # if defined(_MSC_VER) /* Visual */
unsigned long r=0; unsigned long r=0;
@@ -817,6 +829,13 @@ MEM_STATIC size_t BITv05_initDStream(BITv05_DStream_t* bitD, const void* srcBuff
return srcSize; return srcSize;
} }
/*!BITv05_lookBits
* Provides next n bits from local register
* local register is not modified (bits are still present for next read/look)
* On 32-bits, maxNbBits==25
* On 64-bits, maxNbBits==57
* @return : value extracted
*/
MEM_STATIC size_t BITv05_lookBits(BITv05_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BITv05_lookBits(BITv05_DStream_t* bitD, U32 nbBits)
{ {
const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1;
@@ -836,6 +855,11 @@ MEM_STATIC void BITv05_skipBits(BITv05_DStream_t* bitD, U32 nbBits)
bitD->bitsConsumed += nbBits; bitD->bitsConsumed += nbBits;
} }
/*!BITv05_readBits
* Read next n bits from local register.
* pay attention to not read more than nbBits contained into local register.
* @return : extracted value.
*/
MEM_STATIC size_t BITv05_readBits(BITv05_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BITv05_readBits(BITv05_DStream_t* bitD, U32 nbBits)
{ {
size_t value = BITv05_lookBits(bitD, nbBits); size_t value = BITv05_lookBits(bitD, nbBits);
@@ -971,6 +995,54 @@ static unsigned char FSEv05_decodeSymbol(FSEv05_DState_t* DStatePtr, BITv05_DStr
static unsigned FSEv05_endOfDState(const FSEv05_DState_t* DStatePtr); static unsigned FSEv05_endOfDState(const FSEv05_DState_t* DStatePtr);
/*!
Let's now decompose FSEv05_decompress_usingDTable() into its unitary components.
You will decode FSEv05-encoded symbols from the bitStream,
and also any other bitFields you put in, **in reverse order**.
You will need a few variables to track your bitStream. They are :
BITv05_DStream_t DStream; // Stream context
FSEv05_DState_t DState; // State context. Multiple ones are possible
FSEv05_DTable* DTablePtr; // Decoding table, provided by FSEv05_buildDTable()
The first thing to do is to init the bitStream.
errorCode = BITv05_initDStream(&DStream, srcBuffer, srcSize);
You should then retrieve your initial state(s)
(in reverse flushing order if you have several ones) :
errorCode = FSEv05_initDState(&DState, &DStream, DTablePtr);
You can then decode your data, symbol after symbol.
For information the maximum number of bits read by FSEv05_decodeSymbol() is 'tableLog'.
Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
unsigned char symbol = FSEv05_decodeSymbol(&DState, &DStream);
You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
Note : maximum allowed nbBits is 25, for 32-bits compatibility
size_t bitField = BITv05_readBits(&DStream, nbBits);
All above operations only read from local register (which size depends on size_t).
Refueling the register from memory is manually performed by the reload method.
endSignal = FSEv05_reloadDStream(&DStream);
BITv05_reloadDStream() result tells if there is still some more data to read from DStream.
BITv05_DStream_unfinished : there is still some data left into the DStream.
BITv05_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
BITv05_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
BITv05_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
When reaching end of buffer (BITv05_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
to properly detect the exact end of stream.
After each decoded symbol, check if DStream is fully consumed using this simple test :
BITv05_reloadDStream(&DStream) >= BITv05_DStream_completed
When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
Checking if DStream has reached its end is performed by :
BITv05_endOfDStream(&DStream);
Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
FSEv05_endOfDState(&DState);
*/
/* ***************************************** /* *****************************************
+77 -1
View File
@@ -839,6 +839,16 @@ MEM_STATIC BITv06_DStream_status BITv06_reloadDStream(BITv06_DStream_t* bitD);
MEM_STATIC unsigned BITv06_endOfDStream(const BITv06_DStream_t* bitD); MEM_STATIC unsigned BITv06_endOfDStream(const BITv06_DStream_t* bitD);
/* Start by invoking BITv06_initDStream().
* A chunk of the bitStream is then stored into a local register.
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
* You can then retrieve bitFields stored into the local register, **in reverse order**.
* Local register is explicitly reloaded from memory by the BITv06_reloadDStream() method.
* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BITv06_DStream_unfinished.
* Otherwise, it can be less than that, so proceed accordingly.
* Checking if DStream has reached its end can be performed with BITv06_endOfDStream().
*/
/*-**************************************** /*-****************************************
* unsafe API * unsafe API
@@ -851,7 +861,7 @@ MEM_STATIC size_t BITv06_readBitsFast(BITv06_DStream_t* bitD, unsigned nbBits);
/*-************************************************************** /*-**************************************************************
* Internal functions * Internal functions
****************************************************************/ ****************************************************************/
MEM_STATIC unsigned BITv06_highbit32 ( U32 val) MEM_STATIC unsigned BITv06_highbit32 (register U32 val)
{ {
# if defined(_MSC_VER) /* Visual */ # if defined(_MSC_VER) /* Visual */
unsigned long r=0; unsigned long r=0;
@@ -919,6 +929,13 @@ MEM_STATIC size_t BITv06_initDStream(BITv06_DStream_t* bitD, const void* srcBuff
} }
/*! BITv06_lookBits() :
* Provides next n bits from local register.
* local register is not modified.
* On 32-bits, maxNbBits==24.
* On 64-bits, maxNbBits==56.
* @return : value extracted
*/
MEM_STATIC size_t BITv06_lookBits(const BITv06_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BITv06_lookBits(const BITv06_DStream_t* bitD, U32 nbBits)
{ {
U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
@@ -938,6 +955,11 @@ MEM_STATIC void BITv06_skipBits(BITv06_DStream_t* bitD, U32 nbBits)
bitD->bitsConsumed += nbBits; bitD->bitsConsumed += nbBits;
} }
/*! BITv06_readBits() :
* Read (consume) next n bits from local register and update.
* Pay attention to not read more than nbBits contained into local register.
* @return : extracted value.
*/
MEM_STATIC size_t BITv06_readBits(BITv06_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BITv06_readBits(BITv06_DStream_t* bitD, U32 nbBits)
{ {
size_t const value = BITv06_lookBits(bitD, nbBits); size_t const value = BITv06_lookBits(bitD, nbBits);
@@ -954,6 +976,11 @@ MEM_STATIC size_t BITv06_readBitsFast(BITv06_DStream_t* bitD, U32 nbBits)
return value; return value;
} }
/*! BITv06_reloadDStream() :
* Refill `BITv06_DStream_t` from src buffer previously defined (see BITv06_initDStream() ).
* This function is safe, it guarantees it will not read beyond src buffer.
* @return : status of `BITv06_DStream_t` internal register.
if status == unfinished, internal register is filled with >= (sizeof(bitD->bitContainer)*8 - 7) bits */
MEM_STATIC BITv06_DStream_status BITv06_reloadDStream(BITv06_DStream_t* bitD) MEM_STATIC BITv06_DStream_status BITv06_reloadDStream(BITv06_DStream_t* bitD)
{ {
if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should never happen */ if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should never happen */
@@ -1076,6 +1103,55 @@ static void FSEv06_initDState(FSEv06_DState_t* DStatePtr, BITv06_DStream_t*
static unsigned char FSEv06_decodeSymbol(FSEv06_DState_t* DStatePtr, BITv06_DStream_t* bitD); static unsigned char FSEv06_decodeSymbol(FSEv06_DState_t* DStatePtr, BITv06_DStream_t* bitD);
/*!
Let's now decompose FSEv06_decompress_usingDTable() into its unitary components.
You will decode FSE-encoded symbols from the bitStream,
and also any other bitFields you put in, **in reverse order**.
You will need a few variables to track your bitStream. They are :
BITv06_DStream_t DStream; // Stream context
FSEv06_DState_t DState; // State context. Multiple ones are possible
FSEv06_DTable* DTablePtr; // Decoding table, provided by FSEv06_buildDTable()
The first thing to do is to init the bitStream.
errorCode = BITv06_initDStream(&DStream, srcBuffer, srcSize);
You should then retrieve your initial state(s)
(in reverse flushing order if you have several ones) :
errorCode = FSEv06_initDState(&DState, &DStream, DTablePtr);
You can then decode your data, symbol after symbol.
For information the maximum number of bits read by FSEv06_decodeSymbol() is 'tableLog'.
Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
unsigned char symbol = FSEv06_decodeSymbol(&DState, &DStream);
You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
Note : maximum allowed nbBits is 25, for 32-bits compatibility
size_t bitField = BITv06_readBits(&DStream, nbBits);
All above operations only read from local register (which size depends on size_t).
Refueling the register from memory is manually performed by the reload method.
endSignal = FSEv06_reloadDStream(&DStream);
BITv06_reloadDStream() result tells if there is still some more data to read from DStream.
BITv06_DStream_unfinished : there is still some data left into the DStream.
BITv06_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
BITv06_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
BITv06_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
When reaching end of buffer (BITv06_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
to properly detect the exact end of stream.
After each decoded symbol, check if DStream is fully consumed using this simple test :
BITv06_reloadDStream(&DStream) >= BITv06_DStream_completed
When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
Checking if DStream has reached its end is performed by :
BITv06_endOfDStream(&DStream);
Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
FSEv06_endOfDState(&DState);
*/
/* ***************************************** /* *****************************************
* FSE unsafe API * FSE unsafe API
+77 -1
View File
@@ -511,6 +511,16 @@ MEM_STATIC BITv07_DStream_status BITv07_reloadDStream(BITv07_DStream_t* bitD);
MEM_STATIC unsigned BITv07_endOfDStream(const BITv07_DStream_t* bitD); MEM_STATIC unsigned BITv07_endOfDStream(const BITv07_DStream_t* bitD);
/* Start by invoking BITv07_initDStream().
* A chunk of the bitStream is then stored into a local register.
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
* You can then retrieve bitFields stored into the local register, **in reverse order**.
* Local register is explicitly reloaded from memory by the BITv07_reloadDStream() method.
* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BITv07_DStream_unfinished.
* Otherwise, it can be less than that, so proceed accordingly.
* Checking if DStream has reached its end can be performed with BITv07_endOfDStream().
*/
/*-**************************************** /*-****************************************
* unsafe API * unsafe API
@@ -523,7 +533,7 @@ MEM_STATIC size_t BITv07_readBitsFast(BITv07_DStream_t* bitD, unsigned nbBits);
/*-************************************************************** /*-**************************************************************
* Internal functions * Internal functions
****************************************************************/ ****************************************************************/
MEM_STATIC unsigned BITv07_highbit32 (U32 val) MEM_STATIC unsigned BITv07_highbit32 (register U32 val)
{ {
# if defined(_MSC_VER) /* Visual */ # if defined(_MSC_VER) /* Visual */
unsigned long r=0; unsigned long r=0;
@@ -589,6 +599,13 @@ MEM_STATIC size_t BITv07_initDStream(BITv07_DStream_t* bitD, const void* srcBuff
} }
/*! BITv07_lookBits() :
* Provides next n bits from local register.
* local register is not modified.
* On 32-bits, maxNbBits==24.
* On 64-bits, maxNbBits==56.
* @return : value extracted
*/
MEM_STATIC size_t BITv07_lookBits(const BITv07_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BITv07_lookBits(const BITv07_DStream_t* bitD, U32 nbBits)
{ {
U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
@@ -608,6 +625,11 @@ MEM_STATIC void BITv07_skipBits(BITv07_DStream_t* bitD, U32 nbBits)
bitD->bitsConsumed += nbBits; bitD->bitsConsumed += nbBits;
} }
/*! BITv07_readBits() :
* Read (consume) next n bits from local register and update.
* Pay attention to not read more than nbBits contained into local register.
* @return : extracted value.
*/
MEM_STATIC size_t BITv07_readBits(BITv07_DStream_t* bitD, U32 nbBits) MEM_STATIC size_t BITv07_readBits(BITv07_DStream_t* bitD, U32 nbBits)
{ {
size_t const value = BITv07_lookBits(bitD, nbBits); size_t const value = BITv07_lookBits(bitD, nbBits);
@@ -624,6 +646,11 @@ MEM_STATIC size_t BITv07_readBitsFast(BITv07_DStream_t* bitD, U32 nbBits)
return value; return value;
} }
/*! BITv07_reloadDStream() :
* Refill `BITv07_DStream_t` from src buffer previously defined (see BITv07_initDStream() ).
* This function is safe, it guarantees it will not read beyond src buffer.
* @return : status of `BITv07_DStream_t` internal register.
if status == unfinished, internal register is filled with >= (sizeof(bitD->bitContainer)*8 - 7) bits */
MEM_STATIC BITv07_DStream_status BITv07_reloadDStream(BITv07_DStream_t* bitD) MEM_STATIC BITv07_DStream_status BITv07_reloadDStream(BITv07_DStream_t* bitD)
{ {
if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should not happen => corruption detected */ if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should not happen => corruption detected */
@@ -847,6 +874,55 @@ static void FSEv07_initDState(FSEv07_DState_t* DStatePtr, BITv07_DStream_t*
static unsigned char FSEv07_decodeSymbol(FSEv07_DState_t* DStatePtr, BITv07_DStream_t* bitD); static unsigned char FSEv07_decodeSymbol(FSEv07_DState_t* DStatePtr, BITv07_DStream_t* bitD);
/**<
Let's now decompose FSEv07_decompress_usingDTable() into its unitary components.
You will decode FSE-encoded symbols from the bitStream,
and also any other bitFields you put in, **in reverse order**.
You will need a few variables to track your bitStream. They are :
BITv07_DStream_t DStream; // Stream context
FSEv07_DState_t DState; // State context. Multiple ones are possible
FSEv07_DTable* DTablePtr; // Decoding table, provided by FSEv07_buildDTable()
The first thing to do is to init the bitStream.
errorCode = BITv07_initDStream(&DStream, srcBuffer, srcSize);
You should then retrieve your initial state(s)
(in reverse flushing order if you have several ones) :
errorCode = FSEv07_initDState(&DState, &DStream, DTablePtr);
You can then decode your data, symbol after symbol.
For information the maximum number of bits read by FSEv07_decodeSymbol() is 'tableLog'.
Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
unsigned char symbol = FSEv07_decodeSymbol(&DState, &DStream);
You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
Note : maximum allowed nbBits is 25, for 32-bits compatibility
size_t bitField = BITv07_readBits(&DStream, nbBits);
All above operations only read from local register (which size depends on size_t).
Refueling the register from memory is manually performed by the reload method.
endSignal = FSEv07_reloadDStream(&DStream);
BITv07_reloadDStream() result tells if there is still some more data to read from DStream.
BITv07_DStream_unfinished : there is still some data left into the DStream.
BITv07_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
BITv07_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
BITv07_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
When reaching end of buffer (BITv07_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
to properly detect the exact end of stream.
After each decoded symbol, check if DStream is fully consumed using this simple test :
BITv07_reloadDStream(&DStream) >= BITv07_DStream_completed
When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
Checking if DStream has reached its end is performed by :
BITv07_endOfDStream(&DStream);
Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
FSEv07_endOfDState(&DState);
*/
/* ***************************************** /* *****************************************
* FSE unsafe API * FSE unsafe API
+30 -43
View File
@@ -59,7 +59,7 @@ extern "C" {
/*------ Version ------*/ /*------ Version ------*/
#define ZSTD_VERSION_MAJOR 1 #define ZSTD_VERSION_MAJOR 1
#define ZSTD_VERSION_MINOR 3 #define ZSTD_VERSION_MINOR 3
#define ZSTD_VERSION_RELEASE 3 #define ZSTD_VERSION_RELEASE 2
#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) #define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< useful to check dll version */ ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< useful to check dll version */
@@ -131,7 +131,7 @@ ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t
/*====== Helper functions ======*/ /*====== Helper functions ======*/
#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */ #define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < 128 KB) ? ((128 KB - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */
ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case scenario */ ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case scenario */
ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */
ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */ ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */
@@ -432,12 +432,12 @@ typedef struct {
typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params; typedef struct ZSTD_CCtx_params_s ZSTD_CCtx_params;
/*--- Custom memory allocation functions ---*/ /*= Custom memory allocation functions */
typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size);
typedef void (*ZSTD_freeFunction) (void* opaque, void* address); typedef void (*ZSTD_freeFunction) (void* opaque, void* address);
typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem;
/* use this constant to defer to stdlib's functions */ /* use this constant to defer to stdlib's functions */
static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; static const ZSTD_customMem ZSTD_defaultCMem = { NULL, NULL, NULL };
/*************************************** /***************************************
@@ -446,7 +446,7 @@ static ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL };
/*! ZSTD_findFrameCompressedSize() : /*! ZSTD_findFrameCompressedSize() :
* `src` should point to the start of a ZSTD encoded frame or skippable frame * `src` should point to the start of a ZSTD encoded frame or skippable frame
* `srcSize` must be >= first frame size * `srcSize` must be at least as large as the frame
* @return : the compressed size of the first frame starting at `src`, * @return : the compressed size of the first frame starting at `src`,
* suitable to pass to `ZSTD_decompress` or similar, * suitable to pass to `ZSTD_decompress` or similar,
* or an error code if input is invalid */ * or an error code if input is invalid */
@@ -557,8 +557,7 @@ ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem);
* It must outlive context usage. * It must outlive context usage.
* workspaceSize: Use ZSTD_estimateCCtxSize() or ZSTD_estimateCStreamSize() * workspaceSize: Use ZSTD_estimateCCtxSize() or ZSTD_estimateCStreamSize()
* to determine how large workspace must be to support scenario. * to determine how large workspace must be to support scenario.
* @return : pointer to ZSTD_CCtx* (same address as workspace, but different type), * @return : pointer to ZSTD_CCtx*, or NULL if error (size too small)
* or NULL if error (typically size too small)
* Note : zstd will never resize nor malloc() when using a static cctx. * Note : zstd will never resize nor malloc() when using a static cctx.
* If it needs more memory than available, it will simply error out. * If it needs more memory than available, it will simply error out.
* Note 2 : there is no corresponding "free" function. * Note 2 : there is no corresponding "free" function.
@@ -588,7 +587,7 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictS
ZSTD_compressionParameters cParams, ZSTD_compressionParameters cParams,
ZSTD_customMem customMem); ZSTD_customMem customMem);
/*! ZSTD_initStaticCDict() : /*! ZSTD_initStaticCDict_advanced() :
* Generate a digested dictionary in provided memory area. * Generate a digested dictionary in provided memory area.
* workspace: The memory area to emplace the dictionary into. * workspace: The memory area to emplace the dictionary into.
* Provided pointer must 8-bytes aligned. * Provided pointer must 8-bytes aligned.
@@ -597,8 +596,7 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictS
* to determine how large workspace must be. * to determine how large workspace must be.
* cParams : use ZSTD_getCParams() to transform a compression level * cParams : use ZSTD_getCParams() to transform a compression level
* into its relevants cParams. * into its relevants cParams.
* @return : pointer to ZSTD_CDict* (same address as workspace, but different type), * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
* or NULL if error (typically, size too small).
* Note : there is no corresponding "free" function. * Note : there is no corresponding "free" function.
* Since workspace was allocated externally, it must be freed externally. * Since workspace was allocated externally, it must be freed externally.
*/ */
@@ -615,7 +613,7 @@ ZSTDLIB_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, uns
/*! ZSTD_getParams() : /*! ZSTD_getParams() :
* same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`. * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`.
* All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */ * All fields of `ZSTD_frameParameters` are set to default (0) */
ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);
/*! ZSTD_checkCParams() : /*! ZSTD_checkCParams() :
@@ -662,8 +660,7 @@ ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem);
* It must outlive context usage. * It must outlive context usage.
* workspaceSize: Use ZSTD_estimateDCtxSize() or ZSTD_estimateDStreamSize() * workspaceSize: Use ZSTD_estimateDCtxSize() or ZSTD_estimateDStreamSize()
* to determine how large workspace must be to support scenario. * to determine how large workspace must be to support scenario.
* @return : pointer to ZSTD_DCtx* (same address as workspace, but different type), * @return : pointer to ZSTD_DCtx*, or NULL if error (size too small)
* or NULL if error (typically size too small)
* Note : zstd will never resize nor malloc() when using a static dctx. * Note : zstd will never resize nor malloc() when using a static dctx.
* If it needs more memory than available, it will simply error out. * If it needs more memory than available, it will simply error out.
* Note 2 : static dctx is incompatible with legacy support * Note 2 : static dctx is incompatible with legacy support
@@ -734,22 +731,20 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
/*===== Advanced Streaming compression functions =====*/ /*===== Advanced Streaming compression functions =====*/
ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);
ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */
ZSTDLIB_API size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); /**< pledgedSrcSize must be correct. If it is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, "0" also disables frame content size field. It may be enabled in the future. */ ZSTDLIB_API size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize); /**< pledgedSrcSize must be correct, a size of 0 means unknown. for a frame size of 0 use initCStream_advanced */
ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/ ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); /**< creates of an internal CDict (incompatible with static CCtx), except if dict == NULL or dictSize < 8, in which case no dict is used. Note: dict is loaded with ZSTD_dm_auto (treated as a full zstd dictionary if it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy.*/
ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,
ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize must be correct. If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. dict is loaded with ZSTD_dm_auto and ZSTD_dlm_byCopy. */ ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0. dict is loaded with ZSTD_dm_auto and ZSTD_dlm_byCopy. */
ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); /**< note : cdict will just be referenced, and must outlive compression session */ ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); /**< note : cdict will just be referenced, and must outlive compression session */
ZSTDLIB_API size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize); /**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters. pledgedSrcSize must be correct. If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. */ ZSTDLIB_API size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize); /**< same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
/*! ZSTD_resetCStream() : /*! ZSTD_resetCStream() :
* start a new compression job, using same parameters from previous job. * start a new compression job, using same parameters from previous job.
* This is typically useful to skip dictionary loading stage, since it will re-use it in-place.. * This is typically useful to skip dictionary loading stage, since it will re-use it in-place..
* Note that zcs must be init at least once before using ZSTD_resetCStream(). * Note that zcs must be init at least once before using ZSTD_resetCStream().
* If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN. * pledgedSrcSize==0 means "srcSize unknown".
* If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end. * If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end.
* For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs, * @return : 0, or an error code (which can be tested using ZSTD_isError()) */
* but it may change to mean "empty" in some future version, so prefer using macro ZSTD_CONTENTSIZE_UNKNOWN.
* @return : 0, or an error code (which can be tested using ZSTD_isError()) */
ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
@@ -805,10 +800,10 @@ ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompress
/*===== Buffer-less streaming compression functions =====*/ /*===== Buffer-less streaming compression functions =====*/
ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);
ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);
ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be 0 (meaning unknown). note: if the contentSizeFlag is set, pledgedSrcSize == 0 means the source size is actually 0 */
ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */
ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize=0 means null-size */
ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize can be 0, indicating unknown size. if it is non-zero, it must be accurate. for 0 size frames, use compressBegin_advanced */
ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);
@@ -1005,19 +1000,18 @@ typedef enum {
* Special: value 0 means "do not change strategy". */ * Special: value 0 means "do not change strategy". */
/* frame parameters */ /* frame parameters */
ZSTD_p_contentSizeFlag=200, /* Content size will be written into frame header _whenever known_ (default:1) ZSTD_p_contentSizeFlag=200, /* Content size is written into frame header _whenever known_ (default:1)
* Content size must be known at the beginning of compression, * note that content size must be known at the beginning,
* it is provided using ZSTD_CCtx_setPledgedSrcSize() */ * it is sent using ZSTD_CCtx_setPledgedSrcSize() */
ZSTD_p_checksumFlag, /* A 32-bits checksum of content is written at end of frame (default:0) */ ZSTD_p_checksumFlag, /* A 32-bits checksum of content is written at end of frame (default:0) */
ZSTD_p_dictIDFlag, /* When applicable, dictionary's ID is written into frame header (default:1) */ ZSTD_p_dictIDFlag, /* When applicable, dictID of dictionary is provided in frame header (default:1) */
/* multi-threading parameters */ /* multi-threading parameters */
ZSTD_p_nbThreads=400, /* Select how many threads a compression job can spawn (default:1) ZSTD_p_nbThreads=400, /* Select how many threads a compression job can spawn (default:1)
* More threads improve speed, but also increase memory usage. * More threads improve speed, but also increase memory usage.
* Can only receive a value > 1 if ZSTD_MULTITHREAD is enabled. * Can only receive a value > 1 if ZSTD_MULTITHREAD is enabled.
* Special: value 0 means "do not change nbThreads" */ * Special: value 0 means "do not change nbThreads" */
ZSTD_p_jobSize, /* Size of a compression job. This value is only enforced in streaming (non-blocking) mode. ZSTD_p_jobSize, /* Size of a compression job. Each compression job is completed in parallel.
* Each compression job is completed in parallel, so indirectly controls the nb of active threads.
* 0 means default, which is dynamically determined based on compression parameters. * 0 means default, which is dynamically determined based on compression parameters.
* Job size must be a minimum of overlapSize, or 1 KB, whichever is largest * Job size must be a minimum of overlapSize, or 1 KB, whichever is largest
* The minimum size is automatically and transparently enforced */ * The minimum size is automatically and transparently enforced */
@@ -1063,8 +1057,7 @@ typedef enum {
/*! ZSTD_CCtx_setParameter() : /*! ZSTD_CCtx_setParameter() :
* Set one compression parameter, selected by enum ZSTD_cParameter. * Set one compression parameter, selected by enum ZSTD_cParameter.
* Note : when `value` is an enum, cast it to unsigned for proper type checking. * Note : when `value` is an enum, cast it to unsigned for proper type checking.
* @result : informational value (typically, the one being set, possibly corrected), * @result : 0, or an error code (which can be tested with ZSTD_isError()). */
* or an error code (which can be tested with ZSTD_isError()). */
ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value); ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value);
/*! ZSTD_CCtx_setPledgedSrcSize() : /*! ZSTD_CCtx_setPledgedSrcSize() :
@@ -1073,7 +1066,7 @@ ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param
* @result : 0, or an error code (which can be tested with ZSTD_isError()). * @result : 0, or an error code (which can be tested with ZSTD_isError()).
* Note 1 : 0 means zero, empty. * Note 1 : 0 means zero, empty.
* In order to mean "unknown content size", pass constant ZSTD_CONTENTSIZE_UNKNOWN. * In order to mean "unknown content size", pass constant ZSTD_CONTENTSIZE_UNKNOWN.
* ZSTD_CONTENTSIZE_UNKNOWN is default value for any new compression job. * Note that ZSTD_CONTENTSIZE_UNKNOWN is default value for new compression jobs.
* Note 2 : If all data is provided and consumed in a single round, * Note 2 : If all data is provided and consumed in a single round,
* this value is overriden by srcSize instead. */ * this value is overriden by srcSize instead. */
ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize); ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize);
@@ -1145,19 +1138,13 @@ typedef enum {
* - Compression parameters cannot be changed once compression is started. * - Compression parameters cannot be changed once compression is started.
* - outpot->pos must be <= dstCapacity, input->pos must be <= srcSize * - outpot->pos must be <= dstCapacity, input->pos must be <= srcSize
* - outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit. * - outpot->pos and input->pos will be updated. They are guaranteed to remain below their respective limit.
* - In single-thread mode (default), function is blocking : it completed its job before returning to caller. * - @return provides the minimum amount of data still to flush from internal buffers
* - In multi-thread mode, function is non-blocking : it just acquires a copy of input, and distribute job to internal worker threads,
* and then immediately returns, just indicating that there is some data remaining to be flushed.
* The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte.
* - Exception : in multi-threading mode, if the first call requests a ZSTD_e_end directive, it is blocking : it will complete compression before giving back control to caller.
* - @return provides the minimum amount of data remaining to be flushed from internal buffers
* or an error code, which can be tested using ZSTD_isError(). * or an error code, which can be tested using ZSTD_isError().
* if @return != 0, flush is not fully completed, there is still some data left within internal buffers. * if @return != 0, flush is not fully completed, there is some data left within internal buffers.
* This is useful to determine if a ZSTD_e_flush or ZSTD_e_end directive is completed. * - after a ZSTD_e_end directive, if internal buffer is not fully flushed,
* - after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0),
* only ZSTD_e_end or ZSTD_e_flush operations are allowed. * only ZSTD_e_end or ZSTD_e_flush operations are allowed.
* Before starting a new compression job, or changing compression parameters, * It is necessary to fully flush internal buffers
* it is required to fully flush internal buffers. * before starting a new compression job, or changing compression parameters.
*/ */
ZSTDLIB_API size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, ZSTDLIB_API size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
ZSTD_outBuffer* output, ZSTD_outBuffer* output,
+30 -11
View File
@@ -10,19 +10,38 @@ cxx_binary(
'//lib:mem', '//lib:mem',
'//lib:xxhash', '//lib:xxhash',
], ],
preprocessor_flags=[ )
'-DZSTD_GZCOMPRESS',
'-DZSTD_GZDECOMPRESS', cxx_binary(
'-DZSTD_LZMACOMPRESS', name='zstdmt',
'-DZSTD_LZMADECOMPRES', headers=glob(['*.h'], excludes=['datagen.h', 'platform.h', 'util.h']),
'-DZSTD_LZ4COMPRESS', srcs=glob(['*.c'], excludes=['datagen.c']),
'-DZSTD_LZ4DECOMPRES', deps=[
':datagen',
':util',
'//lib:zstd',
'//lib:zdict',
'//lib:mem',
'//lib:xxhash',
], ],
linker_flags=[ preprocessor_flags=['-DZSTD_MULTITHREAD'],
'-lz', linker_flags=['-lpthread'],
'-llzma', )
'-llz4',
cxx_binary(
name='gzstd',
headers=glob(['*.h'], excludes=['datagen.h', 'platform.h', 'util.h']),
srcs=glob(['*.c'], excludes=['datagen.c']),
deps=[
':datagen',
':util',
'//lib:zstd',
'//lib:zdict',
'//lib:mem',
'//lib:xxhash',
], ],
preprocessor_flags=['-DZSTD_GZDECOMPRESS'],
linker_flags=['-lz'],
) )
cxx_library( cxx_library(
+13 -14
View File
@@ -37,7 +37,8 @@ endif
CPPFLAGS+= -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \ CPPFLAGS+= -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/compress \
-I$(ZSTDDIR)/dictBuilder \ -I$(ZSTDDIR)/dictBuilder \
-DXXH_NAMESPACE=ZSTD_ -DZSTD_NEWAPI \
-DXXH_NAMESPACE=ZSTD_ # because xxhash.o already compiled with this macro from library
CFLAGS ?= -O3 CFLAGS ?= -O3
DEBUGFLAGS+=-Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ DEBUGFLAGS+=-Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
-Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \ -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \
@@ -65,7 +66,6 @@ endif
else else
endif endif
# Sort files in alphabetical order for reproducible builds
ZSTDLIB_FILES := $(sort $(wildcard $(ZSTD_FILES)) $(wildcard $(ZSTDLEGACY_FILES)) $(wildcard $(ZDICT_FILES))) ZSTDLIB_FILES := $(sort $(wildcard $(ZSTD_FILES)) $(wildcard $(ZSTDLEGACY_FILES)) $(wildcard $(ZDICT_FILES)))
# Define *.exe as extension for Windows systems # Define *.exe as extension for Windows systems
@@ -226,8 +226,8 @@ clean:
MD2ROFF = ronn MD2ROFF = ronn
MD2ROFF_FLAGS = --roff --warnings --manual="User Commands" --organization="zstd $(ZSTD_VERSION)" MD2ROFF_FLAGS = --roff --warnings --manual="User Commands" --organization="zstd $(ZSTD_VERSION)"
zstd.1: zstd.1.md ../lib/zstd.h zstd.1: zstd.1.md
cat $< | $(MD2ROFF) $(MD2ROFF_FLAGS) | sed -n '/^\.\\\".*/!p' > $@ cat $^ | $(MD2ROFF) $(MD2ROFF_FLAGS) | sed -n '/^\.\\\".*/!p' > $@
.PHONY: man .PHONY: man
man: zstd.1 man: zstd.1
@@ -263,10 +263,9 @@ mandir ?= $(datarootdir)/man
man1dir ?= $(mandir)/man1 man1dir ?= $(mandir)/man1
ifneq (,$(filter $(shell uname),OpenBSD FreeBSD NetBSD DragonFly SunOS)) ifneq (,$(filter $(shell uname),OpenBSD FreeBSD NetBSD DragonFly SunOS))
MANDIR ?= $(PREFIX)/man MANDIR ?= $(PREFIX)/man/man1
MAN1DIR ?= $(MANDIR)/man1
else else
MAN1DIR ?= $(man1dir) MANDIR ?= $(man1dir)
endif endif
ifneq (,$(filter $(shell uname),SunOS)) ifneq (,$(filter $(shell uname),SunOS))
@@ -283,7 +282,7 @@ INSTALL_MAN ?= $(INSTALL_DATA)
.PHONY: install .PHONY: install
install: zstd install: zstd
@echo Installing binaries @echo Installing binaries
@$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)/ $(DESTDIR)$(MAN1DIR)/ @$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)/ $(DESTDIR)$(MANDIR)/
@$(INSTALL_PROGRAM) zstd $(DESTDIR)$(BINDIR)/zstd @$(INSTALL_PROGRAM) zstd $(DESTDIR)$(BINDIR)/zstd
@ln -sf zstd $(DESTDIR)$(BINDIR)/zstdcat @ln -sf zstd $(DESTDIR)$(BINDIR)/zstdcat
@ln -sf zstd $(DESTDIR)$(BINDIR)/unzstd @ln -sf zstd $(DESTDIR)$(BINDIR)/unzstd
@@ -291,9 +290,9 @@ install: zstd
@$(INSTALL_SCRIPT) zstdless $(DESTDIR)$(BINDIR)/zstdless @$(INSTALL_SCRIPT) zstdless $(DESTDIR)$(BINDIR)/zstdless
@$(INSTALL_SCRIPT) zstdgrep $(DESTDIR)$(BINDIR)/zstdgrep @$(INSTALL_SCRIPT) zstdgrep $(DESTDIR)$(BINDIR)/zstdgrep
@echo Installing man pages @echo Installing man pages
@$(INSTALL_MAN) zstd.1 $(DESTDIR)$(MAN1DIR)/zstd.1 @$(INSTALL_MAN) zstd.1 $(DESTDIR)$(MANDIR)/zstd.1
@ln -sf zstd.1 $(DESTDIR)$(MAN1DIR)/zstdcat.1 @ln -sf zstd.1 $(DESTDIR)$(MANDIR)/zstdcat.1
@ln -sf zstd.1 $(DESTDIR)$(MAN1DIR)/unzstd.1 @ln -sf zstd.1 $(DESTDIR)$(MANDIR)/unzstd.1
@echo zstd installation completed @echo zstd installation completed
.PHONY: uninstall .PHONY: uninstall
@@ -303,9 +302,9 @@ uninstall:
@$(RM) $(DESTDIR)$(BINDIR)/zstdcat @$(RM) $(DESTDIR)$(BINDIR)/zstdcat
@$(RM) $(DESTDIR)$(BINDIR)/unzstd @$(RM) $(DESTDIR)$(BINDIR)/unzstd
@$(RM) $(DESTDIR)$(BINDIR)/zstd @$(RM) $(DESTDIR)$(BINDIR)/zstd
@$(RM) $(DESTDIR)$(MAN1DIR)/zstdcat.1 @$(RM) $(DESTDIR)$(MANDIR)/zstdcat.1
@$(RM) $(DESTDIR)$(MAN1DIR)/unzstd.1 @$(RM) $(DESTDIR)$(MANDIR)/unzstd.1
@$(RM) $(DESTDIR)$(MAN1DIR)/zstd.1 @$(RM) $(DESTDIR)$(MANDIR)/zstd.1
@echo zstd programs successfully uninstalled @echo zstd programs successfully uninstalled
endif endif
+104 -124
View File
@@ -34,12 +34,14 @@
#include <stdlib.h> /* malloc, free */ #include <stdlib.h> /* malloc, free */
#include <string.h> /* memset */ #include <string.h> /* memset */
#include <stdio.h> /* fprintf, fopen */ #include <stdio.h> /* fprintf, fopen */
#include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */
#include "mem.h" #include "mem.h"
#define ZSTD_STATIC_LINKING_ONLY #define ZSTD_STATIC_LINKING_ONLY
#include "zstd.h" #include "zstd.h"
#include "datagen.h" /* RDG_genBuffer */ #include "datagen.h" /* RDG_genBuffer */
#include "xxhash.h" #include "xxhash.h"
#include "zstdmt_compress.h"
/* ************************************* /* *************************************
@@ -71,13 +73,12 @@ static U32 g_compressibilityDefault = 50;
#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
static int g_displayLevel = 2; /* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */ static int g_displayLevel = 2; /* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */
static const U64 g_refreshRate = SEC_TO_MICRO / 6; #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER; if ((clock() - g_time > refreshRate) || (g_displayLevel>=4)) \
{ g_time = clock(); DISPLAY(__VA_ARGS__); \
#define DISPLAYUPDATE(l, ...) { if (g_displayLevel>=l) { \ if (g_displayLevel>=4) fflush(stderr); } }
if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \ static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \ static clock_t g_time = 0;
if (g_displayLevel>=4) fflush(stderr); } } }
/* ************************************* /* *************************************
@@ -129,17 +130,6 @@ void BMK_setNbThreads(unsigned nbThreads) {
#endif #endif
g_nbThreads = nbThreads; g_nbThreads = nbThreads;
} }
static U32 g_realTime = 0;
void BMK_setRealTime(unsigned priority) {
g_realTime = (priority>0);
}
static U32 g_separateFiles = 0;
void BMK_setSeparateFiles(unsigned separate) {
g_separateFiles = (separate>0);
}
static U32 g_ldmFlag = 0; static U32 g_ldmFlag = 0;
void BMK_setLdmFlag(unsigned ldmFlag) { void BMK_setLdmFlag(unsigned ldmFlag) {
g_ldmFlag = ldmFlag; g_ldmFlag = ldmFlag;
@@ -191,7 +181,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
const char* displayName, int cLevel, const char* displayName, int cLevel,
const size_t* fileSizes, U32 nbFiles, const size_t* fileSizes, U32 nbFiles,
const void* dictBuffer, size_t dictBufferSize, const void* dictBuffer, size_t dictBufferSize,
const ZSTD_compressionParameters* const comprParams) const ZSTD_compressionParameters* comprParams)
{ {
size_t const blockSize = ((g_blockSize>=32 && !g_decodeOnly) ? g_blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ; size_t const blockSize = ((g_blockSize>=32 && !g_decodeOnly) ? g_blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ;
U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles; U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles;
@@ -199,6 +189,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
size_t const maxCompressedSize = ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024); /* add some room for safety */ size_t const maxCompressedSize = ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024); /* add some room for safety */
void* const compressedBuffer = malloc(maxCompressedSize); void* const compressedBuffer = malloc(maxCompressedSize);
void* resultBuffer = malloc(srcSize); void* resultBuffer = malloc(srcSize);
ZSTDMT_CCtx* const mtctx = ZSTDMT_createCCtx(g_nbThreads);
ZSTD_CCtx* const ctx = ZSTD_createCCtx(); ZSTD_CCtx* const ctx = ZSTD_createCCtx();
ZSTD_DCtx* const dctx = ZSTD_createDCtx(); ZSTD_DCtx* const dctx = ZSTD_createDCtx();
size_t const loadedCompressedSize = srcSize; size_t const loadedCompressedSize = srcSize;
@@ -295,6 +286,8 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
if (!cCompleted) { /* still some time to do compression tests */ if (!cCompleted) { /* still some time to do compression tests */
U64 const clockLoop = g_nbSeconds ? TIMELOOP_MICROSEC : 1; U64 const clockLoop = g_nbSeconds ? TIMELOOP_MICROSEC : 1;
U32 nbLoops = 0; U32 nbLoops = 0;
ZSTD_CDict* cdict = NULL;
#ifdef ZSTD_NEWAPI
ZSTD_CCtx_setParameter(ctx, ZSTD_p_nbThreads, g_nbThreads); ZSTD_CCtx_setParameter(ctx, ZSTD_p_nbThreads, g_nbThreads);
ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionLevel, cLevel); ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionLevel, cLevel);
ZSTD_CCtx_setParameter(ctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag); ZSTD_CCtx_setParameter(ctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag);
@@ -313,64 +306,84 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
ZSTD_CCtx_setParameter(ctx, ZSTD_p_targetLength, comprParams->targetLength); ZSTD_CCtx_setParameter(ctx, ZSTD_p_targetLength, comprParams->targetLength);
ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionStrategy, comprParams->strategy); ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionStrategy, comprParams->strategy);
ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize); ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize);
#else
size_t const avgSize = MIN(blockSize, (srcSize / nbFiles));
ZSTD_parameters zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize);
ZSTD_customMem const cmem = { NULL, NULL, NULL };
if (comprParams->windowLog) zparams.cParams.windowLog = comprParams->windowLog;
if (comprParams->chainLog) zparams.cParams.chainLog = comprParams->chainLog;
if (comprParams->hashLog) zparams.cParams.hashLog = comprParams->hashLog;
if (comprParams->searchLog) zparams.cParams.searchLog = comprParams->searchLog;
if (comprParams->searchLength) zparams.cParams.searchLength = comprParams->searchLength;
if (comprParams->targetLength) zparams.cParams.targetLength = comprParams->targetLength;
if (comprParams->strategy) zparams.cParams.strategy = comprParams->strategy;
cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dm_auto, zparams.cParams, cmem);
if (cdict==NULL) EXM_THROW(1, "ZSTD_createCDict_advanced() allocation failure");
#endif
do { do {
U32 blockNb; U32 blockNb;
for (blockNb=0; blockNb<nbBlocks; blockNb++) { for (blockNb=0; blockNb<nbBlocks; blockNb++) {
#if 0 /* direct compression function, for occasional comparison */ size_t rSize;
ZSTD_parameters const params = ZSTD_getParams(cLevel, blockTable[blockNb].srcSize, dictBufferSize); #ifdef ZSTD_NEWAPI
blockTable[blockNb].cSize = ZSTD_compress_advanced(ctx, ZSTD_outBuffer out = { blockTable[blockNb].cPtr, blockTable[blockNb].cRoom, 0 };
blockTable[blockNb].cPtr, blockTable[blockNb].cRoom, ZSTD_inBuffer in = { blockTable[blockNb].srcPtr, blockTable[blockNb].srcSize, 0 };
blockTable[blockNb].srcPtr, blockTable[blockNb].srcSize, size_t cError = 1;
dictBuffer, dictBufferSize, while (cError) {
params); cError = ZSTD_compress_generic(ctx,
#else
size_t moreToFlush = 1;
ZSTD_outBuffer out;
ZSTD_inBuffer in;
in.src = blockTable[blockNb].srcPtr;
in.size = blockTable[blockNb].srcSize;
in.pos = 0;
out.dst = blockTable[blockNb].cPtr;
out.size = blockTable[blockNb].cRoom;
out.pos = 0;
while (moreToFlush) {
moreToFlush = ZSTD_compress_generic(ctx,
&out, &in, ZSTD_e_end); &out, &in, ZSTD_e_end);
if (ZSTD_isError(moreToFlush)) if (ZSTD_isError(cError))
EXM_THROW(1, "ZSTD_compress_generic() error : %s", EXM_THROW(1, "ZSTD_compress_generic() error : %s",
ZSTD_getErrorName(moreToFlush)); ZSTD_getErrorName(cError));
} }
blockTable[blockNb].cSize = out.pos; rSize = out.pos;
#endif #else /* ! ZSTD_NEWAPI */
if (dictBufferSize) {
rSize = ZSTD_compress_usingCDict(ctx,
blockTable[blockNb].cPtr, blockTable[blockNb].cRoom,
blockTable[blockNb].srcPtr,blockTable[blockNb].srcSize,
cdict);
} else {
# ifdef ZSTD_MULTITHREAD /* note : limitation : MT single-pass does not support compression with dictionary */
rSize = ZSTDMT_compressCCtx(mtctx,
blockTable[blockNb].cPtr, blockTable[blockNb].cRoom,
blockTable[blockNb].srcPtr,blockTable[blockNb].srcSize,
cLevel);
# else
rSize = ZSTD_compress_advanced (ctx,
blockTable[blockNb].cPtr, blockTable[blockNb].cRoom,
blockTable[blockNb].srcPtr,blockTable[blockNb].srcSize,
NULL, 0, zparams);
# endif
}
if (ZSTD_isError(rSize))
EXM_THROW(1, "ZSTD_compress_usingCDict() failed : %s",
ZSTD_getErrorName(rSize));
#endif /* ZSTD_NEWAPI */
blockTable[blockNb].cSize = rSize;
} }
nbLoops++; nbLoops++;
} while (UTIL_clockSpanMicro(clockStart) < clockLoop); } while (UTIL_clockSpanMicro(clockStart) < clockLoop);
{ U64 const loopDuration = UTIL_clockSpanMicro(clockStart); ZSTD_freeCDict(cdict);
if (loopDuration < fastestC*nbLoops) { U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart);
fastestC = loopDuration / nbLoops; if (clockSpanMicro < fastestC*nbLoops) fastestC = clockSpanMicro / nbLoops;
totalCTime += loopDuration; totalCTime += clockSpanMicro;
cCompleted = (totalCTime >= maxTime); /* end compression tests */ cCompleted = (totalCTime >= maxTime);
} } } }
cSize = 0; cSize = 0;
{ U32 blockNb; for (blockNb=0; blockNb<nbBlocks; blockNb++) cSize += blockTable[blockNb].cSize; } { U32 blockNb; for (blockNb=0; blockNb<nbBlocks; blockNb++) cSize += blockTable[blockNb].cSize; }
ratio = (double)srcSize / (double)cSize; ratio = (double)srcSize / (double)cSize;
markNb = (markNb+1) % NB_MARKS; markNb = (markNb+1) % NB_MARKS;
{ int const ratioAccuracy = (ratio < 10.) ? 3 : 2; DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.3f),%6.1f MB/s\r",
double const compressionSpeed = (double)srcSize / fastestC; marks[markNb], displayName, (U32)srcSize, (U32)cSize, ratio,
int const cSpeedAccuracy = (compressionSpeed < 10.) ? 2 : 1; (double)srcSize / fastestC );
DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s\r",
marks[markNb], displayName, (U32)srcSize, (U32)cSize,
ratioAccuracy, ratio,
cSpeedAccuracy, compressionSpeed );
}
} else { /* g_decodeOnly */ } else { /* g_decodeOnly */
memcpy(compressedBuffer, srcBuffer, loadedCompressedSize); memcpy(compressedBuffer, srcBuffer, loadedCompressedSize);
} }
#if 0 /* disable decompression test */ #if 0 /* disable decompression test */
dCompleted=1; dCompleted=1;
(void)totalDTime; (void)fastestD; (void)crcOrig; /* unused when decompression disabled */ (void)totalDTime; (void)fastestD; (void)crcOrig; /* unused when decompression disabled */
#else #else
/* Decompression */ /* Decompression */
if (!dCompleted) memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */ if (!dCompleted) memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */
@@ -400,24 +413,17 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
nbLoops++; nbLoops++;
} while (UTIL_clockSpanMicro(clockStart) < clockLoop); } while (UTIL_clockSpanMicro(clockStart) < clockLoop);
ZSTD_freeDDict(ddict); ZSTD_freeDDict(ddict);
{ U64 const loopDuration = UTIL_clockSpanMicro(clockStart); { U64 const clockSpanMicro = UTIL_clockSpanMicro(clockStart);
if (loopDuration < fastestD*nbLoops) if (clockSpanMicro < fastestD*nbLoops) fastestD = clockSpanMicro / nbLoops;
fastestD = loopDuration / nbLoops; totalDTime += clockSpanMicro;
totalDTime += loopDuration;
dCompleted = (totalDTime >= maxTime); dCompleted = (totalDTime >= maxTime);
} } } }
markNb = (markNb+1) % NB_MARKS; markNb = (markNb+1) % NB_MARKS;
{ int const ratioAccuracy = (ratio < 10.) ? 3 : 2; DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.3f),%6.1f MB/s ,%6.1f MB/s\r",
double const compressionSpeed = (double)srcSize / fastestC; marks[markNb], displayName, (U32)srcSize, (U32)cSize, ratio,
int const cSpeedAccuracy = (compressionSpeed < 10.) ? 2 : 1; (double)srcSize / fastestC,
double const decompressionSpeed = (double)srcSize / fastestD; (double)srcSize / fastestD );
DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s ,%6.1f MB/s \r",
marks[markNb], displayName, (U32)srcSize, (U32)cSize,
ratioAccuracy, ratio,
cSpeedAccuracy, compressionSpeed,
decompressionSpeed);
}
/* CRC Checking */ /* CRC Checking */
{ U64 const crcCheck = XXH64(resultBuffer, srcSize, 0); { U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);
@@ -438,12 +444,10 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
DISPLAY("(sample %u, block %u, pos %u) \n", segNb, bNb, pos); DISPLAY("(sample %u, block %u, pos %u) \n", segNb, bNb, pos);
if (u>5) { if (u>5) {
int n; int n;
DISPLAY("origin: ");
for (n=-5; n<0; n++) DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]); for (n=-5; n<0; n++) DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]);
DISPLAY(" :%02X: ", ((const BYTE*)srcBuffer)[u]); DISPLAY(" :%02X: ", ((const BYTE*)srcBuffer)[u]);
for (n=1; n<3; n++) DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]); for (n=1; n<3; n++) DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]);
DISPLAY(" \n"); DISPLAY(" \n");
DISPLAY("decode: ");
for (n=-5; n<0; n++) DISPLAY("%02X ", ((const BYTE*)resultBuffer)[u+n]); for (n=-5; n<0; n++) DISPLAY("%02X ", ((const BYTE*)resultBuffer)[u+n]);
DISPLAY(" :%02X: ", ((const BYTE*)resultBuffer)[u]); DISPLAY(" :%02X: ", ((const BYTE*)resultBuffer)[u]);
for (n=1; n<3; n++) DISPLAY("%02X ", ((const BYTE*)resultBuffer)[u+n]); for (n=1; n<3; n++) DISPLAY("%02X ", ((const BYTE*)resultBuffer)[u+n]);
@@ -459,7 +463,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
#endif #endif
} /* for (testNb = 1; testNb <= (g_nbSeconds + !g_nbSeconds); testNb++) */ } /* for (testNb = 1; testNb <= (g_nbSeconds + !g_nbSeconds); testNb++) */
if (g_displayLevel == 1) { /* hidden display mode -q, used by python speed benchmark */ if (g_displayLevel == 1) {
double cSpeed = (double)srcSize / fastestC; double cSpeed = (double)srcSize / fastestC;
double dSpeed = (double)srcSize / fastestD; double dSpeed = (double)srcSize / fastestD;
if (g_additionalParam) if (g_additionalParam)
@@ -474,6 +478,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize,
free(blockTable); free(blockTable);
free(compressedBuffer); free(compressedBuffer);
free(resultBuffer); free(resultBuffer);
ZSTDMT_freeCCtx(mtctx);
ZSTD_freeCCtx(ctx); ZSTD_freeCCtx(ctx);
ZSTD_freeDCtx(dctx); ZSTD_freeDCtx(dctx);
return 0; return 0;
@@ -498,11 +503,11 @@ static size_t BMK_findMaxMem(U64 requiredMem)
return (size_t)(requiredMem); return (size_t)(requiredMem);
} }
static void BMK_benchCLevel(const void* srcBuffer, size_t benchedSize, static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize,
const char* displayName, int cLevel, int cLevelLast, const char* displayName, int cLevel, int cLevelLast,
const size_t* fileSizes, unsigned nbFiles, const size_t* fileSizes, unsigned nbFiles,
const void* dictBuffer, size_t dictBufferSize, const void* dictBuffer, size_t dictBufferSize,
const ZSTD_compressionParameters* const compressionParams) ZSTD_compressionParameters *compressionParams, int setRealTimePrio)
{ {
int l; int l;
@@ -510,8 +515,8 @@ static void BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
if (!pch) pch = strrchr(displayName, '/'); /* Linux */ if (!pch) pch = strrchr(displayName, '/'); /* Linux */
if (pch) displayName = pch+1; if (pch) displayName = pch+1;
if (g_realTime) { if (setRealTimePrio) {
DISPLAYLEVEL(2, "Note : switching to real-time priority \n"); DISPLAYLEVEL(2, "Note : switching to a real-time priority \n");
SET_REALTIME_PRIORITY; SET_REALTIME_PRIORITY;
} }
@@ -534,7 +539,7 @@ static void BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
At most, fills `buffer` entirely */ At most, fills `buffer` entirely */
static void BMK_loadFiles(void* buffer, size_t bufferSize, static void BMK_loadFiles(void* buffer, size_t bufferSize,
size_t* fileSizes, size_t* fileSizes,
const char* const * const fileNamesTable, unsigned nbFiles) const char** fileNamesTable, unsigned nbFiles)
{ {
size_t pos = 0, totalSize = 0; size_t pos = 0, totalSize = 0;
unsigned n; unsigned n;
@@ -546,11 +551,6 @@ static void BMK_loadFiles(void* buffer, size_t bufferSize,
fileSizes[n] = 0; fileSizes[n] = 0;
continue; continue;
} }
if (fileSize == UTIL_FILESIZE_UNKNOWN) {
DISPLAYLEVEL(2, "Cannot evaluate size of %s, ignoring ... \n", fileNamesTable[n]);
fileSizes[n] = 0;
continue;
}
f = fopen(fileNamesTable[n], "rb"); f = fopen(fileNamesTable[n], "rb");
if (f==NULL) EXM_THROW(10, "impossible to open file %s", fileNamesTable[n]); if (f==NULL) EXM_THROW(10, "impossible to open file %s", fileNamesTable[n]);
DISPLAYUPDATE(2, "Loading %s... \r", fileNamesTable[n]); DISPLAYUPDATE(2, "Loading %s... \r", fileNamesTable[n]);
@@ -566,30 +566,26 @@ static void BMK_loadFiles(void* buffer, size_t bufferSize,
if (totalSize == 0) EXM_THROW(12, "no data to bench"); if (totalSize == 0) EXM_THROW(12, "no data to bench");
} }
static void BMK_benchFileTable(const char* const * const fileNamesTable, unsigned const nbFiles, static void BMK_benchFileTable(const char** fileNamesTable, unsigned nbFiles, const char* dictFileName, int cLevel,
const char* const dictFileName, int cLevelLast, ZSTD_compressionParameters *compressionParams, int setRealTimePrio)
int const cLevel, int const cLevelLast,
const ZSTD_compressionParameters* const compressionParams)
{ {
void* srcBuffer; void* srcBuffer;
size_t benchedSize; size_t benchedSize;
void* dictBuffer = NULL; void* dictBuffer = NULL;
size_t dictBufferSize = 0; size_t dictBufferSize = 0;
size_t* const fileSizes = (size_t*)malloc(nbFiles * sizeof(size_t)); size_t* fileSizes = (size_t*)malloc(nbFiles * sizeof(size_t));
U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles); U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
char mfName[20] = {0};
if (!fileSizes) EXM_THROW(12, "not enough memory for fileSizes"); if (!fileSizes) EXM_THROW(12, "not enough memory for fileSizes");
/* Load dictionary */ /* Load dictionary */
if (dictFileName != NULL) { if (dictFileName != NULL) {
U64 const dictFileSize = UTIL_getFileSize(dictFileName); U64 dictFileSize = UTIL_getFileSize(dictFileName);
if (dictFileSize > 64 MB) if (dictFileSize > 64 MB) EXM_THROW(10, "dictionary file %s too large", dictFileName);
EXM_THROW(10, "dictionary file %s too large", dictFileName);
dictBufferSize = (size_t)dictFileSize; dictBufferSize = (size_t)dictFileSize;
dictBuffer = malloc(dictBufferSize); dictBuffer = malloc(dictBufferSize);
if (dictBuffer==NULL) if (dictBuffer==NULL) EXM_THROW(11, "not enough memory for dictionary (%u bytes)", (U32)dictBufferSize);
EXM_THROW(11, "not enough memory for dictionary (%u bytes)",
(U32)dictBufferSize);
BMK_loadFiles(dictBuffer, dictBufferSize, fileSizes, &dictFileName, 1); BMK_loadFiles(dictBuffer, dictBufferSize, fileSizes, &dictFileName, 1);
} }
@@ -605,26 +601,13 @@ static void BMK_benchFileTable(const char* const * const fileNamesTable, unsigne
BMK_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles); BMK_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles);
/* Bench */ /* Bench */
if (g_separateFiles) { snprintf (mfName, sizeof(mfName), " %u files", nbFiles);
const BYTE* srcPtr = (const BYTE*)srcBuffer; { const char* displayName = (nbFiles > 1) ? mfName : fileNamesTable[0];
U32 fileNb; BMK_benchCLevel(srcBuffer, benchedSize,
for (fileNb=0; fileNb<nbFiles; fileNb++) { displayName, cLevel, cLevelLast,
size_t const fileSize = fileSizes[fileNb]; fileSizes, nbFiles,
BMK_benchCLevel(srcPtr, fileSize, dictBuffer, dictBufferSize, compressionParams, setRealTimePrio);
fileNamesTable[fileNb], cLevel, cLevelLast, }
fileSizes+fileNb, 1,
dictBuffer, dictBufferSize, compressionParams);
srcPtr += fileSize;
}
} else {
char mfName[20] = {0};
snprintf (mfName, sizeof(mfName), " %u files", nbFiles);
{ const char* const displayName = (nbFiles > 1) ? mfName : fileNamesTable[0];
BMK_benchCLevel(srcBuffer, benchedSize,
displayName, cLevel, cLevelLast,
fileSizes, nbFiles,
dictBuffer, dictBufferSize, compressionParams);
} }
/* clean up */ /* clean up */
free(srcBuffer); free(srcBuffer);
@@ -633,7 +616,7 @@ static void BMK_benchFileTable(const char* const * const fileNamesTable, unsigne
} }
static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility, const ZSTD_compressionParameters* compressionParams) static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility, ZSTD_compressionParameters* compressionParams, int setRealTimePrio)
{ {
char name[20] = {0}; char name[20] = {0};
size_t benchedSize = 10000000; size_t benchedSize = 10000000;
@@ -647,17 +630,15 @@ static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility
/* Bench */ /* Bench */
snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100)); snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100));
BMK_benchCLevel(srcBuffer, benchedSize, name, cLevel, cLevelLast, &benchedSize, 1, NULL, 0, compressionParams); BMK_benchCLevel(srcBuffer, benchedSize, name, cLevel, cLevelLast, &benchedSize, 1, NULL, 0, compressionParams, setRealTimePrio);
/* clean up */ /* clean up */
free(srcBuffer); free(srcBuffer);
} }
int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles, int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles, const char* dictFileName,
const char* dictFileName, int cLevel, int cLevelLast, ZSTD_compressionParameters* compressionParams, int setRealTimePrio)
int cLevel, int cLevelLast,
const ZSTD_compressionParameters* compressionParams)
{ {
double const compressibility = (double)g_compressibilityDefault / 100; double const compressibility = (double)g_compressibilityDefault / 100;
@@ -665,12 +646,11 @@ int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles,
if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel(); if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel();
if (cLevelLast > ZSTD_maxCLevel()) cLevelLast = ZSTD_maxCLevel(); if (cLevelLast > ZSTD_maxCLevel()) cLevelLast = ZSTD_maxCLevel();
if (cLevelLast < cLevel) cLevelLast = cLevel; if (cLevelLast < cLevel) cLevelLast = cLevel;
if (cLevelLast > cLevel) if (cLevelLast > cLevel) DISPLAYLEVEL(2, "Benchmarking levels from %d to %d\n", cLevel, cLevelLast);
DISPLAYLEVEL(2, "Benchmarking levels from %d to %d\n", cLevel, cLevelLast);
if (nbFiles == 0) if (nbFiles == 0)
BMK_syntheticTest(cLevel, cLevelLast, compressibility, compressionParams); BMK_syntheticTest(cLevel, cLevelLast, compressibility, compressionParams, setRealTimePrio);
else else
BMK_benchFileTable(fileNamesTable, nbFiles, dictFileName, cLevel, cLevelLast, compressionParams); BMK_benchFileTable(fileNamesTable, nbFiles, dictFileName, cLevel, cLevelLast, compressionParams, setRealTimePrio);
return 0; return 0;
} }
+2 -4
View File
@@ -16,16 +16,14 @@
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressionParameters */ #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressionParameters */
#include "zstd.h" /* ZSTD_compressionParameters */ #include "zstd.h" /* ZSTD_compressionParameters */
int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles, const char* dictFileName, int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles,const char* dictFileName,
int cLevel, int cLevelLast, const ZSTD_compressionParameters* compressionParams); int cLevel, int cLevelLast, ZSTD_compressionParameters* compressionParams, int setRealTimePrio);
/* Set Parameters */ /* Set Parameters */
void BMK_setNbSeconds(unsigned nbLoops); void BMK_setNbSeconds(unsigned nbLoops);
void BMK_setBlockSize(size_t blockSize); void BMK_setBlockSize(size_t blockSize);
void BMK_setNbThreads(unsigned nbThreads); void BMK_setNbThreads(unsigned nbThreads);
void BMK_setRealTime(unsigned priority);
void BMK_setNotificationLevel(unsigned level); void BMK_setNotificationLevel(unsigned level);
void BMK_setSeparateFiles(unsigned separate);
void BMK_setAdditionalParam(int additionalParam); void BMK_setAdditionalParam(int additionalParam);
void BMK_setDecodeOnlyMode(unsigned decodeFlag); void BMK_setDecodeOnlyMode(unsigned decodeFlag);
void BMK_setLdmFlag(unsigned ldmFlag); void BMK_setLdmFlag(unsigned ldmFlag);
+12 -10
View File
@@ -26,6 +26,7 @@
#include <stdlib.h> /* malloc, free */ #include <stdlib.h> /* malloc, free */
#include <string.h> /* memset */ #include <string.h> /* memset */
#include <stdio.h> /* fprintf, fopen, ftello64 */ #include <stdio.h> /* fprintf, fopen, ftello64 */
#include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */
#include <errno.h> /* errno */ #include <errno.h> /* errno */
#include "mem.h" /* read */ #include "mem.h" /* read */
@@ -54,13 +55,15 @@ static const size_t g_maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((siz
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__) #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); } #define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
static const U64 g_refreshRate = SEC_TO_MICRO / 6; #define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER; if ((DIB_clockSpan(g_time) > refreshRate) || (displayLevel>=4)) \
{ g_time = clock(); DISPLAY(__VA_ARGS__); \
if (displayLevel>=4) fflush(stderr); } }
static const clock_t refreshRate = CLOCKS_PER_SEC * 2 / 10;
static clock_t g_time = 0;
static clock_t DIB_clockSpan(clock_t nPrevious) { return clock() - nPrevious; }
#define DISPLAYUPDATE(l, ...) { if (displayLevel>=l) { \
if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (displayLevel>=4)) \
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
if (displayLevel>=4) fflush(stderr); } } }
/*-************************************* /*-*************************************
* Exceptions * Exceptions
@@ -114,7 +117,7 @@ static unsigned DiB_loadFiles(void* buffer, size_t* bufferSizePtr,
for (fileIndex=0; fileIndex<nbFiles; fileIndex++) { for (fileIndex=0; fileIndex<nbFiles; fileIndex++) {
const char* const fileName = fileNamesTable[fileIndex]; const char* const fileName = fileNamesTable[fileIndex];
unsigned long long const fs64 = UTIL_getFileSize(fileName); unsigned long long const fs64 = UTIL_getFileSize(fileName);
unsigned long long remainingToLoad = (fs64 == UTIL_FILESIZE_UNKNOWN) ? 0 : fs64; unsigned long long remainingToLoad = fs64;
U32 const nbChunks = targetChunkSize ? (U32)((fs64 + (targetChunkSize-1)) / targetChunkSize) : 1; U32 const nbChunks = targetChunkSize ? (U32)((fs64 + (targetChunkSize-1)) / targetChunkSize) : 1;
U64 const chunkSize = targetChunkSize ? MIN(targetChunkSize, fs64) : fs64; U64 const chunkSize = targetChunkSize ? MIN(targetChunkSize, fs64) : fs64;
size_t const maxChunkSize = (size_t)MIN(chunkSize, SAMPLESIZE_MAX); size_t const maxChunkSize = (size_t)MIN(chunkSize, SAMPLESIZE_MAX);
@@ -242,9 +245,8 @@ static fileStats DiB_fileStats(const char** fileNamesTable, unsigned nbFiles, si
memset(&fs, 0, sizeof(fs)); memset(&fs, 0, sizeof(fs));
for (n=0; n<nbFiles; n++) { for (n=0; n<nbFiles; n++) {
U64 const fileSize = UTIL_getFileSize(fileNamesTable[n]); U64 const fileSize = UTIL_getFileSize(fileNamesTable[n]);
U64 const srcSize = (fileSize == UTIL_FILESIZE_UNKNOWN) ? 0 : fileSize; U32 const nbSamples = (U32)(chunkSize ? (fileSize + (chunkSize-1)) / chunkSize : 1);
U32 const nbSamples = (U32)(chunkSize ? (srcSize + (chunkSize-1)) / chunkSize : 1); U64 const chunkToLoad = chunkSize ? MIN(chunkSize, fileSize) : fileSize;
U64 const chunkToLoad = chunkSize ? MIN(chunkSize, srcSize) : srcSize;
size_t const cappedChunkSize = (size_t)MIN(chunkToLoad, SAMPLESIZE_MAX); size_t const cappedChunkSize = (size_t)MIN(chunkToLoad, SAMPLESIZE_MAX);
fs.totalSizeToLoad += cappedChunkSize * nbSamples; fs.totalSizeToLoad += cappedChunkSize * nbSamples;
fs.oneSampleTooLarge |= (chunkSize > 2*SAMPLESIZE_MAX); fs.oneSampleTooLarge |= (chunkSize > 2*SAMPLESIZE_MAX);
+278 -222
View File
@@ -25,10 +25,11 @@
* Includes * Includes
***************************************/ ***************************************/
#include "platform.h" /* Large Files support, SET_BINARY_MODE */ #include "platform.h" /* Large Files support, SET_BINARY_MODE */
#include "util.h" /* UTIL_getFileSize, UTIL_isRegularFile */ #include "util.h" /* UTIL_getFileSize */
#include <stdio.h> /* fprintf, fopen, fread, _fileno, stdin, stdout */ #include <stdio.h> /* fprintf, fopen, fread, _fileno, stdin, stdout */
#include <stdlib.h> /* malloc, free */ #include <stdlib.h> /* malloc, free */
#include <string.h> /* strcmp, strlen */ #include <string.h> /* strcmp, strlen */
#include <time.h> /* clock */
#include <errno.h> /* errno */ #include <errno.h> /* errno */
#if defined (_MSC_VER) #if defined (_MSC_VER)
@@ -39,9 +40,11 @@
#include "bitstream.h" #include "bitstream.h"
#include "mem.h" #include "mem.h"
#include "fileio.h" #include "fileio.h"
#include "util.h"
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */ #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */
#include "zstd.h" #include "zstd.h"
#ifdef ZSTD_MULTITHREAD
# include "zstdmt_compress.h"
#endif
#if defined(ZSTD_GZCOMPRESS) || defined(ZSTD_GZDECOMPRESS) #if defined(ZSTD_GZCOMPRESS) || defined(ZSTD_GZDECOMPRESS)
# include <zlib.h> # include <zlib.h>
# if !defined(z_const) # if !defined(z_const)
@@ -67,6 +70,18 @@
#define MB *(1<<20) #define MB *(1<<20)
#define GB *(1U<<30) #define GB *(1U<<30)
#define _1BIT 0x01
#define _2BITS 0x03
#define _3BITS 0x07
#define _4BITS 0x0F
#define _6BITS 0x3F
#define _8BITS 0xFF
#define BLOCKSIZE (128 KB)
#define ROLLBUFFERSIZE (BLOCKSIZE*8*64)
#define FIO_FRAMEHEADERSIZE 5 /* as a define, because needed to allocated table on stack */
#define DICTSIZE_MAX (32 MB) /* protection against large input (attack scenario) */ #define DICTSIZE_MAX (32 MB) /* protection against large input (attack scenario) */
#define FNSPACE 30 #define FNSPACE 30
@@ -81,13 +96,12 @@
static int g_displayLevel = 2; /* 0 : no display; 1: errors; 2: + result + interaction + warnings; 3: + progression; 4: + information */ static int g_displayLevel = 2; /* 0 : no display; 1: errors; 2: + result + interaction + warnings; 3: + progression; 4: + information */
void FIO_setNotificationLevel(unsigned level) { g_displayLevel=level; } void FIO_setNotificationLevel(unsigned level) { g_displayLevel=level; }
static const U64 g_refreshRate = SEC_TO_MICRO / 6;
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
#define DISPLAYUPDATE(l, ...) { if (g_displayLevel>=l) { \ #define DISPLAYUPDATE(l, ...) { if (g_displayLevel>=l) { \
if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \ if ((clock() - g_time > refreshRate) || (g_displayLevel>=4)) \
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \ { g_time = clock(); DISPLAY(__VA_ARGS__); \
if (g_displayLevel>=4) fflush(stderr); } } } if (g_displayLevel>=4) fflush(stderr); } } }
static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
static clock_t g_time = 0;
#undef MIN /* in case it would be already defined */ #undef MIN /* in case it would be already defined */
#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -108,23 +122,22 @@ static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
# define ZSTD_DEBUG 0 # define ZSTD_DEBUG 0
#endif #endif
#define DEBUGLOG(l,...) if (l<=ZSTD_DEBUG) DISPLAY(__VA_ARGS__); #define DEBUGLOG(l,...) if (l<=ZSTD_DEBUG) DISPLAY(__VA_ARGS__);
#define EXM_THROW(error, ...) \ #define EXM_THROW(error, ...) \
{ \ { \
DISPLAYLEVEL(1, "zstd: "); \ DISPLAYLEVEL(1, "zstd: "); \
DEBUGLOG(1, "Error defined at %s, line %i : \n", __FILE__, __LINE__); \ DEBUGLOG(1, "Error defined at %s, line %i : \n", __FILE__, __LINE__); \
DISPLAYLEVEL(1, "error %i : ", error); \ DISPLAYLEVEL(1, "error %i : ", error); \
DISPLAYLEVEL(1, __VA_ARGS__); \ DISPLAYLEVEL(1, __VA_ARGS__); \
DISPLAYLEVEL(1, " \n"); \ DISPLAYLEVEL(1, " \n"); \
exit(error); \ exit(error); \
} }
#define CHECK_V(v, f) \ #define CHECK(f) { \
v = f; \ size_t const err = f; \
if (ZSTD_isError(v)) { \ if (ZSTD_isError(err)) { \
DEBUGLOG(1, "%s \n", #f); \ DEBUGLOG(1, "%s \n", #f); \
EXM_THROW(11, "%s", ZSTD_getErrorName(v)); \ EXM_THROW(11, "%s", ZSTD_getErrorName(err)); \
} } }
#define CHECK(f) { size_t err; CHECK_V(err, f); }
/*-************************************ /*-************************************
@@ -143,21 +156,6 @@ static void INThandler(int sig)
DISPLAY("\n"); DISPLAY("\n");
exit(2); exit(2);
} }
static void addHandler(char const* dstFileName)
{
if (UTIL_isRegularFile(dstFileName)) {
g_artefact = dstFileName;
signal(SIGINT, INThandler);
} else {
g_artefact = NULL;
}
}
/* Idempotent */
static void clearHandler(void)
{
if (g_artefact) signal(SIGINT, SIG_DFL);
g_artefact = NULL;
}
/* ************************************************************ /* ************************************************************
@@ -220,6 +218,10 @@ static U32 g_blockSize = 0;
void FIO_setBlockSize(unsigned blockSize) { void FIO_setBlockSize(unsigned blockSize) {
if (blockSize && g_nbThreads==1) if (blockSize && g_nbThreads==1)
DISPLAYLEVEL(2, "Setting block size is useless in single-thread mode \n"); DISPLAYLEVEL(2, "Setting block size is useless in single-thread mode \n");
#ifdef ZSTD_MULTITHREAD
if (blockSize-1 < ZSTDMT_SECTION_SIZE_MIN-1) /* intentional underflow */
DISPLAYLEVEL(2, "Note : minimum block size is %u KB \n", (ZSTDMT_SECTION_SIZE_MIN>>10));
#endif
g_blockSize = blockSize; g_blockSize = blockSize;
} }
#define FIO_OVERLAP_LOG_NOTSET 9999 #define FIO_OVERLAP_LOG_NOTSET 9999
@@ -262,10 +264,6 @@ void FIO_setLdmHashEveryLog(unsigned ldmHashEveryLog) {
* @result : Unlink `fileName`, even if it's read-only */ * @result : Unlink `fileName`, even if it's read-only */
static int FIO_remove(const char* path) static int FIO_remove(const char* path)
{ {
if (!UTIL_isRegularFile(path)) {
DISPLAYLEVEL(2, "zstd: Refusing to remove non-regular file %s\n", path);
return 0;
}
#if defined(_WIN32) || defined(WIN32) #if defined(_WIN32) || defined(WIN32)
/* windows doesn't allow remove read-only files, /* windows doesn't allow remove read-only files,
* so try to make it writable first */ * so try to make it writable first */
@@ -275,92 +273,86 @@ static int FIO_remove(const char* path)
} }
/** FIO_openSrcFile() : /** FIO_openSrcFile() :
* condition : `srcFileName` must be non-NULL. * condition : `dstFileName` must be non-NULL.
* @result : FILE* to `srcFileName`, or NULL if it fails */ * @result : FILE* to `dstFileName`, or NULL if it fails */
static FILE* FIO_openSrcFile(const char* srcFileName) static FILE* FIO_openSrcFile(const char* srcFileName)
{ {
assert(srcFileName != NULL); FILE* f;
if (!strcmp (srcFileName, stdinmark)) { if (!strcmp (srcFileName, stdinmark)) {
DISPLAYLEVEL(4,"Using stdin for input\n"); DISPLAYLEVEL(4,"Using stdin for input\n");
f = stdin;
SET_BINARY_MODE(stdin); SET_BINARY_MODE(stdin);
return stdin; } else {
} if (!UTIL_isRegularFile(srcFileName)) {
DISPLAYLEVEL(1, "zstd: %s is not a regular file -- ignored \n",
if (!UTIL_isRegularFile(srcFileName)) { srcFileName);
DISPLAYLEVEL(1, "zstd: %s is not a regular file -- ignored \n", return NULL;
srcFileName); }
return NULL; f = fopen(srcFileName, "rb");
} if ( f==NULL )
{ FILE* const f = fopen(srcFileName, "rb");
if (f == NULL)
DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno)); DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno));
return f;
} }
return f;
} }
/** FIO_openDstFile() : /** FIO_openDstFile() :
* condition : `dstFileName` must be non-NULL. * condition : `dstFileName` must be non-NULL.
* @result : FILE* to `dstFileName`, or NULL if it fails */ * @result : FILE* to `dstFileName`, or NULL if it fails */
static FILE* FIO_openDstFile(const char* dstFileName) static FILE* FIO_openDstFile(const char* dstFileName)
{ {
assert(dstFileName != NULL); FILE* f;
if (!strcmp (dstFileName, stdoutmark)) { if (!strcmp (dstFileName, stdoutmark)) {
DISPLAYLEVEL(4,"Using stdout for output\n"); DISPLAYLEVEL(4,"Using stdout for output\n");
f = stdout;
SET_BINARY_MODE(stdout); SET_BINARY_MODE(stdout);
if (g_sparseFileSupport==1) { if (g_sparseFileSupport==1) {
g_sparseFileSupport = 0; g_sparseFileSupport = 0;
DISPLAYLEVEL(4, "Sparse File Support is automatically disabled on stdout ; try --sparse \n"); DISPLAYLEVEL(4, "Sparse File Support is automatically disabled on stdout ; try --sparse \n");
} }
return stdout; } else {
} if (g_sparseFileSupport == 1) {
g_sparseFileSupport = ZSTD_SPARSE_DEFAULT;
if (g_sparseFileSupport == 1) {
g_sparseFileSupport = ZSTD_SPARSE_DEFAULT;
}
if (UTIL_isRegularFile(dstFileName)) {
FILE* fCheck;
if (!strcmp(dstFileName, nulmark)) {
EXM_THROW(40, "%s is unexpectedly a regular file", dstFileName);
} }
/* Check if destination file already exists */ if (strcmp (dstFileName, nulmark)) {
fCheck = fopen( dstFileName, "rb" ); /* Check if destination file already exists */
if (fCheck != NULL) { /* dst file exists, authorization prompt */ f = fopen( dstFileName, "rb" );
fclose(fCheck); if (f != 0) { /* dst file exists, prompt for overwrite authorization */
if (!g_overwrite) { fclose(f);
if (g_displayLevel <= 1) { if (!g_overwrite) {
/* No interaction possible */ if (g_displayLevel <= 1) {
DISPLAY("zstd: %s already exists; not overwritten \n", /* No interaction possible */
dstFileName); DISPLAY("zstd: %s already exists; not overwritten \n",
return NULL; dstFileName);
}
DISPLAY("zstd: %s already exists; overwrite (y/N) ? ",
dstFileName);
{ int ch = getchar();
if ((ch!='Y') && (ch!='y')) {
DISPLAY(" not overwritten \n");
return NULL; return NULL;
} }
/* flush rest of input line */ DISPLAY("zstd: %s already exists; do you wish to overwrite (y/N) ? ",
while ((ch!=EOF) && (ch!='\n')) ch = getchar(); dstFileName);
} } { int ch = getchar();
/* need to unlink */ if ((ch!='Y') && (ch!='y')) {
FIO_remove(dstFileName); DISPLAY(" not overwritten \n");
} } return NULL;
}
{ FILE* const f = fopen( dstFileName, "wb" ); /* flush rest of input line */
if (f == NULL) while ((ch!=EOF) && (ch!='\n')) ch = getchar();
DISPLAYLEVEL(1, "zstd: %s: %s\n", dstFileName, strerror(errno)); } }
return f; /* need to unlink */
FIO_remove(dstFileName);
} }
f = fopen( dstFileName, "wb" );
if (f==NULL) DISPLAYLEVEL(1, "zstd: %s: %s\n", dstFileName, strerror(errno));
} }
return f;
} }
/*! FIO_createDictBuffer() : /*! FIO_createDictBuffer() :
* creates a buffer, pointed by `*bufferPtr`, * creates a buffer, pointed by `*bufferPtr`,
* loads `filename` content into it, up to DICTSIZE_MAX bytes. * loads `filename` content into it, up to DICTSIZE_MAX bytes.
* @return : loaded size * @return : loaded size
* if fileName==NULL, returns 0 and a NULL pointer * if fileName==NULL, returns 0 and a NULL pointer
*/ */
static size_t FIO_createDictBuffer(void** bufferPtr, const char* fileName) static size_t FIO_createDictBuffer(void** bufferPtr, const char* fileName)
@@ -368,13 +360,12 @@ static size_t FIO_createDictBuffer(void** bufferPtr, const char* fileName)
FILE* fileHandle; FILE* fileHandle;
U64 fileSize; U64 fileSize;
assert(bufferPtr != NULL);
*bufferPtr = NULL; *bufferPtr = NULL;
if (fileName == NULL) return 0; if (fileName == NULL) return 0;
DISPLAYLEVEL(4,"Loading %s as dictionary \n", fileName); DISPLAYLEVEL(4,"Loading %s as dictionary \n", fileName);
fileHandle = fopen(fileName, "rb"); fileHandle = fopen(fileName, "rb");
if (fileHandle==NULL) EXM_THROW(31, "%s: %s", fileName, strerror(errno)); if (fileHandle==0) EXM_THROW(31, "%s: %s", fileName, strerror(errno));
fileSize = UTIL_getFileSize(fileName); fileSize = UTIL_getFileSize(fileName);
if (fileSize > DICTSIZE_MAX) { if (fileSize > DICTSIZE_MAX) {
EXM_THROW(32, "Dictionary file %s is too large (> %u MB)", EXM_THROW(32, "Dictionary file %s is too large (> %u MB)",
@@ -402,7 +393,11 @@ typedef struct {
size_t srcBufferSize; size_t srcBufferSize;
void* dstBuffer; void* dstBuffer;
size_t dstBufferSize; size_t dstBufferSize;
#if !defined(ZSTD_NEWAPI) && defined(ZSTD_MULTITHREAD)
ZSTDMT_CCtx* cctx;
#else
ZSTD_CStream* cctx; ZSTD_CStream* cctx;
#endif
} cRess_t; } cRess_t;
static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
@@ -411,9 +406,24 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
cRess_t ress; cRess_t ress;
memset(&ress, 0, sizeof(ress)); memset(&ress, 0, sizeof(ress));
#ifdef ZSTD_NEWAPI
ress.cctx = ZSTD_createCCtx(); ress.cctx = ZSTD_createCCtx();
if (ress.cctx == NULL) if (ress.cctx == NULL)
EXM_THROW(30, "allocation error : can't create ZSTD_CCtx"); EXM_THROW(30, "allocation error : can't create ZSTD_CCtx");
#elif defined(ZSTD_MULTITHREAD)
ress.cctx = ZSTDMT_createCCtx(g_nbThreads);
if (ress.cctx == NULL)
EXM_THROW(30, "allocation error : can't create ZSTDMT_CCtx");
if ((cLevel==ZSTD_maxCLevel()) && (g_overlapLog==FIO_OVERLAP_LOG_NOTSET))
/* use complete window for overlap */
ZSTDMT_setMTCtxParameter(ress.cctx, ZSTDMT_p_overlapSectionLog, 9);
if (g_overlapLog != FIO_OVERLAP_LOG_NOTSET)
ZSTDMT_setMTCtxParameter(ress.cctx, ZSTDMT_p_overlapSectionLog, g_overlapLog);
#else
ress.cctx = ZSTD_createCStream();
if (ress.cctx == NULL)
EXM_THROW(30, "allocation error : can't create ZSTD_CStream");
#endif
ress.srcBufferSize = ZSTD_CStreamInSize(); ress.srcBufferSize = ZSTD_CStreamInSize();
ress.srcBuffer = malloc(ress.srcBufferSize); ress.srcBuffer = malloc(ress.srcBufferSize);
ress.dstBufferSize = ZSTD_CStreamOutSize(); ress.dstBufferSize = ZSTD_CStreamOutSize();
@@ -421,44 +431,72 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel,
if (!ress.srcBuffer || !ress.dstBuffer) if (!ress.srcBuffer || !ress.dstBuffer)
EXM_THROW(31, "allocation error : not enough memory"); EXM_THROW(31, "allocation error : not enough memory");
/* Advances parameters, including dictionary */ /* dictionary */
{ void* dictBuffer; { void* dictBuffer;
size_t const dictBuffSize = FIO_createDictBuffer(&dictBuffer, dictFileName); /* works with dictFileName==NULL */ size_t const dictBuffSize = FIO_createDictBuffer(&dictBuffer, dictFileName); /* works with dictFileName==NULL */
if (dictFileName && (dictBuffer==NULL)) if (dictFileName && (dictBuffer==NULL))
EXM_THROW(32, "allocation error : can't create dictBuffer"); EXM_THROW(32, "allocation error : can't create dictBuffer");
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_contentSizeFlag, 1) ); /* always enable content size when available (note: supposed to be default) */ #ifdef ZSTD_NEWAPI
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_dictIDFlag, g_dictIDFlag) ); { /* frame parameters */
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_checksumFlag, g_checksumFlag) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_dictIDFlag, g_dictIDFlag) );
/* compression level */ CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_checksumFlag, g_checksumFlag) );
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionLevel, cLevel) ); (void)srcSize;
/* long distance matching */ /* compression level */
CHECK( ZSTD_CCtx_setParameter( CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionLevel, cLevel) );
ress.cctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag) ); /* long distance matching */
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashLog, g_ldmHashLog) ); CHECK( ZSTD_CCtx_setParameter(
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch) ); ress.cctx, ZSTD_p_enableLongDistanceMatching, g_ldmFlag) );
if (g_ldmBucketSizeLog != FIO_LDM_PARAM_NOTSET) { CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashLog, g_ldmHashLog) );
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmBucketSizeLog, g_ldmBucketSizeLog) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmMinMatch, g_ldmMinMatch) );
if (g_ldmBucketSizeLog != FIO_LDM_PARAM_NOTSET) {
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmBucketSizeLog, g_ldmBucketSizeLog) );
}
if (g_ldmHashEveryLog != FIO_LDM_PARAM_NOTSET) {
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashEveryLog, g_ldmHashEveryLog) );
}
/* compression parameters */
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_windowLog, comprParams->windowLog) );
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_chainLog, comprParams->chainLog) );
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_hashLog, comprParams->hashLog) );
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_searchLog, comprParams->searchLog) );
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_minMatch, comprParams->searchLength) );
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_targetLength, comprParams->targetLength) );
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionStrategy, (U32)comprParams->strategy) );
/* multi-threading */
DISPLAYLEVEL(5,"set nb threads = %u \n", g_nbThreads);
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) );
/* dictionary */
CHECK( ZSTD_CCtx_loadDictionary(ress.cctx, dictBuffer, dictBuffSize) );
} }
if (g_ldmHashEveryLog != FIO_LDM_PARAM_NOTSET) { #elif defined(ZSTD_MULTITHREAD)
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_ldmHashEveryLog, g_ldmHashEveryLog) ); { ZSTD_parameters params = ZSTD_getParams(cLevel, srcSize, dictBuffSize);
params.fParams.checksumFlag = g_checksumFlag;
params.fParams.noDictIDFlag = !g_dictIDFlag;
if (comprParams->windowLog) params.cParams.windowLog = comprParams->windowLog;
if (comprParams->chainLog) params.cParams.chainLog = comprParams->chainLog;
if (comprParams->hashLog) params.cParams.hashLog = comprParams->hashLog;
if (comprParams->searchLog) params.cParams.searchLog = comprParams->searchLog;
if (comprParams->searchLength) params.cParams.searchLength = comprParams->searchLength;
if (comprParams->targetLength) params.cParams.targetLength = comprParams->targetLength;
if (comprParams->strategy) params.cParams.strategy = (ZSTD_strategy) comprParams->strategy;
CHECK( ZSTDMT_initCStream_advanced(ress.cctx, dictBuffer, dictBuffSize, params, srcSize) );
ZSTDMT_setMTCtxParameter(ress.cctx, ZSTDMT_p_sectionSize, g_blockSize);
} }
/* compression parameters */ #else
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_windowLog, comprParams->windowLog) ); { ZSTD_parameters params = ZSTD_getParams(cLevel, srcSize, dictBuffSize);
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_chainLog, comprParams->chainLog) ); params.fParams.checksumFlag = g_checksumFlag;
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_hashLog, comprParams->hashLog) ); params.fParams.noDictIDFlag = !g_dictIDFlag;
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_searchLog, comprParams->searchLog) ); if (comprParams->windowLog) params.cParams.windowLog = comprParams->windowLog;
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_minMatch, comprParams->searchLength) ); if (comprParams->chainLog) params.cParams.chainLog = comprParams->chainLog;
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_targetLength, comprParams->targetLength) ); if (comprParams->hashLog) params.cParams.hashLog = comprParams->hashLog;
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_compressionStrategy, (U32)comprParams->strategy) ); if (comprParams->searchLog) params.cParams.searchLog = comprParams->searchLog;
/* multi-threading */ if (comprParams->searchLength) params.cParams.searchLength = comprParams->searchLength;
DISPLAYLEVEL(5,"set nb threads = %u \n", g_nbThreads); if (comprParams->targetLength) params.cParams.targetLength = comprParams->targetLength;
CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_p_nbThreads, g_nbThreads) ); if (comprParams->strategy) params.cParams.strategy = (ZSTD_strategy) comprParams->strategy;
/* dictionary */ CHECK( ZSTD_initCStream_advanced(ress.cctx, dictBuffer, dictBuffSize, params, srcSize) );
CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, srcSize) ); /* just for dictionary loading, for compression parameters adaptation */ }
CHECK( ZSTD_CCtx_loadDictionary(ress.cctx, dictBuffer, dictBuffSize) ); #endif
CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, ZSTD_CONTENTSIZE_UNKNOWN) ); /* reset */
free(dictBuffer); free(dictBuffer);
} }
@@ -469,7 +507,11 @@ static void FIO_freeCResources(cRess_t ress)
{ {
free(ress.srcBuffer); free(ress.srcBuffer);
free(ress.dstBuffer); free(ress.dstBuffer);
#if !defined(ZSTD_NEWAPI) && defined(ZSTD_MULTITHREAD)
ZSTDMT_freeCCtx(ress.cctx);
#else
ZSTD_freeCStream(ress.cctx); /* never fails */ ZSTD_freeCStream(ress.cctx); /* never fails */
#endif
} }
@@ -520,7 +562,7 @@ static unsigned long long FIO_compressGzFrame(cRess_t* ress,
strm.avail_out = (uInt)ress->dstBufferSize; strm.avail_out = (uInt)ress->dstBufferSize;
} }
} }
if (srcFileSize == UTIL_FILESIZE_UNKNOWN) if (!srcFileSize)
DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%%", DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%%",
(U32)(inFileSize>>20), (U32)(inFileSize>>20),
(double)outFileSize/inFileSize*100) (double)outFileSize/inFileSize*100)
@@ -607,7 +649,7 @@ static unsigned long long FIO_compressLzmaFrame(cRess_t* ress,
strm.next_out = (BYTE*)ress->dstBuffer; strm.next_out = (BYTE*)ress->dstBuffer;
strm.avail_out = ress->dstBufferSize; strm.avail_out = ress->dstBufferSize;
} } } }
if (srcFileSize == UTIL_FILESIZE_UNKNOWN) if (!srcFileSize)
DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%%", DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%%",
(U32)(inFileSize>>20), (U32)(inFileSize>>20),
(double)outFileSize/inFileSize*100) (double)outFileSize/inFileSize*100)
@@ -626,16 +668,11 @@ static unsigned long long FIO_compressLzmaFrame(cRess_t* ress,
#endif #endif
#ifdef ZSTD_LZ4COMPRESS #ifdef ZSTD_LZ4COMPRESS
#if LZ4_VERSION_NUMBER <= 10600
#define LZ4F_blockLinked blockLinked
#define LZ4F_max64KB max64KB
#endif
static int FIO_LZ4_GetBlockSize_FromBlockId (int id) { return (1 << (8 + (2 * id))); } static int FIO_LZ4_GetBlockSize_FromBlockId (int id) { return (1 << (8 + (2 * id))); }
static unsigned long long FIO_compressLz4Frame(cRess_t* ress, static unsigned long long FIO_compressLz4Frame(cRess_t* ress,
const char* srcFileName, U64 const srcFileSize, const char* srcFileName, U64 const srcFileSize,
int compressionLevel, U64* readsize) int compressionLevel, U64* readsize)
{ {
const size_t blockSize = FIO_LZ4_GetBlockSize_FromBlockId(LZ4F_max64KB);
unsigned long long inFileSize = 0, outFileSize = 0; unsigned long long inFileSize = 0, outFileSize = 0;
LZ4F_preferences_t prefs; LZ4F_preferences_t prefs;
@@ -647,26 +684,29 @@ static unsigned long long FIO_compressLz4Frame(cRess_t* ress,
memset(&prefs, 0, sizeof(prefs)); memset(&prefs, 0, sizeof(prefs));
assert(blockSize <= ress->srcBufferSize); #if LZ4_VERSION_NUMBER <= 10600
#define LZ4F_blockIndependent blockIndependent
#define LZ4F_max4MB max4MB
#endif
prefs.autoFlush = 1; prefs.autoFlush = 1;
prefs.compressionLevel = compressionLevel; prefs.compressionLevel = compressionLevel;
prefs.frameInfo.blockMode = LZ4F_blockLinked; prefs.frameInfo.blockMode = LZ4F_blockIndependent; /* stick to defaults for lz4 cli */
prefs.frameInfo.blockSizeID = LZ4F_max64KB; prefs.frameInfo.blockSizeID = LZ4F_max4MB;
prefs.frameInfo.contentChecksumFlag = (contentChecksum_t)g_checksumFlag; prefs.frameInfo.contentChecksumFlag = (contentChecksum_t)g_checksumFlag;
#if LZ4_VERSION_NUMBER >= 10600 #if LZ4_VERSION_NUMBER >= 10600
prefs.frameInfo.contentSize = (srcFileSize==UTIL_FILESIZE_UNKNOWN) ? 0 : srcFileSize; prefs.frameInfo.contentSize = srcFileSize;
#endif #endif
assert(LZ4F_compressBound(blockSize, &prefs) <= ress->dstBufferSize);
{ {
size_t blockSize = FIO_LZ4_GetBlockSize_FromBlockId(LZ4F_max4MB);
size_t readSize; size_t readSize;
size_t headerSize = LZ4F_compressBegin(ctx, ress->dstBuffer, ress->dstBufferSize, &prefs); size_t headerSize = LZ4F_compressBegin(ctx, ress->dstBuffer, ress->dstBufferSize, &prefs);
if (LZ4F_isError(headerSize)) if (LZ4F_isError(headerSize))
EXM_THROW(33, "File header generation failed : %s", EXM_THROW(33, "File header generation failed : %s",
LZ4F_getErrorName(headerSize)); LZ4F_getErrorName(headerSize));
if (fwrite(ress->dstBuffer, 1, headerSize, ress->dstFile) != headerSize) { size_t const sizeCheck = fwrite(ress->dstBuffer, 1, headerSize, ress->dstFile);
EXM_THROW(34, "Write error : cannot write header"); if (sizeCheck!=headerSize) EXM_THROW(34, "Write error : cannot write header"); }
outFileSize += headerSize; outFileSize += headerSize;
/* Read first block */ /* Read first block */
@@ -683,7 +723,7 @@ static unsigned long long FIO_compressLz4Frame(cRess_t* ress,
EXM_THROW(35, "zstd: %s: lz4 compression failed : %s", EXM_THROW(35, "zstd: %s: lz4 compression failed : %s",
srcFileName, LZ4F_getErrorName(outSize)); srcFileName, LZ4F_getErrorName(outSize));
outFileSize += outSize; outFileSize += outSize;
if (srcFileSize == UTIL_FILESIZE_UNKNOWN) if (!srcFileSize)
DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%%", DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%%",
(U32)(inFileSize>>20), (U32)(inFileSize>>20),
(double)outFileSize/inFileSize*100) (double)outFileSize/inFileSize*100)
@@ -734,7 +774,6 @@ static int FIO_compressFilename_internal(cRess_t ress,
U64 readsize = 0; U64 readsize = 0;
U64 compressedfilesize = 0; U64 compressedfilesize = 0;
U64 const fileSize = UTIL_getFileSize(srcFileName); U64 const fileSize = UTIL_getFileSize(srcFileName);
ZSTD_EndDirective directive = ZSTD_e_continue;
DISPLAYLEVEL(5, "%s: %u bytes \n", srcFileName, (U32)fileSize); DISPLAYLEVEL(5, "%s: %u bytes \n", srcFileName, (U32)fileSize);
switch (g_compressionType) { switch (g_compressionType) {
@@ -774,52 +813,83 @@ static int FIO_compressFilename_internal(cRess_t ress,
} }
/* init */ /* init */
if (fileSize != UTIL_FILESIZE_UNKNOWN) #ifdef ZSTD_NEWAPI
ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize); if (fileSize!=0) /* when src is stdin, fileSize==0, but is effectively unknown */
ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize); /* note : fileSize==0 means "empty" */
#elif defined(ZSTD_MULTITHREAD)
CHECK( ZSTDMT_resetCStream(ress.cctx, fileSize) ); /* note : fileSize==0 means "unknown" */
#else
CHECK( ZSTD_resetCStream(ress.cctx, fileSize) ); /* note : fileSize==0 means "unknown" */
#endif
/* Main compression loop */ /* Main compression loop */
do { while (1) {
size_t result;
/* Fill input Buffer */ /* Fill input Buffer */
size_t const inSize = fread(ress.srcBuffer, (size_t)1, ress.srcBufferSize, srcFile); size_t const inSize = fread(ress.srcBuffer, (size_t)1, ress.srcBufferSize, srcFile);
ZSTD_inBuffer inBuff = { ress.srcBuffer, inSize, 0 }; ZSTD_inBuffer inBuff = { ress.srcBuffer, inSize, 0 };
if (inSize==0) break;
readsize += inSize; readsize += inSize;
if (inSize == 0 || (fileSize != UTIL_FILESIZE_UNKNOWN && readsize == fileSize)) while (inBuff.pos != inBuff.size) {
directive = ZSTD_e_end;
result = 1;
while (inBuff.pos != inBuff.size || (directive == ZSTD_e_end && result != 0)) {
ZSTD_outBuffer outBuff = { ress.dstBuffer, ress.dstBufferSize, 0 }; ZSTD_outBuffer outBuff = { ress.dstBuffer, ress.dstBufferSize, 0 };
CHECK_V(result, ZSTD_compress_generic(ress.cctx, &outBuff, &inBuff, directive)); #ifdef ZSTD_NEWAPI
CHECK( ZSTD_compress_generic(ress.cctx,
&outBuff, &inBuff, ZSTD_e_continue) );
#elif defined(ZSTD_MULTITHREAD)
CHECK( ZSTDMT_compressStream(ress.cctx, &outBuff, &inBuff) );
#else
CHECK( ZSTD_compressStream(ress.cctx, &outBuff, &inBuff) );
#endif
/* Write compressed stream */ /* Write compressed stream */
DISPLAYLEVEL(6, "ZSTD_compress_generic,ZSTD_e_continue: generated %u bytes \n",
(U32)outBuff.pos);
if (outBuff.pos) { if (outBuff.pos) {
size_t const sizeCheck = fwrite(ress.dstBuffer, 1, outBuff.pos, dstFile); size_t const sizeCheck = fwrite(ress.dstBuffer, 1, outBuff.pos, dstFile);
if (sizeCheck!=outBuff.pos) if (sizeCheck!=outBuff.pos)
EXM_THROW(25, "Write error : cannot write compressed block into %s", dstFileName); EXM_THROW(25, "Write error : cannot write compressed block into %s", dstFileName);
compressedfilesize += outBuff.pos; compressedfilesize += outBuff.pos;
} } }
}
if (g_nbThreads > 1) { if (g_nbThreads > 1) {
if (fileSize == UTIL_FILESIZE_UNKNOWN) if (!fileSize)
DISPLAYUPDATE(2, "\rRead : %u MB", (U32)(readsize>>20)) DISPLAYUPDATE(2, "\rRead : %u MB", (U32)(readsize>>20))
else else
DISPLAYUPDATE(2, "\rRead : %u / %u MB", DISPLAYUPDATE(2, "\rRead : %u / %u MB",
(U32)(readsize>>20), (U32)(fileSize>>20)); (U32)(readsize>>20), (U32)(fileSize>>20));
} else { } else {
if (fileSize == UTIL_FILESIZE_UNKNOWN) if (!fileSize)
DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%%", DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%%",
(U32)(readsize>>20), (U32)(readsize>>20),
(double)compressedfilesize/readsize*100) (double)compressedfilesize/readsize*100)
else else
DISPLAYUPDATE(2, "\rRead : %u / %u MB ==> %.2f%%", DISPLAYUPDATE(2, "\rRead : %u / %u MB ==> %.2f%%",
(U32)(readsize>>20), (U32)(fileSize>>20), (U32)(readsize>>20), (U32)(fileSize>>20),
(double)compressedfilesize/readsize*100); (double)compressedfilesize/readsize*100);
} }
} while (directive != ZSTD_e_end); }
/* End of Frame */
{ size_t result = 1;
while (result != 0) {
ZSTD_outBuffer outBuff = { ress.dstBuffer, ress.dstBufferSize, 0 };
#ifdef ZSTD_NEWAPI
ZSTD_inBuffer inBuff = { NULL, 0, 0 };
result = ZSTD_compress_generic(ress.cctx,
&outBuff, &inBuff, ZSTD_e_end);
#elif defined(ZSTD_MULTITHREAD)
result = ZSTDMT_endStream(ress.cctx, &outBuff);
#else
result = ZSTD_endStream(ress.cctx, &outBuff);
#endif
if (ZSTD_isError(result)) {
EXM_THROW(26, "Compression error during frame end : %s",
ZSTD_getErrorName(result));
}
{ size_t const sizeCheck = fwrite(ress.dstBuffer, 1, outBuff.pos, dstFile);
if (sizeCheck!=outBuff.pos)
EXM_THROW(27, "Write error : cannot write frame end into %s", dstFileName);
}
compressedfilesize += outBuff.pos;
}
}
finish: finish:
/* Status */ /* Status */
@@ -857,10 +927,6 @@ static int FIO_compressFilename_srcFile(cRess_t ress,
fclose(ress.srcFile); fclose(ress.srcFile);
if (g_removeSrcFile /* --rm */ && !result && strcmp(srcFileName, stdinmark)) { if (g_removeSrcFile /* --rm */ && !result && strcmp(srcFileName, stdinmark)) {
/* We must clear the handler, since after this point calling it would
* delete both the source and destination files.
*/
clearHandler();
if (remove(srcFileName)) if (remove(srcFileName))
EXM_THROW(1, "zstd: %s: %s", srcFileName, strerror(errno)); EXM_THROW(1, "zstd: %s: %s", srcFileName, strerror(errno));
} }
@@ -883,16 +949,18 @@ static int FIO_compressFilename_dstFile(cRess_t ress,
ress.dstFile = FIO_openDstFile(dstFileName); ress.dstFile = FIO_openDstFile(dstFileName);
if (ress.dstFile==NULL) return 1; /* could not open dstFileName */ if (ress.dstFile==NULL) return 1; /* could not open dstFileName */
/* Must ony be added after FIO_openDstFile() succeeds.
* Otherwise we may delete the destination file if at already exists, and if (UTIL_isRegularFile(dstFileName)) {
* the user presses Ctrl-C when asked if they wish to overwrite. g_artefact = dstFileName;
*/ signal(SIGINT, INThandler);
addHandler(dstFileName); } else {
g_artefact = NULL;
}
if (strcmp (srcFileName, stdinmark) && UTIL_getFileStat(srcFileName, &statbuf)) if (strcmp (srcFileName, stdinmark) && UTIL_getFileStat(srcFileName, &statbuf))
stat_result = 1; stat_result = 1;
result = FIO_compressFilename_srcFile(ress, dstFileName, srcFileName, compressionLevel); result = FIO_compressFilename_srcFile(ress, dstFileName, srcFileName, compressionLevel);
clearHandler();
if (fclose(ress.dstFile)) { /* error closing dstFile */ if (fclose(ress.dstFile)) { /* error closing dstFile */
DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno)); DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno));
@@ -905,6 +973,8 @@ static int FIO_compressFilename_dstFile(cRess_t ress,
else if (strcmp (dstFileName, stdoutmark) && stat_result) else if (strcmp (dstFileName, stdoutmark) && stat_result)
UTIL_setFileStat(dstFileName, &statbuf); UTIL_setFileStat(dstFileName, &statbuf);
signal(SIGINT, SIG_DFL);
return result; return result;
} }
@@ -913,8 +983,7 @@ int FIO_compressFilename(const char* dstFileName, const char* srcFileName,
const char* dictFileName, int compressionLevel, ZSTD_compressionParameters* comprParams) const char* dictFileName, int compressionLevel, ZSTD_compressionParameters* comprParams)
{ {
clock_t const start = clock(); clock_t const start = clock();
U64 const fileSize = UTIL_getFileSize(srcFileName); U64 const srcSize = UTIL_getFileSize(srcFileName);
U64 const srcSize = (fileSize == UTIL_FILESIZE_UNKNOWN) ? ZSTD_CONTENTSIZE_UNKNOWN : fileSize;
cRess_t const ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, comprParams); cRess_t const ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, comprParams);
int const result = FIO_compressFilename_dstFile(ress, dstFileName, srcFileName, compressionLevel); int const result = FIO_compressFilename_dstFile(ress, dstFileName, srcFileName, compressionLevel);
@@ -928,7 +997,7 @@ int FIO_compressFilename(const char* dstFileName, const char* srcFileName,
int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFiles, int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFiles,
const char* outFileName, const char* suffix, const char* suffix,
const char* dictFileName, int compressionLevel, const char* dictFileName, int compressionLevel,
ZSTD_compressionParameters* comprParams) ZSTD_compressionParameters* comprParams)
{ {
@@ -936,23 +1005,22 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile
size_t dfnSize = FNSPACE; size_t dfnSize = FNSPACE;
char* dstFileName = (char*)malloc(FNSPACE); char* dstFileName = (char*)malloc(FNSPACE);
size_t const suffixSize = suffix ? strlen(suffix) : 0; size_t const suffixSize = suffix ? strlen(suffix) : 0;
U64 const firstFileSize = UTIL_getFileSize(inFileNamesTable[0]); U64 const srcSize = (nbFiles != 1) ? 0 : UTIL_getFileSize(inFileNamesTable[0]) ;
U64 const firstSrcSize = (firstFileSize == UTIL_FILESIZE_UNKNOWN) ? ZSTD_CONTENTSIZE_UNKNOWN : firstFileSize;
U64 const srcSize = (nbFiles != 1) ? ZSTD_CONTENTSIZE_UNKNOWN : firstSrcSize ;
cRess_t ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, comprParams); cRess_t ress = FIO_createCResources(dictFileName, compressionLevel, srcSize, comprParams);
/* init */ /* init */
if (dstFileName==NULL) if (dstFileName==NULL)
EXM_THROW(27, "FIO_compressMultipleFilenames : allocation error for dstFileName"); EXM_THROW(27, "FIO_compressMultipleFilenames : allocation error for dstFileName");
if (outFileName == NULL && suffix == NULL) if (suffix == NULL)
EXM_THROW(28, "FIO_compressMultipleFilenames : dst unknown"); /* should never happen */ EXM_THROW(28, "FIO_compressMultipleFilenames : dst unknown"); /* should never happen */
/* loop on each file */ /* loop on each file */
if (outFileName != NULL) { if (!strcmp(suffix, stdoutmark)) {
unsigned u; unsigned u;
ress.dstFile = FIO_openDstFile(outFileName); ress.dstFile = stdout;
SET_BINARY_MODE(stdout);
for (u=0; u<nbFiles; u++) for (u=0; u<nbFiles; u++)
missed_files += FIO_compressFilename_srcFile(ress, outFileName, inFileNamesTable[u], compressionLevel); missed_files += FIO_compressFilename_srcFile(ress, stdoutmark, inFileNamesTable[u], compressionLevel);
if (fclose(ress.dstFile)) if (fclose(ress.dstFile))
EXM_THROW(29, "Write error : cannot properly close stdout"); EXM_THROW(29, "Write error : cannot properly close stdout");
} else { } else {
@@ -963,9 +1031,9 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile
free(dstFileName); free(dstFileName);
dfnSize = ifnSize + 20; dfnSize = ifnSize + 20;
dstFileName = (char*)malloc(dfnSize); dstFileName = (char*)malloc(dfnSize);
if (!dstFileName) { if (!dstFileName)
EXM_THROW(30, "zstd: %s", strerror(errno)); EXM_THROW(30, "zstd: %s", strerror(errno));
} } }
strcpy(dstFileName, inFileNamesTable[u]); strcpy(dstFileName, inFileNamesTable[u]);
strcat(dstFileName, suffix); strcat(dstFileName, suffix);
missed_files += FIO_compressFilename_dstFile(ress, dstFileName, inFileNamesTable[u], compressionLevel); missed_files += FIO_compressFilename_dstFile(ress, dstFileName, inFileNamesTable[u], compressionLevel);
@@ -1145,7 +1213,7 @@ static void FIO_zstdErrorHelp(dRess_t* ress, size_t ret, char const* srcFileName
if (ret == 0) { if (ret == 0) {
U32 const windowSize = (U32)header.windowSize; U32 const windowSize = (U32)header.windowSize;
U32 const windowLog = BIT_highbit32(windowSize) + ((windowSize & (windowSize - 1)) != 0); U32 const windowLog = BIT_highbit32(windowSize) + ((windowSize & (windowSize - 1)) != 0);
U32 const windowMB = (windowSize >> 20) + ((windowSize & ((1 MB) - 1)) != 0); U32 const windowMB = (windowSize >> 20) + (windowSize & ((1 MB) - 1));
assert(header.windowSize <= (U64)((U32)-1)); assert(header.windowSize <= (U64)((U32)-1));
assert(g_memLimit > 0); assert(g_memLimit > 0);
DISPLAYLEVEL(1, "%s : Window size larger than maximum : %llu > %u\n", DISPLAYLEVEL(1, "%s : Window size larger than maximum : %llu > %u\n",
@@ -1567,10 +1635,6 @@ static int FIO_decompressSrcFile(dRess_t ress, const char* dstFileName, const ch
if ( g_removeSrcFile /* --rm */ if ( g_removeSrcFile /* --rm */
&& (result==0) /* decompression successful */ && (result==0) /* decompression successful */
&& strcmp(srcFileName, stdinmark) ) /* not stdin */ { && strcmp(srcFileName, stdinmark) ) /* not stdin */ {
/* We must clear the handler, since after this point calling it would
* delete both the source and destination files.
*/
clearHandler();
if (remove(srcFileName)) { if (remove(srcFileName)) {
/* failed to remove src file */ /* failed to remove src file */
DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno)); DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno));
@@ -1594,17 +1658,18 @@ static int FIO_decompressDstFile(dRess_t ress,
ress.dstFile = FIO_openDstFile(dstFileName); ress.dstFile = FIO_openDstFile(dstFileName);
if (ress.dstFile==0) return 1; if (ress.dstFile==0) return 1;
/* Must ony be added after FIO_openDstFile() succeeds.
* Otherwise we may delete the destination file if at already exists, and if (UTIL_isRegularFile(dstFileName)) {
* the user presses Ctrl-C when asked if they wish to overwrite. g_artefact = dstFileName;
*/ signal(SIGINT, INThandler);
addHandler(dstFileName); } else {
g_artefact = NULL;
}
if ( strcmp(srcFileName, stdinmark) if ( strcmp(srcFileName, stdinmark)
&& UTIL_getFileStat(srcFileName, &statbuf) ) && UTIL_getFileStat(srcFileName, &statbuf) )
stat_result = 1; stat_result = 1;
result = FIO_decompressSrcFile(ress, dstFileName, srcFileName); result = FIO_decompressSrcFile(ress, dstFileName, srcFileName);
clearHandler();
if (fclose(ress.dstFile)) { if (fclose(ress.dstFile)) {
DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno)); DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno));
@@ -1642,21 +1707,24 @@ int FIO_decompressFilename(const char* dstFileName, const char* srcFileName,
#define MAXSUFFIXSIZE 8 #define MAXSUFFIXSIZE 8
int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles, int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles,
const char* outFileName, const char* suffix,
const char* dictFileName) const char* dictFileName)
{ {
int skippedFiles = 0; int skippedFiles = 0;
int missingFiles = 0; int missingFiles = 0;
dRess_t ress = FIO_createDResources(dictFileName); dRess_t ress = FIO_createDResources(dictFileName);
if (outFileName) { if (suffix==NULL)
EXM_THROW(70, "zstd: decompression: unknown dst"); /* should never happen */
if (!strcmp(suffix, stdoutmark) || !strcmp(suffix, nulmark)) { /* special cases : -c or -t */
unsigned u; unsigned u;
ress.dstFile = FIO_openDstFile(outFileName); ress.dstFile = FIO_openDstFile(suffix);
if (ress.dstFile == 0) EXM_THROW(71, "cannot open %s", outFileName); if (ress.dstFile == 0) EXM_THROW(71, "cannot open %s", suffix);
for (u=0; u<nbFiles; u++) for (u=0; u<nbFiles; u++)
missingFiles += FIO_decompressSrcFile(ress, outFileName, srcNamesTable[u]); missingFiles += FIO_decompressSrcFile(ress, suffix, srcNamesTable[u]);
if (fclose(ress.dstFile)) if (fclose(ress.dstFile))
EXM_THROW(72, "Write error : cannot properly close output file"); EXM_THROW(72, "Write error : cannot properly close stdout");
} else { } else {
size_t suffixSize; size_t suffixSize;
size_t dfnSize = FNSPACE; size_t dfnSize = FNSPACE;
@@ -1729,7 +1797,7 @@ typedef struct {
* 2 for file not compressed with zstd * 2 for file not compressed with zstd
* 3 for cases in which file could not be opened. * 3 for cases in which file could not be opened.
*/ */
static int getFileInfo_fileConfirmed(fileInfo_t* info, const char* inFileName){ static int getFileInfo(fileInfo_t* info, const char* inFileName){
int detectError = 0; int detectError = 0;
FILE* const srcFile = FIO_openSrcFile(inFileName); FILE* const srcFile = FIO_openSrcFile(inFileName);
if (srcFile == NULL) { if (srcFile == NULL) {
@@ -1745,8 +1813,7 @@ static int getFileInfo_fileConfirmed(fileInfo_t* info, const char* inFileName){
if (numBytesRead < ZSTD_frameHeaderSize_min) { if (numBytesRead < ZSTD_frameHeaderSize_min) {
if ( feof(srcFile) if ( feof(srcFile)
&& (numBytesRead == 0) && (numBytesRead == 0)
&& (info->compressedSize > 0) && (info->compressedSize > 0) ) {
&& (info->compressedSize != UTIL_FILESIZE_UNKNOWN) ) {
break; break;
} }
else if (feof(srcFile)) { else if (feof(srcFile)) {
@@ -1859,18 +1926,7 @@ static int getFileInfo_fileConfirmed(fileInfo_t* info, const char* inFileName){
return detectError; return detectError;
} }
static int getFileInfo(fileInfo_t* info, const char* srcFileName) static void displayInfo(const char* inFileName, fileInfo_t* info, int displayLevel){
{
int const isAFile = UTIL_isRegularFile(srcFileName);
if (!isAFile) {
DISPLAY("Error : %s is not a file", srcFileName);
return 3;
}
return getFileInfo_fileConfirmed(info, srcFileName);
}
static void displayInfo(const char* inFileName, const fileInfo_t* info, int displayLevel){
unsigned const unit = info->compressedSize < (1 MB) ? (1 KB) : (1 MB); unsigned const unit = info->compressedSize < (1 MB) ? (1 KB) : (1 MB);
const char* const unitStr = info->compressedSize < (1 MB) ? "KB" : "MB"; const char* const unitStr = info->compressedSize < (1 MB) ? "KB" : "MB";
double const windowSizeUnit = (double)info->windowSize / unit; double const windowSizeUnit = (double)info->windowSize / unit;
@@ -1893,10 +1949,8 @@ static void displayInfo(const char* inFileName, const fileInfo_t* info, int disp
checkString, inFileName); checkString, inFileName);
} }
} else { } else {
DISPLAYOUT("%s \n", inFileName);
DISPLAYOUT("# Zstandard Frames: %d\n", info->numActualFrames); DISPLAYOUT("# Zstandard Frames: %d\n", info->numActualFrames);
if (info->numSkippableFrames) DISPLAYOUT("# Skippable Frames: %d\n", info->numSkippableFrames);
DISPLAYOUT("# Skippable Frames: %d\n", info->numSkippableFrames);
DISPLAYOUT("Window Size: %.2f %2s (%llu B)\n", DISPLAYOUT("Window Size: %.2f %2s (%llu B)\n",
windowSizeUnit, unitStr, windowSizeUnit, unitStr,
(unsigned long long)info->windowSize); (unsigned long long)info->windowSize);
@@ -1928,6 +1982,7 @@ static fileInfo_t FIO_addFInfo(fileInfo_t fi1, fileInfo_t fi2)
} }
static int FIO_listFile(fileInfo_t* total, const char* inFileName, int displayLevel){ static int FIO_listFile(fileInfo_t* total, const char* inFileName, int displayLevel){
/* initialize info to avoid warnings */
fileInfo_t info; fileInfo_t info;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
{ int const error = getFileInfo(&info, inFileName); { int const error = getFileInfo(&info, inFileName);
@@ -1967,7 +2022,7 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis
for (u=0; u<numFiles;u++) { for (u=0; u<numFiles;u++) {
error |= FIO_listFile(&total, filenameTable[u], displayLevel); error |= FIO_listFile(&total, filenameTable[u], displayLevel);
} }
if (numFiles > 1 && displayLevel <= 2) { /* display total */ if (numFiles > 1 && displayLevel <= 2) {
unsigned const unit = total.compressedSize < (1 MB) ? (1 KB) : (1 MB); unsigned const unit = total.compressedSize < (1 MB) ? (1 KB) : (1 MB);
const char* const unitStr = total.compressedSize < (1 MB) ? "KB" : "MB"; const char* const unitStr = total.compressedSize < (1 MB) ? "KB" : "MB";
double const compressedSizeUnit = (double)total.compressedSize / unit; double const compressedSizeUnit = (double)total.compressedSize / unit;
@@ -1987,7 +2042,8 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis
total.numSkippableFrames, total.numSkippableFrames,
compressedSizeUnit, unitStr, decompressedSizeUnit, unitStr, compressedSizeUnit, unitStr, decompressedSizeUnit, unitStr,
ratio, checkString, total.nbFiles); ratio, checkString, total.nbFiles);
} } }
}
return error; return error;
} }
} }
+2 -2
View File
@@ -84,14 +84,14 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis
/** FIO_compressMultipleFilenames() : /** FIO_compressMultipleFilenames() :
@return : nb of missing files */ @return : nb of missing files */
int FIO_compressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles, int FIO_compressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles,
const char* outFileName, const char* suffix, const char* suffix,
const char* dictFileName, int compressionLevel, const char* dictFileName, int compressionLevel,
ZSTD_compressionParameters* comprParams); ZSTD_compressionParameters* comprParams);
/** FIO_decompressMultipleFilenames() : /** FIO_decompressMultipleFilenames() :
@return : nb of missing or skipped files */ @return : nb of missing or skipped files */
int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles, int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles,
const char* outFileName, const char* suffix,
const char* dictFileName); const char* dictFileName);
+6 -6
View File
@@ -21,10 +21,10 @@ extern "C" {
* Compiler Options * Compiler Options
****************************************/ ****************************************/
#if defined(_MSC_VER) #if defined(_MSC_VER)
# define _CRT_SECURE_NO_WARNINGS /* Disable Visual Studio warning messages for fopen, strncpy, strerror */ # define _CRT_SECURE_NO_WARNINGS /* Disable Visual Studio warning messages for fopen, strncpy, strerror */
# if (_MSC_VER <= 1800) /* 1800 == Visual Studio 2013 */ # define _CRT_SECURE_NO_DEPRECATE /* VS2005 - must be declared before <io.h> and <windows.h> */
# define _CRT_SECURE_NO_DEPRECATE /* VS2005 - must be declared before <io.h> and <windows.h> */ # if (_MSC_VER <= 1800) /* (1800 = Visual Studio 2013) */
# define snprintf sprintf_s /* snprintf unsupported by Visual <= 2013 */ # define snprintf sprintf_s /* snprintf unsupported by Visual <= 2013 */
# endif # endif
#endif #endif
@@ -117,7 +117,7 @@ static __inline int IS_CONSOLE(FILE* stdStream)
/****************************** /******************************
* OS-specific IO behaviors * OS-specific Includes
******************************/ ******************************/
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32)
# include <fcntl.h> /* _O_BINARY */ # include <fcntl.h> /* _O_BINARY */
@@ -125,7 +125,7 @@ static __inline int IS_CONSOLE(FILE* stdStream)
# if !defined(__DJGPP__) # if !defined(__DJGPP__)
# include <windows.h> /* DeviceIoControl, HANDLE, FSCTL_SET_SPARSE */ # include <windows.h> /* DeviceIoControl, HANDLE, FSCTL_SET_SPARSE */
# include <winioctl.h> /* FSCTL_SET_SPARSE */ # include <winioctl.h> /* FSCTL_SET_SPARSE */
# define SET_BINARY_MODE(file) { int const unused=_setmode(_fileno(file), _O_BINARY); (void)unused; } # define SET_BINARY_MODE(file) { int unused=_setmode(_fileno(file), _O_BINARY); (void)unused; }
# define SET_SPARSE_FILE_MODE(file) { DWORD dw; DeviceIoControl((HANDLE) _get_osfhandle(_fileno(file)), FSCTL_SET_SPARSE, 0, 0, 0, 0, &dw, 0); } # define SET_SPARSE_FILE_MODE(file) { DWORD dw; DeviceIoControl((HANDLE) _get_osfhandle(_fileno(file)), FSCTL_SET_SPARSE, 0, 0, 0, 0, &dw, 0); }
# else # else
# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) # define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+19 -29
View File
@@ -34,7 +34,7 @@ extern "C" {
# include <unistd.h> /* chown, stat */ # include <unistd.h> /* chown, stat */
# include <utime.h> /* utime */ # include <utime.h> /* utime */
#endif #endif
#include <time.h> /* clock_t, clock, CLOCKS_PER_SEC, nanosleep */ #include <time.h> /* time */
#include <errno.h> #include <errno.h>
#include "mem.h" /* U32, U64 */ #include "mem.h" /* U32, U64 */
@@ -64,6 +64,7 @@ extern "C" {
#elif PLATFORM_POSIX_VERSION >= 0 /* Unix-like operating system */ #elif PLATFORM_POSIX_VERSION >= 0 /* Unix-like operating system */
# include <unistd.h> # include <unistd.h>
# include <sys/resource.h> /* setpriority */ # include <sys/resource.h> /* setpriority */
# include <time.h> /* clock_t, nanosleep, clock, CLOCKS_PER_SEC */
# if defined(PRIO_PROCESS) # if defined(PRIO_PROCESS)
# define SET_REALTIME_PRIORITY setpriority(PRIO_PROCESS, 0, -20) # define SET_REALTIME_PRIORITY setpriority(PRIO_PROCESS, 0, -20)
# else # else
@@ -117,7 +118,6 @@ static int g_utilDisplayLevel;
* Time functions * Time functions
******************************************/ ******************************************/
#if defined(_WIN32) /* Windows */ #if defined(_WIN32) /* Windows */
#define UTIL_TIME_INITIALIZER { { 0, 0 } }
typedef LARGE_INTEGER UTIL_time_t; typedef LARGE_INTEGER UTIL_time_t;
UTIL_STATIC UTIL_time_t UTIL_getTime(void) { UTIL_time_t x; QueryPerformanceCounter(&x); return x; } UTIL_STATIC UTIL_time_t UTIL_getTime(void) { UTIL_time_t x; QueryPerformanceCounter(&x); return x; }
UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd)
@@ -144,7 +144,6 @@ static int g_utilDisplayLevel;
} }
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)
#include <mach/mach_time.h> #include <mach/mach_time.h>
#define UTIL_TIME_INITIALIZER 0
typedef U64 UTIL_time_t; typedef U64 UTIL_time_t;
UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return mach_absolute_time(); } UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return mach_absolute_time(); }
UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd)
@@ -167,8 +166,8 @@ static int g_utilDisplayLevel;
} }
return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom); return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom);
} }
#elif (PLATFORM_POSIX_VERSION >= 200112L) && (defined __UCLIBC__ || ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) || __GLIBC__ > 2)) #elif (PLATFORM_POSIX_VERSION >= 200112L)
#define UTIL_TIME_INITIALIZER { 0, 0 } #include <time.h>
typedef struct timespec UTIL_freq_t; typedef struct timespec UTIL_freq_t;
typedef struct timespec UTIL_time_t; typedef struct timespec UTIL_time_t;
UTIL_STATIC UTIL_time_t UTIL_getTime(void) UTIL_STATIC UTIL_time_t UTIL_getTime(void)
@@ -208,13 +207,11 @@ static int g_utilDisplayLevel;
} }
#else /* relies on standard C (note : clock_t measurements can be wrong when using multi-threading) */ #else /* relies on standard C (note : clock_t measurements can be wrong when using multi-threading) */
typedef clock_t UTIL_time_t; typedef clock_t UTIL_time_t;
#define UTIL_TIME_INITIALIZER 0
UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return clock(); } UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return clock(); }
UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; }
#endif #endif
#define SEC_TO_MICRO 1000000
/* returns time span in microseconds */ /* returns time span in microseconds */
UTIL_STATIC U64 UTIL_clockSpanMicro( UTIL_time_t clockStart ) UTIL_STATIC U64 UTIL_clockSpanMicro( UTIL_time_t clockStart )
@@ -316,40 +313,33 @@ UTIL_STATIC U32 UTIL_isLink(const char* infilename)
} }
#define UTIL_FILESIZE_UNKNOWN ((U64)(-1))
UTIL_STATIC U64 UTIL_getFileSize(const char* infilename) UTIL_STATIC U64 UTIL_getFileSize(const char* infilename)
{ {
if (!UTIL_isRegularFile(infilename)) return UTIL_FILESIZE_UNKNOWN; int r;
{ int r;
#if defined(_MSC_VER) #if defined(_MSC_VER)
struct __stat64 statbuf; struct __stat64 statbuf;
r = _stat64(infilename, &statbuf); r = _stat64(infilename, &statbuf);
if (r || !(statbuf.st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN; if (r || !(statbuf.st_mode & S_IFREG)) return 0; /* No good... */
#elif defined(__MINGW32__) && defined (__MSVCRT__) #elif defined(__MINGW32__) && defined (__MSVCRT__)
struct _stati64 statbuf; struct _stati64 statbuf;
r = _stati64(infilename, &statbuf); r = _stati64(infilename, &statbuf);
if (r || !(statbuf.st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN; if (r || !(statbuf.st_mode & S_IFREG)) return 0; /* No good... */
#else #else
struct stat statbuf; struct stat statbuf;
r = stat(infilename, &statbuf); r = stat(infilename, &statbuf);
if (r || !S_ISREG(statbuf.st_mode)) return UTIL_FILESIZE_UNKNOWN; if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */
#endif #endif
return (U64)statbuf.st_size; return (U64)statbuf.st_size;
}
} }
UTIL_STATIC U64 UTIL_getTotalFileSize(const char* const * const fileNamesTable, unsigned nbFiles) UTIL_STATIC U64 UTIL_getTotalFileSize(const char** fileNamesTable, unsigned nbFiles)
{ {
U64 total = 0; U64 total = 0;
int error = 0;
unsigned n; unsigned n;
for (n=0; n<nbFiles; n++) { for (n=0; n<nbFiles; n++)
U64 const size = UTIL_getFileSize(fileNamesTable[n]); total += UTIL_getFileSize(fileNamesTable[n]);
error |= (size == UTIL_FILESIZE_UNKNOWN); return total;
total += size;
}
return error ? UTIL_FILESIZE_UNKNOWN : total;
} }
+3 -9
View File
@@ -1,5 +1,5 @@
. .
.TH "ZSTD" "1" "December 2017" "zstd 1.3.3" "User Commands" .TH "ZSTD" "1" "September 2017" "zstd 1.3.1" "User Commands"
. .
.SH "NAME" .SH "NAME"
\fBzstd\fR \- zstd, zstdmt, unzstd, zstdcat \- Compress or decompress \.zst files \fBzstd\fR \- zstd, zstdmt, unzstd, zstdcat \- Compress or decompress \.zst files
@@ -60,11 +60,11 @@ In most places where an integer argument is expected, an optional suffix is supp
. .
.TP .TP
\fBKiB\fR \fBKiB\fR
Multiply the integer by 1,024 (2^10)\. \fBKi\fR, \fBK\fR, and \fBKB\fR are accepted as synonyms for \fBKiB\fR\. Multiply the integer by 1,024 (2\e \fBKi\fR, \fBK\fR, and \fBKB\fR are accepted as synonyms for \fBKiB\fR\.
. .
.TP .TP
\fBMiB\fR \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\. Multiply the integer by 1,048,576 (2\e \fBMi\fR, \fBM\fR, and \fBMB\fR are accepted as synonyms for \fBMiB\fR\.
. .
.SS "Operation mode" .SS "Operation mode"
If multiple operation mode options are given, the last one takes effect\. If multiple operation mode options are given, the last one takes effect\.
@@ -261,12 +261,6 @@ cut file(s) into independent blocks of size # (default: no block)
\fB\-\-priority=rt\fR \fB\-\-priority=rt\fR
set process priority to real\-time set process priority to real\-time
. .
.P
\fBOutput Format:\fR CompressionLevel#Filename : IntputSize \-> OutputSize (CompressionRatio), CompressionSpeed, DecompressionSpeed
.
.P
\fBMethodology:\fR For both compression and decompression speed, 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 "ADVANCED COMPRESSION OPTIONS" .SH "ADVANCED COMPRESSION OPTIONS"
. .
.SS "\-\-zstd[=options]:" .SS "\-\-zstd[=options]:"
-3
View File
@@ -258,9 +258,6 @@ BENCHMARK
* `--priority=rt`: * `--priority=rt`:
set process priority to real-time set process priority to real-time
**Output Format:** CompressionLevel#Filename : IntputSize -> OutputSize (CompressionRatio), CompressionSpeed, DecompressionSpeed
**Methodology:** For both compression and decompression speed, 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.
ADVANCED COMPRESSION OPTIONS ADVANCED COMPRESSION OPTIONS
---------------------------- ----------------------------
+10 -14
View File
@@ -377,7 +377,6 @@ int main(int argCount, const char* argv[])
lastCommand = 0, lastCommand = 0,
nbThreads = 1, nbThreads = 1,
setRealTimePrio = 0, setRealTimePrio = 0,
separateFiles = 0,
ldmFlag = 0; ldmFlag = 0;
unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */ unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */
size_t blockSize = 0; size_t blockSize = 0;
@@ -634,12 +633,6 @@ int main(int argCount, const char* argv[])
blockSize = readU32FromChar(&argument); blockSize = readU32FromChar(&argument);
break; break;
/* benchmark files separately (hidden option) */
case 'S':
argument++;
separateFiles = 1;
break;
#endif /* ZSTD_NOBENCH */ #endif /* ZSTD_NOBENCH */
/* nb of threads (hidden option) */ /* nb of threads (hidden option) */
@@ -758,10 +751,8 @@ int main(int argCount, const char* argv[])
if (operation==zom_bench) { if (operation==zom_bench) {
#ifndef ZSTD_NOBENCH #ifndef ZSTD_NOBENCH
BMK_setNotificationLevel(g_displayLevel); BMK_setNotificationLevel(g_displayLevel);
BMK_setSeparateFiles(separateFiles);
BMK_setBlockSize(blockSize); BMK_setBlockSize(blockSize);
BMK_setNbThreads(nbThreads); BMK_setNbThreads(nbThreads);
BMK_setRealTime(setRealTimePrio);
BMK_setNbSeconds(bench_nbSeconds); BMK_setNbSeconds(bench_nbSeconds);
BMK_setLdmFlag(ldmFlag); BMK_setLdmFlag(ldmFlag);
BMK_setLdmMinMatch(g_ldmMinMatch); BMK_setLdmMinMatch(g_ldmMinMatch);
@@ -772,10 +763,9 @@ int main(int argCount, const char* argv[])
if (g_ldmHashEveryLog != LDM_PARAM_DEFAULT) { if (g_ldmHashEveryLog != LDM_PARAM_DEFAULT) {
BMK_setLdmHashEveryLog(g_ldmHashEveryLog); BMK_setLdmHashEveryLog(g_ldmHashEveryLog);
} }
BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast, &compressionParams); BMK_benchFiles(filenameTable, filenameIdx, dictFileName, cLevel, cLevelLast, &compressionParams, setRealTimePrio);
#else
(void)bench_nbSeconds; (void)blockSize; (void)setRealTimePrio; (void)separateFiles;
#endif #endif
(void)bench_nbSeconds; (void)blockSize; (void)setRealTimePrio;
goto _end; goto _end;
} }
@@ -815,6 +805,12 @@ int main(int argCount, const char* argv[])
if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !strcmp(filenameTable[0], stdinmark) && !forceStdout && operation!=zom_decompress) if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !strcmp(filenameTable[0], stdinmark) && !forceStdout && operation!=zom_decompress)
CLEAN_RETURN(badusage(programName)); CLEAN_RETURN(badusage(programName));
/* user-selected output filename, only possible with a single file */
if (outFileName && strcmp(outFileName,stdoutmark) && strcmp(outFileName,nulmark) && (filenameIdx>1)) {
DISPLAY("Too many files (%u) on the command line. \n", filenameIdx);
CLEAN_RETURN(filenameIdx);
}
#ifndef ZSTD_NOCOMPRESS #ifndef ZSTD_NOCOMPRESS
/* check compression level limits */ /* check compression level limits */
{ int const maxCLevel = ultra ? ZSTD_maxCLevel() : ZSTDCLI_CLEVEL_MAX; { int const maxCLevel = ultra ? ZSTD_maxCLevel() : ZSTDCLI_CLEVEL_MAX;
@@ -848,7 +844,7 @@ int main(int argCount, const char* argv[])
if ((filenameIdx==1) && outFileName) if ((filenameIdx==1) && outFileName)
operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel, &compressionParams); operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel, &compressionParams);
else else
operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, outFileName, suffix, dictFileName, cLevel, &compressionParams); operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : suffix, dictFileName, cLevel, &compressionParams);
#else #else
(void)suffix; (void)suffix;
DISPLAY("Compression not supported\n"); DISPLAY("Compression not supported\n");
@@ -866,7 +862,7 @@ int main(int argCount, const char* argv[])
if (filenameIdx==1 && outFileName) if (filenameIdx==1 && outFileName)
operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName); operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName);
else else
operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, outFileName, dictFileName); operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : ZSTD_EXTENSION, dictFileName);
#else #else
DISPLAY("Decompression not supported\n"); DISPLAY("Decompression not supported\n");
#endif #endif
+33 -32
View File
@@ -76,16 +76,16 @@ allnothread: fullbench fuzzer paramgrill datagen decodecorpus
dll: fuzzer-dll zstreamtest-dll dll: fuzzer-dll zstreamtest-dll
zstd: zstd:
$(MAKE) -C $(PRGDIR) $@ MOREFLAGS+="$(DEBUGFLAGS)" $(MAKE) -C $(PRGDIR) $@
zstd32: zstd32:
$(MAKE) -C $(PRGDIR) $@ MOREFLAGS+="$(DEBUGFLAGS)" $(MAKE) -C $(PRGDIR) $@
zstd-nolegacy: zstd-nolegacy:
$(MAKE) -C $(PRGDIR) $@ MOREFLAGS+="$(DEBUGFLAGS)" $(MAKE) -C $(PRGDIR) $@
gzstd: gzstd:
$(MAKE) -C $(PRGDIR) zstd HAVE_ZLIB=1 MOREFLAGS="$(DEBUGFLAGS)" $(MAKE) -C $(PRGDIR) zstd HAVE_ZLIB=1
fullbench32: CPPFLAGS += -m32 fullbench32: CPPFLAGS += -m32
fullbench fullbench32 : CPPFLAGS += $(MULTITHREAD_CPP) fullbench fullbench32 : CPPFLAGS += $(MULTITHREAD_CPP)
@@ -130,13 +130,16 @@ zbufftest-dll : $(ZSTDDIR)/common/xxhash.c $(PRGDIR)/datagen.c zbufftest.c
$(MAKE) -C $(ZSTDDIR) libzstd $(MAKE) -C $(ZSTDDIR) libzstd
$(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@$(EXT) $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@$(EXT)
ZSTREAMFILES := $(ZSTD_FILES) $(ZDICT_FILES) $(PRGDIR)/datagen.c seqgen.c zstreamtest.c ZSTREAMFILES := $(ZSTD_FILES) $(ZDICT_FILES) $(PRGDIR)/datagen.c zstreamtest.c
zstreamtest32 : CFLAGS += -m32 zstreamtest : CPPFLAGS += $(MULTITHREAD_CPP)
zstreamtest zstreamtest32 : CPPFLAGS += $(MULTITHREAD_CPP) zstreamtest : LDFLAGS += $(MULTITHREAD_LD)
zstreamtest zstreamtest32 : LDFLAGS += $(MULTITHREAD_LD) zstreamtest : $(ZSTREAMFILES)
zstreamtest zstreamtest32 : $(ZSTREAMFILES)
$(CC) $(FLAGS) $^ -o $@$(EXT) $(CC) $(FLAGS) $^ -o $@$(EXT)
zstreamtest32 : CFLAGS += -m32
zstreamtest32 : $(ZSTREAMFILES)
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
zstreamtest_asan : CFLAGS += -fsanitize=address zstreamtest_asan : CFLAGS += -fsanitize=address
zstreamtest_asan : $(ZSTREAMFILES) zstreamtest_asan : $(ZSTREAMFILES)
$(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT) $(CC) $(FLAGS) $(MULTITHREAD) $^ -o $@$(EXT)
@@ -292,48 +295,48 @@ test-gzstd: gzstd
$(RM) *.gz *.zst README2.md gz_zstd zstd_gz hello.txt $(RM) *.gz *.zst README2.md gz_zstd zstd_gz hello.txt
test-fullbench: fullbench datagen test-fullbench: fullbench datagen
$(QEMU_SYS) ./fullbench -i1 echo -n "XXX"; date; $(QEMU_SYS) ./fullbench -i1
$(QEMU_SYS) ./fullbench -i1 -P0 echo -n "XXX"; date; $(QEMU_SYS) ./fullbench -i1 -P0
test-fullbench32: fullbench32 datagen test-fullbench32: fullbench32 datagen
$(QEMU_SYS) ./fullbench32 -i1 echo -n "XXX"; date; $(QEMU_SYS) ./fullbench32 -i1
$(QEMU_SYS) ./fullbench32 -i1 -P0 echo -n "XXX"; date; $(QEMU_SYS) ./fullbench32 -i1 -P0
test-fuzzer: fuzzer test-fuzzer: fuzzer
$(QEMU_SYS) ./fuzzer -v $(FUZZERTEST) $(FUZZER_FLAGS) echo -n "XXX"; date; $(QEMU_SYS) ./fuzzer $(FUZZERTEST) $(FUZZER_FLAGS)
test-fuzzer32: fuzzer32 test-fuzzer32: fuzzer32
$(QEMU_SYS) ./fuzzer32 -v $(FUZZERTEST) $(FUZZER_FLAGS) echo -n "XXX"; date; $(QEMU_SYS) ./fuzzer32 $(FUZZERTEST) $(FUZZER_FLAGS)
test-zbuff: zbufftest test-zbuff: zbufftest
$(QEMU_SYS) ./zbufftest $(ZSTREAM_TESTTIME) echo -n "XXX"; date; $(QEMU_SYS) ./zbufftest $(ZSTREAM_TESTTIME)
test-zbuff32: zbufftest32 test-zbuff32: zbufftest32
$(QEMU_SYS) ./zbufftest32 $(ZSTREAM_TESTTIME) echo -n "XXX"; date; $(QEMU_SYS) ./zbufftest32 $(ZSTREAM_TESTTIME)
test-zstream: zstreamtest test-zstream: zstreamtest
$(QEMU_SYS) ./zstreamtest -v $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) echo -n "XXX"; date; $(QEMU_SYS) ./zstreamtest $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
$(QEMU_SYS) ./zstreamtest --mt -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) echo -n "XXX"; date; $(QEMU_SYS) ./zstreamtest --mt -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
$(QEMU_SYS) ./zstreamtest --newapi -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) echo -n "XXX"; date; $(QEMU_SYS) ./zstreamtest --newapi -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
$(QEMU_SYS) ./zstreamtest --opaqueapi -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) echo -n "XXX"; date; $(QEMU_SYS) ./zstreamtest --opaqueapi -t1 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
test-zstream32: zstreamtest32 test-zstream32: zstreamtest32
$(QEMU_SYS) ./zstreamtest32 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS) echo -n "XXX"; date; $(QEMU_SYS) ./zstreamtest32 $(ZSTREAM_TESTTIME) $(FUZZER_FLAGS)
test-longmatch: longmatch test-longmatch: longmatch
$(QEMU_SYS) ./longmatch $(QEMU_SYS) ./longmatch
test-invalidDictionaries: invalidDictionaries test-invalidDictionaries: invalidDictionaries
$(QEMU_SYS) ./invalidDictionaries echo -n "XXX"; date; $(QEMU_SYS) ./invalidDictionaries
test-symbols: symbols test-symbols: symbols
$(QEMU_SYS) ./symbols echo -n "XXX"; date; $(QEMU_SYS) ./symbols
test-legacy: legacy test-legacy: legacy
$(QEMU_SYS) ./legacy echo -n "XXX"; date; $(QEMU_SYS) ./legacy
test-decodecorpus: decodecorpus test-decodecorpus: decodecorpus
$(QEMU_SYS) ./decodecorpus -t $(DECODECORPUS_TESTTIME) echo -n "XXX"; date; $(QEMU_SYS) ./decodecorpus -t $(DECODECORPUS_TESTTIME)
test-decodecorpus-cli: decodecorpus test-decodecorpus-cli: decodecorpus
@echo "\n ---- decodecorpus basic cli tests ----" @echo "\n ---- decodecorpus basic cli tests ----"
@@ -369,14 +372,14 @@ test-decodecorpus-cli: decodecorpus
@rm -rf testdir @rm -rf testdir
test-pool: poolTests test-pool: poolTests
$(QEMU_SYS) ./poolTests echo -n "XXX"; date; $(QEMU_SYS) ./poolTests
test-lz4: ZSTD = LD_LIBRARY_PATH=/usr/local/lib $(PRGDIR)/zstd 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_LZ4 = LD_LIBRARY_PATH=/usr/local/lib ./lz4
test-lz4: ZSTD_UNLZ4 = LD_LIBRARY_PATH=/usr/local/lib ./unlz4 test-lz4: ZSTD_UNLZ4 = LD_LIBRARY_PATH=/usr/local/lib ./unlz4
test-lz4: zstd decodecorpus datagen test-lz4: zstd decodecorpus
[ -f lz4 ] || ln -s $(PRGDIR)/zstd lz4 ln -s $(PRGDIR)/zstd lz4
[ -f unlz4 ] || ln -s $(PRGDIR)/zstd unlz4 ln -s $(PRGDIR)/zstd unlz4
./decodecorpus -ptmp ./decodecorpus -ptmp
# lz4 -> zstd # lz4 -> zstd
@@ -402,8 +405,6 @@ test-lz4: zstd decodecorpus datagen
$(ZSTD) -d | \ $(ZSTD) -d | \
cmp - tmp cmp - tmp
./datagen -g384KB | $(ZSTD) --format=lz4 | $(ZSTD) -d > /dev/null
rm tmp lz4 unlz4 rm tmp lz4 unlz4
endif endif
+12 -8
View File
@@ -14,8 +14,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include "util.h"
#include "zstd.h" #include "zstd.h"
#include "zstd_internal.h" #include "zstd_internal.h"
#include "mem.h" #include "mem.h"
@@ -49,16 +49,20 @@ static U32 g_displayLevel = 2;
#define DISPLAYUPDATE(...) \ #define DISPLAYUPDATE(...) \
do { \ do { \
if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || \ if ((clockSpan(g_displayClock) > g_refreshRate) || \
(g_displayLevel >= 4)) { \ (g_displayLevel >= 4)) { \
g_displayClock = UTIL_getTime(); \ g_displayClock = clock(); \
DISPLAY(__VA_ARGS__); \ DISPLAY(__VA_ARGS__); \
if (g_displayLevel >= 4) fflush(stderr); \ if (g_displayLevel >= 4) fflush(stderr); \
} \ } \
} while (0) } while (0)
static const clock_t g_refreshRate = CLOCKS_PER_SEC / 6;
static clock_t g_displayClock = 0;
static const U64 g_refreshRate = SEC_TO_MICRO / 6; static clock_t clockSpan(clock_t cStart)
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER; {
return clock() - cStart; /* works even when overflow; max span ~ 30mn */
}
#define CHECKERR(code) \ #define CHECKERR(code) \
do { \ do { \
@@ -1527,14 +1531,14 @@ static int runTestMode(U32 seed, unsigned numFiles, unsigned const testDurationS
{ {
unsigned fnum; unsigned fnum;
UTIL_time_t const startClock = UTIL_getTime(); clock_t const startClock = clock();
U64 const maxClockSpan = testDurationS * SEC_TO_MICRO; clock_t const maxClockSpan = testDurationS * CLOCKS_PER_SEC;
if (numFiles == 0 && !testDurationS) numFiles = 1; if (numFiles == 0 && !testDurationS) numFiles = 1;
DISPLAY("seed: %u\n", seed); DISPLAY("seed: %u\n", seed);
for (fnum = 0; fnum < numFiles || UTIL_clockSpanMicro(startClock) < maxClockSpan; fnum++) { for (fnum = 0; fnum < numFiles || clockSpan(startClock) < maxClockSpan; fnum++) {
if (fnum < numFiles) if (fnum < numFiles)
DISPLAYUPDATE("\r%u/%u ", fnum, numFiles); DISPLAYUPDATE("\r%u/%u ", fnum, numFiles);
else else
+3 -8
View File
@@ -233,7 +233,7 @@ static ZSTD_CCtx* g_zcc = NULL;
size_t local_ZSTD_compressContinue(void* dst, size_t dstCapacity, void* buff2, const void* src, size_t srcSize) size_t local_ZSTD_compressContinue(void* dst, size_t dstCapacity, void* buff2, const void* src, size_t srcSize)
{ {
(void)buff2; (void)buff2;
ZSTD_compressBegin(g_zcc, 1 /* compressionLevel */); ZSTD_compressBegin(g_zcc, 1);
return ZSTD_compressEnd(g_zcc, dst, dstCapacity, src, srcSize); return ZSTD_compressEnd(g_zcc, dst, dstCapacity, src, srcSize);
} }
@@ -484,8 +484,8 @@ static int benchFiles(const char** fileNamesTable, const int nbFiles, U32 benchN
/* Loop for each file */ /* Loop for each file */
int fileIdx; int fileIdx;
for (fileIdx=0; fileIdx<nbFiles; fileIdx++) { for (fileIdx=0; fileIdx<nbFiles; fileIdx++) {
const char* const inFileName = fileNamesTable[fileIdx]; const char* inFileName = fileNamesTable[fileIdx];
FILE* const inFile = fopen( inFileName, "rb" ); FILE* inFile = fopen( inFileName, "rb" );
U64 inFileSize; U64 inFileSize;
size_t benchedSize; size_t benchedSize;
void* origBuff; void* origBuff;
@@ -495,11 +495,6 @@ static int benchFiles(const char** fileNamesTable, const int nbFiles, U32 benchN
/* Memory allocation & restrictions */ /* Memory allocation & restrictions */
inFileSize = UTIL_getFileSize(inFileName); inFileSize = UTIL_getFileSize(inFileName);
if (inFileSize == UTIL_FILESIZE_UNKNOWN) {
DISPLAY( "Cannot measure size of %s\n", inFileName);
fclose(inFile);
return 11;
}
benchedSize = BMK_findMaxMem(inFileSize*3) / 3; benchedSize = BMK_findMaxMem(inFileSize*3) / 3;
if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize; if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
if (benchedSize < inFileSize) if (benchedSize < inFileSize)
+28 -99
View File
@@ -25,7 +25,7 @@
#include <stdlib.h> /* free */ #include <stdlib.h> /* free */
#include <stdio.h> /* fgets, sscanf */ #include <stdio.h> /* fgets, sscanf */
#include <string.h> /* strcmp */ #include <string.h> /* strcmp */
#include <assert.h> #include <time.h> /* clock_t */
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressContinue, ZSTD_compressBlock */ #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressContinue, ZSTD_compressBlock */
#include "zstd.h" /* ZSTD_VERSION_STRING */ #include "zstd.h" /* ZSTD_VERSION_STRING */
#include "zstd_errors.h" /* ZSTD_getErrorCode */ #include "zstd_errors.h" /* ZSTD_getErrorCode */
@@ -36,7 +36,6 @@
#include "mem.h" #include "mem.h"
#define XXH_STATIC_LINKING_ONLY #define XXH_STATIC_LINKING_ONLY
#include "xxhash.h" /* XXH64 */ #include "xxhash.h" /* XXH64 */
#include "util.h"
/*-************************************ /*-************************************
@@ -57,22 +56,25 @@ static const U32 nbTestsDefault = 30000;
#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
static U32 g_displayLevel = 2; static U32 g_displayLevel = 2;
static const U64 g_refreshRate = SEC_TO_MICRO / 6;
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \ if ((FUZ_clockSpan(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \ { g_displayClock = clock(); DISPLAY(__VA_ARGS__); \
if (g_displayLevel>=4) fflush(stderr); } } if (g_displayLevel>=4) fflush(stdout); } }
static const clock_t g_refreshRate = CLOCKS_PER_SEC / 6;
static clock_t g_displayClock = 0;
/*-******************************************************* /*-*******************************************************
* Fuzzer functions * Fuzzer functions
*********************************************************/ *********************************************************/
#undef MIN
#undef MAX
#define MIN(a,b) ((a)<(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b))
static clock_t FUZ_clockSpan(clock_t cStart)
{
return clock() - cStart; /* works even when overflow; max span ~ 30mn */
}
#define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r))) #define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
static unsigned FUZ_rand(unsigned* src) static unsigned FUZ_rand(unsigned* src)
{ {
@@ -95,22 +97,6 @@ static unsigned FUZ_highbit32(U32 v32)
} }
/*=============================================
* Test macros
=============================================*/
#define CHECK_Z(f) { \
size_t const err = f; \
if (ZSTD_isError(err)) { \
DISPLAY("Error => %s : %s ", \
#f, ZSTD_getErrorName(err)); \
exit(1); \
} }
#define CHECK_V(var, fn) size_t const var = fn; if (ZSTD_isError(var)) goto _output_error
#define CHECK(fn) { CHECK_V(err, fn); }
#define CHECKPLUS(var, fn, more) { CHECK_V(var, fn); more; }
/*============================================= /*=============================================
* Memory Tests * Memory Tests
=============================================*/ =============================================*/
@@ -160,6 +146,14 @@ static void FUZ_displayMallocStats(mallocCounter_t count)
(U32)(count.totalMalloc >> 10)); (U32)(count.totalMalloc >> 10));
} }
#define CHECK_Z(f) { \
size_t const err = f; \
if (ZSTD_isError(err)) { \
DISPLAY("Error => %s : %s ", \
#f, ZSTD_getErrorName(err)); \
exit(1); \
} }
static int FUZ_mallocTests(unsigned seed, double compressibility, unsigned part) static int FUZ_mallocTests(unsigned seed, double compressibility, unsigned part)
{ {
size_t const inSize = 64 MB + 16 MB + 4 MB + 1 MB + 256 KB + 64 KB; /* 85.3 MB */ size_t const inSize = 64 MB + 16 MB + 4 MB + 1 MB + 256 KB + 64 KB; /* 85.3 MB */
@@ -265,6 +259,10 @@ static int FUZ_mallocTests(unsigned seed, double compressibility, unsigned part)
* Unit tests * Unit tests
=============================================*/ =============================================*/
#define CHECK_V(var, fn) size_t const var = fn; if (ZSTD_isError(var)) goto _output_error
#define CHECK(fn) { CHECK_V(err, fn); }
#define CHECKPLUS(var, fn, more) { CHECK_V(var, fn); more; }
static int basicUnitTests(U32 seed, double compressibility) static int basicUnitTests(U32 seed, double compressibility)
{ {
size_t const CNBuffSize = 5 MB; size_t const CNBuffSize = 5 MB;
@@ -361,31 +359,6 @@ static int basicUnitTests(U32 seed, double compressibility)
if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; } if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error; }
DISPLAYLEVEL(4, "OK \n"); DISPLAYLEVEL(4, "OK \n");
DISPLAYLEVEL(4, "test%di : check CCtx size after compressing empty input : ", testNb++);
{ ZSTD_CCtx* cctx = ZSTD_createCCtx();
size_t const r = ZSTD_compressCCtx(cctx, compressedBuffer, compressedBufferSize, NULL, 0, 19);
if (ZSTD_isError(r)) goto _output_error;
if (ZSTD_sizeof_CCtx(cctx) > (1U << 20)) goto _output_error;
ZSTD_freeCCtx(cctx);
}
DISPLAYLEVEL(4, "OK \n");
DISPLAYLEVEL(4, "test%di : re-use CCtx with expanding block size : ", testNb++);
{ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
ZSTD_parameters const params = ZSTD_getParams(1, ZSTD_CONTENTSIZE_UNKNOWN, 0);
assert(params.fParams.contentSizeFlag == 1); /* block size will be adapted if pledgedSrcSize is enabled */
CHECK_Z( ZSTD_compressBegin_advanced(cctx, NULL, 0, params, 1 /*pledgedSrcSize*/) );
CHECK_Z( ZSTD_compressEnd(cctx, compressedBuffer, compressedBufferSize, CNBuffer, 1) ); /* creates a block size of 1 */
CHECK_Z( ZSTD_compressBegin_advanced(cctx, NULL, 0, params, ZSTD_CONTENTSIZE_UNKNOWN) ); /* re-use same parameters */
{ size_t const inSize = 2* 128 KB;
size_t const outSize = ZSTD_compressBound(inSize);
CHECK_Z( ZSTD_compressEnd(cctx, compressedBuffer, outSize, CNBuffer, inSize) );
/* will fail if blockSize is not resized */
}
ZSTD_freeCCtx(cctx);
}
DISPLAYLEVEL(4, "OK \n");
/* Static CCtx tests */ /* Static CCtx tests */
#define STATIC_CCTX_LEVEL 3 #define STATIC_CCTX_LEVEL 3
@@ -544,7 +517,7 @@ static int basicUnitTests(U32 seed, double compressibility)
off += r; off += r;
if (i == segs/2) { if (i == segs/2) {
/* insert skippable frame */ /* insert skippable frame */
const U32 skipLen = 129 KB; const U32 skipLen = 128 KB;
MEM_writeLE32((BYTE*)compressedBuffer + off, ZSTD_MAGIC_SKIPPABLE_START); MEM_writeLE32((BYTE*)compressedBuffer + off, ZSTD_MAGIC_SKIPPABLE_START);
MEM_writeLE32((BYTE*)compressedBuffer + off + 4, skipLen); MEM_writeLE32((BYTE*)compressedBuffer + off + 4, skipLen);
off += skipLen + ZSTD_skippableHeaderSize; off += skipLen + ZSTD_skippableHeaderSize;
@@ -857,50 +830,6 @@ static int basicUnitTests(U32 seed, double compressibility)
} }
DISPLAYLEVEL(4, "OK \n"); DISPLAYLEVEL(4, "OK \n");
DISPLAYLEVEL(4, "test%3i : Dictionary with non-default repcodes : ", testNb++);
{ U32 u; for (u=0; u<nbSamples; u++) samplesSizes[u] = sampleUnitSize; }
dictSize = ZDICT_trainFromBuffer(dictBuffer, dictSize,
CNBuffer, samplesSizes, nbSamples);
if (ZDICT_isError(dictSize)) goto _output_error;
/* Set all the repcodes to non-default */
{
BYTE* dictPtr = (BYTE*)dictBuffer;
BYTE* dictLimit = dictPtr + dictSize - 12;
/* Find the repcodes */
while (dictPtr < dictLimit &&
(MEM_readLE32(dictPtr) != 1 || MEM_readLE32(dictPtr + 4) != 4 ||
MEM_readLE32(dictPtr + 8) != 8)) {
++dictPtr;
}
if (dictPtr >= dictLimit) goto _output_error;
MEM_writeLE32(dictPtr + 0, 10);
MEM_writeLE32(dictPtr + 4, 10);
MEM_writeLE32(dictPtr + 8, 10);
/* Set the last 8 bytes to 'x' */
memset((BYTE*)dictBuffer + dictSize - 8, 'x', 8);
}
/* The optimal parser checks all the repcodes.
* Make sure at least one is a match >= targetLength so that it is
* immediately chosen. This will make sure that the compressor and
* decompressor agree on at least one of the repcodes.
*/
{ size_t dSize;
BYTE data[1024];
ZSTD_compressionParameters const cParams = ZSTD_getCParams(19, CNBuffSize, dictSize);
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictSize,
ZSTD_dlm_byRef, ZSTD_dm_auto,
cParams, ZSTD_defaultCMem);
memset(data, 'x', sizeof(data));
cSize = ZSTD_compress_usingCDict(cctx, compressedBuffer, compressedBufferSize,
data, sizeof(data), cdict);
ZSTD_freeCDict(cdict);
if (ZSTD_isError(cSize)) { DISPLAYLEVEL(5, "Compression error %s : ", ZSTD_getErrorName(cSize)); goto _output_error; }
dSize = ZSTD_decompress_usingDict(dctx, decodedBuffer, sizeof(data), compressedBuffer, cSize, dictBuffer, dictSize);
if (ZSTD_isError(dSize)) { DISPLAYLEVEL(5, "Decompression error %s : ", ZSTD_getErrorName(dSize)); goto _output_error; }
if (memcmp(data, decodedBuffer, sizeof(data))) { DISPLAYLEVEL(5, "Data corruption : "); goto _output_error; }
}
DISPLAYLEVEL(4, "OK \n");
ZSTD_freeCCtx(cctx); ZSTD_freeCCtx(cctx);
free(dictBuffer); free(dictBuffer);
free(samplesSizes); free(samplesSizes);
@@ -1271,8 +1200,8 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
U32 result = 0; U32 result = 0;
U32 testNb = 0; U32 testNb = 0;
U32 coreSeed = seed, lseed = 0; U32 coreSeed = seed, lseed = 0;
UTIL_time_t const startClock = UTIL_getTime(); clock_t const startClock = clock();
U64 const maxClockSpan = maxDurationS * SEC_TO_MICRO; clock_t const maxClockSpan = maxDurationS * CLOCKS_PER_SEC;
int const cLevelLimiter = bigTests ? 3 : 2; int const cLevelLimiter = bigTests ? 3 : 2;
/* allocation */ /* allocation */
@@ -1297,7 +1226,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD
for (testNb=1; testNb < startTest; testNb++) FUZ_rand(&coreSeed); for (testNb=1; testNb < startTest; testNb++) FUZ_rand(&coreSeed);
/* main test loop */ /* main test loop */
for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < maxClockSpan); testNb++ ) { for ( ; (testNb <= nbTests) || (FUZ_clockSpan(startClock) < maxClockSpan); testNb++ ) {
size_t sampleSize, maxTestSize, totalTestSize; size_t sampleSize, maxTestSize, totalTestSize;
size_t cSize, totalCSize, totalGenSize; size_t cSize, totalCSize, totalGenSize;
U64 crcOrig; U64 crcOrig;
+33 -35
View File
@@ -17,14 +17,13 @@
#include <stdio.h> /* fprintf, fopen, ftello64 */ #include <stdio.h> /* fprintf, fopen, ftello64 */
#include <string.h> /* strcmp */ #include <string.h> /* strcmp */
#include <math.h> /* log */ #include <math.h> /* log */
#include <time.h> #include <time.h> /* clock_t */
#include "mem.h" #include "mem.h"
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters, ZSTD_estimateCCtxSize */ #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters, ZSTD_estimateCCtxSize */
#include "zstd.h" #include "zstd.h"
#include "datagen.h" #include "datagen.h"
#include "xxhash.h" #include "xxhash.h"
#include "util.h"
/*-************************************ /*-************************************
@@ -40,7 +39,7 @@
#define GB *(1ULL<<30) #define GB *(1ULL<<30)
#define NBLOOPS 2 #define NBLOOPS 2
#define TIMELOOP (2 * SEC_TO_MICRO) #define TIMELOOP (2 * CLOCKS_PER_SEC)
#define NB_LEVELS_TRACKED 30 #define NB_LEVELS_TRACKED 30
@@ -50,8 +49,8 @@ static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t
static const size_t sampleSize = 10000000; static const size_t sampleSize = 10000000;
static const double g_grillDuration_s = 90000; /* about 24 hours */ static const double g_grillDuration_s = 90000; /* about 24 hours */
static const U64 g_maxParamTime = 15 * SEC_TO_MICRO; static const clock_t g_maxParamTime = 15 * CLOCKS_PER_SEC;
static const U64 g_maxVariationTime = 60 * SEC_TO_MICRO; static const clock_t g_maxVariationTime = 60 * CLOCKS_PER_SEC;
static const int g_maxNbVariations = 64; static const int g_maxNbVariations = 64;
@@ -89,9 +88,13 @@ void BMK_SetNbIterations(int nbLoops)
* Private functions * Private functions
*********************************************************/ *********************************************************/
/* works even if overflow ; max span ~ 30 mn */
static clock_t BMK_clockSpan(clock_t cStart) { return clock() - cStart; }
/* accuracy in seconds only, span can be multiple years */ /* accuracy in seconds only, span can be multiple years */
static double BMK_timeSpan(time_t tStart) { return difftime(time(NULL), tStart); } static double BMK_timeSpan(time_t tStart) { return difftime(time(NULL), tStart); }
static size_t BMK_findMaxMem(U64 requiredMem) static size_t BMK_findMaxMem(U64 requiredMem)
{ {
size_t const step = 64 MB; size_t const step = 64 MB;
@@ -218,7 +221,7 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr,
size_t cSize = 0; size_t cSize = 0;
double fastestC = 100000000., fastestD = 100000000.; double fastestC = 100000000., fastestD = 100000000.;
double ratio = 0.; double ratio = 0.;
UTIL_time_t const benchStart = UTIL_getTime(); clock_t const benchStart = clock();
DISPLAY("\r%79s\r", ""); DISPLAY("\r%79s\r", "");
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
@@ -226,10 +229,9 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr,
for (loopNb = 1; loopNb <= g_nbIterations; loopNb++) { for (loopNb = 1; loopNb <= g_nbIterations; loopNb++) {
int nbLoops; int nbLoops;
U32 blockNb; U32 blockNb;
UTIL_time_t roundStart; clock_t roundStart, roundClock;
U64 roundClock;
{ U64 const benchTime = UTIL_clockSpanMicro(benchStart); { clock_t const benchTime = BMK_clockSpan(benchStart);
if (benchTime > g_maxParamTime) break; } if (benchTime > g_maxParamTime) break; }
/* Compression */ /* Compression */
@@ -237,9 +239,10 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr,
memset(compressedBuffer, 0xE5, maxCompressedSize); memset(compressedBuffer, 0xE5, maxCompressedSize);
nbLoops = 0; nbLoops = 0;
UTIL_waitForNextTick(); roundStart = clock();
roundStart = UTIL_getTime(); while (clock() == roundStart);
while (UTIL_clockSpanMicro(roundStart) < TIMELOOP) { roundStart = clock();
while (BMK_clockSpan(roundStart) < TIMELOOP) {
for (blockNb=0; blockNb<nbBlocks; blockNb++) for (blockNb=0; blockNb<nbBlocks; blockNb++)
blockTable[blockNb].cSize = ZSTD_compress_advanced(ctx, blockTable[blockNb].cSize = ZSTD_compress_advanced(ctx,
blockTable[blockNb].cPtr, blockTable[blockNb].cRoom, blockTable[blockNb].cPtr, blockTable[blockNb].cRoom,
@@ -248,13 +251,13 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr,
params); params);
nbLoops++; nbLoops++;
} }
roundClock = UTIL_clockSpanMicro(roundStart); roundClock = BMK_clockSpan(roundStart);
cSize = 0; cSize = 0;
for (blockNb=0; blockNb<nbBlocks; blockNb++) for (blockNb=0; blockNb<nbBlocks; blockNb++)
cSize += blockTable[blockNb].cSize; cSize += blockTable[blockNb].cSize;
ratio = (double)srcSize / (double)cSize; ratio = (double)srcSize / (double)cSize;
if ((double)roundClock < fastestC * SEC_TO_MICRO * nbLoops) fastestC = ((double)roundClock / SEC_TO_MICRO) / nbLoops; if ((double)roundClock < fastestC * CLOCKS_PER_SEC * nbLoops) fastestC = ((double)roundClock / CLOCKS_PER_SEC) / nbLoops;
DISPLAY("\r"); DISPLAY("\r");
DISPLAY("%1u-%s : %9u ->", loopNb, name, (U32)srcSize); DISPLAY("%1u-%s : %9u ->", loopNb, name, (U32)srcSize);
DISPLAY(" %9u (%4.3f),%7.1f MB/s", (U32)cSize, ratio, (double)srcSize / fastestC / 1000000.); DISPLAY(" %9u (%4.3f),%7.1f MB/s", (U32)cSize, ratio, (double)srcSize / fastestC / 1000000.);
@@ -266,16 +269,17 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr,
memset(resultBuffer, 0xD6, srcSize); memset(resultBuffer, 0xD6, srcSize);
nbLoops = 0; nbLoops = 0;
UTIL_waitForNextTick(); roundStart = clock();
roundStart = UTIL_getTime(); while (clock() == roundStart);
for ( ; UTIL_clockSpanMicro(roundStart) < TIMELOOP; nbLoops++) { roundStart = clock();
for ( ; BMK_clockSpan(roundStart) < TIMELOOP; nbLoops++) {
for (blockNb=0; blockNb<nbBlocks; blockNb++) for (blockNb=0; blockNb<nbBlocks; blockNb++)
blockTable[blockNb].resSize = ZSTD_decompress(blockTable[blockNb].resPtr, blockTable[blockNb].srcSize, blockTable[blockNb].resSize = ZSTD_decompress(blockTable[blockNb].resPtr, blockTable[blockNb].srcSize,
blockTable[blockNb].cPtr, blockTable[blockNb].cSize); blockTable[blockNb].cPtr, blockTable[blockNb].cSize);
} }
roundClock = UTIL_clockSpanMicro(roundStart); roundClock = BMK_clockSpan(roundStart);
if ((double)roundClock < fastestD * SEC_TO_MICRO * nbLoops) fastestD = ((double)roundClock / SEC_TO_MICRO) / nbLoops; if ((double)roundClock < fastestD * CLOCKS_PER_SEC * nbLoops) fastestD = ((double)roundClock / CLOCKS_PER_SEC) / nbLoops;
DISPLAY("\r"); DISPLAY("\r");
DISPLAY("%1u-%s : %9u -> ", loopNb, name, (U32)srcSize); DISPLAY("%1u-%s : %9u -> ", loopNb, name, (U32)srcSize);
DISPLAY("%9u (%4.3f),%7.1f MB/s, ", (U32)cSize, ratio, (double)srcSize / fastestC / 1000000.); DISPLAY("%9u (%4.3f),%7.1f MB/s, ", (U32)cSize, ratio, (double)srcSize / fastestC / 1000000.);
@@ -306,10 +310,14 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr,
} }
const char* g_stratName[ZSTD_btultra+1] = { const char* g_stratName[] = { "ZSTD_fast ",
"(none) ", "ZSTD_fast ", "ZSTD_dfast ", "ZSTD_dfast ",
"ZSTD_greedy ", "ZSTD_lazy ", "ZSTD_lazy2 ", "ZSTD_greedy ",
"ZSTD_btlazy2 ", "ZSTD_btopt ", "ZSTD_btultra "}; "ZSTD_lazy ",
"ZSTD_lazy2 ",
"ZSTD_btlazy2 ",
"ZSTD_btopt ",
"ZSTD_btultra "};
static void BMK_printWinner(FILE* f, U32 cLevel, BMK_result_t result, ZSTD_compressionParameters params, size_t srcSize) static void BMK_printWinner(FILE* f, U32 cLevel, BMK_result_t result, ZSTD_compressionParameters params, size_t srcSize)
{ {
@@ -517,9 +525,9 @@ static void playAround(FILE* f, winnerInfo_t* winners,
ZSTD_CCtx* ctx) ZSTD_CCtx* ctx)
{ {
int nbVariations = 0; int nbVariations = 0;
UTIL_time_t const clockStart = UTIL_getTime(); clock_t const clockStart = clock();
while (UTIL_clockSpanMicro(clockStart) < g_maxVariationTime) { while (BMK_clockSpan(clockStart) < g_maxVariationTime) {
ZSTD_compressionParameters p = params; ZSTD_compressionParameters p = params;
if (nbVariations++ > g_maxNbVariations) break; if (nbVariations++ > g_maxNbVariations) break;
@@ -679,11 +687,6 @@ int benchFiles(const char** fileNamesTable, int nbFiles)
DISPLAY( "Pb opening %s\n", inFileName); DISPLAY( "Pb opening %s\n", inFileName);
return 11; return 11;
} }
if (inFileSize == UTIL_FILESIZE_UNKNOWN) {
DISPLAY("Pb evaluatin size of %s \n", inFileName);
fclose(inFile);
return 11;
}
/* Memory allocation */ /* Memory allocation */
benchedSize = BMK_findMaxMem(inFileSize*3) / 3; benchedSize = BMK_findMaxMem(inFileSize*3) / 3;
@@ -737,11 +740,6 @@ int optimizeForSize(const char* inFileName, U32 targetSpeed)
/* Init */ /* Init */
if (inFile==NULL) { DISPLAY( "Pb opening %s\n", inFileName); return 11; } if (inFile==NULL) { DISPLAY( "Pb opening %s\n", inFileName); return 11; }
if (inFileSize == UTIL_FILESIZE_UNKNOWN) {
DISPLAY("Pb evaluatin size of %s \n", inFileName);
fclose(inFile);
return 11;
}
/* Memory allocation & restrictions */ /* Memory allocation & restrictions */
if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize; if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
+56 -71
View File
@@ -5,6 +5,12 @@ die() {
exit 1 exit 1
} }
display_time()
{
echo -n "XXX"
date
}
roundTripTest() { roundTripTest() {
if [ -n "$3" ]; then if [ -n "$3" ]; then
cLevel="$3" cLevel="$3"
@@ -56,12 +62,10 @@ fi
isWindows=false isWindows=false
INTOVOID="/dev/null" INTOVOID="/dev/null"
DEVDEVICE="/dev/zero"
case "$OS" in case "$OS" in
Windows*) Windows*)
isWindows=true isWindows=true
INTOVOID="NUL" INTOVOID="NUL"
DEVDEVICE="NUL"
;; ;;
esac esac
@@ -93,7 +97,8 @@ else
hasMT="true" hasMT="true"
fi fi
$ECHO "\n===> simple tests " display_time
$ECHO "\n**** simple tests **** "
./datagen > tmp ./datagen > tmp
$ECHO "test : basic compression " $ECHO "test : basic compression "
@@ -126,10 +131,6 @@ $ZSTD -d > $INTOVOID && die "should have refused : compressed data from terminal
fi fi
$ECHO "test : null-length file roundtrip" $ECHO "test : null-length file roundtrip"
$ECHO -n '' | $ZSTD - --stdout | $ZSTD -d --stdout $ECHO -n '' | $ZSTD - --stdout | $ZSTD -d --stdout
$ECHO "test : ensure small file doesn't add 3-bytes null block"
./datagen -g1 > tmp1
$ZSTD tmp1 -c | wc -c | grep "14"
$ZSTD < tmp1 | wc -c | grep "14"
$ECHO "test : decompress file with wrong suffix (must fail)" $ECHO "test : decompress file with wrong suffix (must fail)"
$ZSTD -d tmpCompressed && die "wrong suffix error not detected!" $ZSTD -d tmpCompressed && die "wrong suffix error not detected!"
$ZSTD -df tmp && die "should have refused : wrong extension" $ZSTD -df tmp && die "should have refused : wrong extension"
@@ -165,36 +166,15 @@ $ZSTD -f --rm tmp
test ! -f tmp # tmp should no longer be present test ! -f tmp # tmp should no longer be present
$ZSTD -f -d --rm tmp.zst $ZSTD -f -d --rm tmp.zst
test ! -f tmp.zst # tmp.zst should no longer be present test ! -f tmp.zst # tmp.zst should no longer be present
$ECHO "test : should quietly not remove non-regular file"
$ECHO hello > tmp
$ZSTD tmp -f -o "$DEVDEVICE" 2>tmplog > "$INTOVOID"
grep -v "Refusing to remove non-regular file" tmplog
rm -f tmplog
$ZSTD tmp -f -o "$INTONULL" 2>&1 | grep -v "Refusing to remove non-regular file"
$ECHO "test : --rm on stdin" $ECHO "test : --rm on stdin"
$ECHO a | $ZSTD --rm > $INTOVOID # --rm should remain silent $ECHO a | $ZSTD --rm > $INTOVOID # --rm should remain silent
rm tmp rm tmp
$ZSTD -f tmp && die "tmp not present : should have failed" $ZSTD -f tmp && die "tmp not present : should have failed"
test ! -f tmp.zst # tmp.zst should not be created test ! -f tmp.zst # tmp.zst should not be created
$ECHO "test : compress multiple files"
$ECHO hello > tmp1
$ECHO world > tmp2
$ZSTD tmp1 tmp2 -o "$INTOVOID"
$ZSTD tmp1 tmp2 -c | $ZSTD -t
$ZSTD tmp1 tmp2 -o tmp.zst
test ! -f tmp1.zst
test ! -f tmp2.zst
$ZSTD tmp1 tmp2
$ZSTD -t tmp1.zst tmp2.zst
$ZSTD -dc tmp1.zst tmp2.zst
$ZSTD tmp1.zst tmp2.zst -o "$INTOVOID"
$ZSTD -d tmp1.zst tmp2.zst -o tmp
rm tmp*
display_time
$ECHO "\n**** Advanced compression parameters **** "
$ECHO "\n===> Advanced compression parameters "
$ECHO "Hello world!" | $ZSTD --zstd=windowLog=21, - -o tmp.zst && die "wrong parameters not detected!" $ECHO "Hello world!" | $ZSTD --zstd=windowLog=21, - -o tmp.zst && die "wrong parameters not detected!"
$ECHO "Hello world!" | $ZSTD --zstd=windowLo=21 - -o tmp.zst && die "wrong parameters not detected!" $ECHO "Hello world!" | $ZSTD --zstd=windowLo=21 - -o tmp.zst && die "wrong parameters not detected!"
$ECHO "Hello world!" | $ZSTD --zstd=windowLog=21,slog - -o tmp.zst && die "wrong parameters not detected!" $ECHO "Hello world!" | $ZSTD --zstd=windowLog=21,slog - -o tmp.zst && die "wrong parameters not detected!"
@@ -208,14 +188,14 @@ roundTripTest -g512K " --long --zstd=ldmhlog=20,ldmslen=64,ldmblog=1,ldmhevery=7
roundTripTest -g512K 19 roundTripTest -g512K 19
$ECHO "\n===> Pass-Through mode " $ECHO "\n**** Pass-Through mode **** "
$ECHO "Hello world 1!" | $ZSTD -df $ECHO "Hello world 1!" | $ZSTD -df
$ECHO "Hello world 2!" | $ZSTD -dcf $ECHO "Hello world 2!" | $ZSTD -dcf
$ECHO "Hello world 3!" > tmp1 $ECHO "Hello world 3!" > tmp1
$ZSTD -dcf tmp1 $ZSTD -dcf tmp1
$ECHO "\n===> frame concatenation " $ECHO "\n**** frame concatenation **** "
$ECHO "hello " > hello.tmp $ECHO "hello " > hello.tmp
$ECHO "world!" > world.tmp $ECHO "world!" > world.tmp
@@ -246,7 +226,7 @@ $ECHO "$ECHO foo | $ZSTD | $ZSTD -d > /dev/full"
$ECHO foo | $ZSTD | $ZSTD -d > /dev/full && die "write error not detected!" $ECHO foo | $ZSTD | $ZSTD -d > /dev/full && die "write error not detected!"
$ECHO "\n===> symbolic link test " $ECHO "\n**** symbolic link test **** "
rm -f hello.tmp world.tmp hello.tmp.zst world.tmp.zst rm -f hello.tmp world.tmp hello.tmp.zst world.tmp.zst
$ECHO "hello world" > hello.tmp $ECHO "hello world" > hello.tmp
@@ -261,7 +241,8 @@ rm -f hello.tmp world.tmp hello.tmp.zst world.tmp.zst
fi fi
$ECHO "\n===> test sparse file support " display_time
$ECHO "\n**** test sparse file support **** "
./datagen -g5M -P100 > tmpSparse ./datagen -g5M -P100 > tmpSparse
$ZSTD tmpSparse -c | $ZSTD -dv -o tmpSparseRegen $ZSTD tmpSparse -c | $ZSTD -dv -o tmpSparseRegen
@@ -288,7 +269,7 @@ $DIFF tmpSparse2M tmpSparseRegenerated
rm tmpSparse* rm tmpSparse*
$ECHO "\n===> multiple files tests " $ECHO "\n**** multiple files tests **** "
./datagen -s1 > tmp1 2> $INTOVOID ./datagen -s1 > tmp1 2> $INTOVOID
./datagen -s2 -g100K > tmp2 2> $INTOVOID ./datagen -s2 -g100K > tmp2 2> $INTOVOID
@@ -311,7 +292,7 @@ $ECHO "compress multiple files including a missing one (notHere) : "
$ZSTD -f tmp1 notHere tmp2 && die "missing file not detected!" $ZSTD -f tmp1 notHere tmp2 && die "missing file not detected!"
$ECHO "\n===> dictionary tests " $ECHO "\n**** dictionary tests **** "
$ECHO "- test with raw dict (content only) " $ECHO "- test with raw dict (content only) "
./datagen > tmpDict ./datagen > tmpDict
@@ -325,11 +306,6 @@ cp $TESTFILE tmp
$ZSTD -f tmp -D tmpDict $ZSTD -f tmp -D tmpDict
$ZSTD -d tmp.zst -D tmpDict -fo result $ZSTD -d tmp.zst -D tmpDict -fo result
$DIFF $TESTFILE result $DIFF $TESTFILE result
if [ -n "$hasMT" ]
then
$ECHO "- Test dictionary compression with multithreading "
./datagen -g5M | $ZSTD -T2 -D tmpDict | $ZSTD -t -D tmpDict # fails with v1.3.2
fi
$ECHO "- Create second (different) dictionary " $ECHO "- Create second (different) dictionary "
$ZSTD --train *.c ../programs/*.c ../programs/*.h -o tmpDictC $ZSTD --train *.c ../programs/*.c ../programs/*.h -o tmpDictC
$ZSTD -d tmp.zst -D tmpDictC -fo result && die "wrong dictionary not detected!" $ZSTD -d tmp.zst -D tmpDictC -fo result && die "wrong dictionary not detected!"
@@ -372,7 +348,8 @@ $ZSTD --train-legacy -q tmp && die "Dictionary training should fail : source is
rm tmp* rm tmp*
$ECHO "\n===> cover dictionary builder : advanced options " display_time
$ECHO "\n**** cover dictionary tests **** "
TESTFILE=../programs/zstdcli.c TESTFILE=../programs/zstdcli.c
./datagen > tmpDict ./datagen > tmpDict
@@ -392,7 +369,7 @@ $ECHO "- Create dictionary with size limit"
$ZSTD --train-cover=steps=8 *.c ../programs/*.c -o tmpDict2 --maxdict=4K $ZSTD --train-cover=steps=8 *.c ../programs/*.c -o tmpDict2 --maxdict=4K
rm tmp* rm tmp*
$ECHO "\n===> legacy dictionary builder " $ECHO "\n**** legacy dictionary tests **** "
TESTFILE=../programs/zstdcli.c TESTFILE=../programs/zstdcli.c
./datagen > tmpDict ./datagen > tmpDict
@@ -413,7 +390,7 @@ $ZSTD --train-legacy -s9 *.c ../programs/*.c -o tmpDict2 --maxdict=4K
rm tmp* rm tmp*
$ECHO "\n===> integrity tests " $ECHO "\n**** integrity tests **** "
$ECHO "test one file (tmp1.zst) " $ECHO "test one file (tmp1.zst) "
./datagen > tmp1 ./datagen > tmp1
@@ -438,13 +415,14 @@ $ZSTD -t tmpSplit.* && die "bad file not detected !"
$ECHO "\n===> golden files tests " $ECHO "\n**** golden files tests **** "
$ZSTD -t -r files $ZSTD -t -r files
$ZSTD -c -r files | $ZSTD -t $ZSTD -c -r files | $ZSTD -t
$ECHO "\n===> benchmark mode tests " display_time
$ECHO "\n**** benchmark mode tests **** "
$ECHO "bench one file" $ECHO "bench one file"
./datagen > tmp1 ./datagen > tmp1
@@ -455,7 +433,7 @@ $ECHO "with recursive and quiet modes"
$ZSTD -rqi1b1e2 tmp1 $ZSTD -rqi1b1e2 tmp1
$ECHO "\n===> gzip compatibility tests " $ECHO "\n**** gzip compatibility tests **** "
GZIPMODE=1 GZIPMODE=1
$ZSTD --format=gzip -V || GZIPMODE=0 $ZSTD --format=gzip -V || GZIPMODE=0
@@ -478,7 +456,7 @@ else
fi fi
$ECHO "\n===> gzip frame tests " $ECHO "\n**** gzip frame tests **** "
if [ $GZIPMODE -eq 1 ]; then if [ $GZIPMODE -eq 1 ]; then
./datagen > tmp ./datagen > tmp
@@ -492,7 +470,7 @@ else
fi fi
$ECHO "\n===> xz compatibility tests " $ECHO "\n**** xz compatibility tests **** "
LZMAMODE=1 LZMAMODE=1
$ZSTD --format=xz -V || LZMAMODE=0 $ZSTD --format=xz -V || LZMAMODE=0
@@ -538,7 +516,8 @@ else
fi fi
$ECHO "\n===> xz frame tests " display_time
$ECHO "\n**** xz frame tests **** "
if [ $LZMAMODE -eq 1 ]; then if [ $LZMAMODE -eq 1 ]; then
./datagen > tmp ./datagen > tmp
@@ -553,7 +532,7 @@ else
$ECHO "xz mode not supported" $ECHO "xz mode not supported"
fi fi
$ECHO "\n===> lz4 compatibility tests " $ECHO "\n**** lz4 compatibility tests **** "
LZ4MODE=1 LZ4MODE=1
$ZSTD --format=lz4 -V || LZ4MODE=0 $ZSTD --format=lz4 -V || LZ4MODE=0
@@ -576,7 +555,7 @@ else
fi fi
$ECHO "\n===> lz4 frame tests " $ECHO "\n**** lz4 frame tests **** "
if [ $LZ4MODE -eq 1 ]; then if [ $LZ4MODE -eq 1 ]; then
./datagen > tmp ./datagen > tmp
@@ -589,7 +568,7 @@ else
$ECHO "lz4 mode not supported" $ECHO "lz4 mode not supported"
fi fi
$ECHO "\n===> zstd round-trip tests " $ECHO "\n**** zstd round-trip tests **** "
roundTripTest roundTripTest
roundTripTest -g15K # TableID==3 roundTripTest -g15K # TableID==3
@@ -602,7 +581,8 @@ roundTripTest -g516K 19 # btopt
fileRoundTripTest -g500K fileRoundTripTest -g500K
$ECHO "\n===> zstd long distance matching round-trip tests " display_time
$ECHO "\n**** zstd long distance matching round-trip tests **** "
roundTripTest -g0 "2 --long" roundTripTest -g0 "2 --long"
roundTripTest -g1000K "1 --long" roundTripTest -g1000K "1 --long"
roundTripTest -g517K "6 --long" roundTripTest -g517K "6 --long"
@@ -613,56 +593,58 @@ fileRoundTripTest -g5M "3 --long"
if [ -n "$hasMT" ] if [ -n "$hasMT" ]
then then
$ECHO "\n===> zstdmt round-trip tests " $ECHO "\n**** zstdmt round-trip tests **** "
roundTripTest -g4M "1 -T0" roundTripTest -g4M "1 -T0"
roundTripTest -g8M "3 -T2" roundTripTest -g8M "3 -T2"
roundTripTest -g8000K "2 --threads=2" roundTripTest -g8000K "2 --threads=2"
fileRoundTripTest -g4M "19 -T2 -B1M" fileRoundTripTest -g4M "19 -T2 -B1M"
$ECHO "\n===> zstdmt long distance matching round-trip tests " $ECHO "\n**** zstdmt long distance matching round-trip tests **** "
roundTripTest -g8M "3 --long -T2" roundTripTest -g8M "3 --long -T2"
else else
$ECHO "\n===> no multithreading, skipping zstdmt tests " $ECHO "\n**** no multithreading, skipping zstdmt tests **** "
fi fi
rm tmp* rm tmp*
$ECHO "\n===> zstd --list/-l single frame tests " $ECHO "\n**** zstd --list/-l single frame tests ****"
./datagen > tmp1 ./datagen > tmp1
./datagen > tmp2 ./datagen > tmp2
./datagen > tmp3 ./datagen > tmp3
$ZSTD tmp* $ZSTD tmp*
$ZSTD -l *.zst $ZSTD -l *.zst
$ZSTD -lv *.zst | grep "Decompressed Size:" # check that decompressed size is present in header $ZSTD -lv *.zst
$ZSTD --list *.zst $ZSTD --list *.zst
$ZSTD --list -v *.zst $ZSTD --list -v *.zst
$ECHO "\n===> zstd --list/-l multiple frame tests " $ECHO "\n**** zstd --list/-l multiple frame tests ****"
cat tmp1.zst tmp2.zst > tmp12.zst cat tmp1.zst tmp2.zst > tmp12.zst
cat tmp12.zst tmp3.zst > tmp123.zst cat tmp12.zst tmp3.zst > tmp123.zst
$ZSTD -l *.zst $ZSTD -l *.zst
$ZSTD -lv *.zst $ZSTD -lv *.zst
$ZSTD --list *.zst
$ZSTD --list -v *.zst
$ECHO "\n===> zstd --list/-l error detection tests " $ECHO "\n**** zstd --list/-l error detection tests ****"
! $ZSTD -l tmp1 tmp1.zst ! $ZSTD -l tmp1 tmp1.zst
! $ZSTD --list tmp* ! $ZSTD --list tmp*
! $ZSTD -lv tmp1* ! $ZSTD -lv tmp1*
! $ZSTD --list -v tmp2 tmp12.zst ! $ZSTD --list -v tmp2 tmp12.zst
$ECHO "\n===> zstd --list/-l test with null files " $ECHO "\n**** zstd --list/-l test with null files ****"
./datagen -g0 > tmp5 ./datagen -g0 > tmp5
$ZSTD tmp5 $ZSTD tmp5
$ZSTD -l tmp5.zst $ZSTD -l tmp5.zst
! $ZSTD -l tmp5* ! $ZSTD -l tmp5*
$ZSTD -lv tmp5.zst | grep "Decompressed Size: 0.00 KB (0 B)" # check that 0 size is present in header $ZSTD -lv tmp5.zst
! $ZSTD -lv tmp5* ! $ZSTD -lv tmp5*
$ECHO "\n===> zstd --list/-l test with no content size field " $ECHO "\n**** zstd --list/-l test with no content size field ****"
./datagen -g513K | $ZSTD > tmp6.zst ./datagen -g1MB | $ZSTD > tmp6.zst
$ZSTD -l tmp6.zst $ZSTD -l tmp6.zst
! $ZSTD -lv tmp6.zst | grep "Decompressed Size:" # must NOT be present in header $ZSTD -lv tmp6.zst
$ECHO "\n===> zstd --list/-l test with no checksum " $ECHO "\n**** zstd --list/-l test with no checksum ****"
$ZSTD -f --no-check tmp1 $ZSTD -f --no-check tmp1
$ZSTD -l tmp1.zst $ZSTD -l tmp1.zst
$ZSTD -lv tmp1.zst $ZSTD -lv tmp1.zst
@@ -670,7 +652,8 @@ $ZSTD -lv tmp1.zst
rm tmp* rm tmp*
$ECHO "\n===> zstd long distance matching tests " display_time
$ECHO "\n**** zstd long distance matching tests **** "
roundTripTest -g0 " --long" roundTripTest -g0 " --long"
roundTripTest -g9M "2 --long" roundTripTest -g9M "2 --long"
# Test parameter parsing # Test parameter parsing
@@ -685,7 +668,8 @@ if [ "$1" != "--test-large-data" ]; then
exit 0 exit 0
fi fi
$ECHO "\n===> large files tests " display_time
$ECHO "\n**** large files tests **** "
roundTripTest -g270000000 1 roundTripTest -g270000000 1
roundTripTest -g250000000 2 roundTripTest -g250000000 2
@@ -716,7 +700,7 @@ roundTripTest -g5000000000 -P99 1
fileRoundTripTest -g4193M -P99 1 fileRoundTripTest -g4193M -P99 1
$ECHO "\n===> zstd long, long distance matching round-trip tests " $ECHO "\n**** zstd long, long distance matching round-trip tests **** "
roundTripTest -g270000000 "1 --long" roundTripTest -g270000000 "1 --long"
roundTripTest -g130000000 -P60 "5 --long" roundTripTest -g130000000 -P60 "5 --long"
roundTripTest -g35000000 -P70 "8 --long" roundTripTest -g35000000 -P70 "8 --long"
@@ -726,9 +710,10 @@ roundTripTest -g700M -P50 "1 --long=29"
roundTripTest -g600M -P50 "1 --long --zstd=wlog=29,clog=28" roundTripTest -g600M -P50 "1 --long --zstd=wlog=29,clog=28"
display_time
if [ -n "$hasMT" ] if [ -n "$hasMT" ]
then then
$ECHO "\n===> zstdmt long round-trip tests " $ECHO "\n**** zstdmt long round-trip tests **** "
roundTripTest -g80000000 -P99 "19 -T2" " " roundTripTest -g80000000 -P99 "19 -T2" " "
roundTripTest -g5000000000 -P99 "1 -T2" " " roundTripTest -g5000000000 -P99 "1 -T2" " "
roundTripTest -g500000000 -P97 "1 -T999" " " roundTripTest -g500000000 -P97 "1 -T999" " "
-260
View File
@@ -1,260 +0,0 @@
/*
* Copyright (c) 2017-present, Facebook, Inc.
* 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 "seqgen.h"
#include "mem.h"
#include <string.h>
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static const size_t kMatchBytes = 128;
#define SEQ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
static BYTE SEQ_randByte(U32* src)
{
static const U32 prime1 = 2654435761U;
static const U32 prime2 = 2246822519U;
U32 rand32 = *src;
rand32 *= prime1;
rand32 ^= prime2;
rand32 = SEQ_rotl32(rand32, 13);
*src = rand32;
return (BYTE)(rand32 >> 5);
}
SEQ_stream SEQ_initStream(unsigned seed)
{
SEQ_stream stream;
stream.state = 0;
XXH64_reset(&stream.xxh, 0);
stream.seed = seed;
return stream;
}
/* Generates a single guard byte, then match length + 1 of a different byte,
* then another guard byte.
*/
static size_t SEQ_gen_matchLength(SEQ_stream* stream, unsigned value,
SEQ_outBuffer* out)
{
typedef enum {
ml_first_byte = 0,
ml_match_bytes,
ml_last_byte,
} ml_state;
BYTE* const ostart = (BYTE*)out->dst;
BYTE* const oend = ostart + out->size;
BYTE* op = ostart + out->pos;
switch ((ml_state)stream->state) {
case ml_first_byte:
/* Generate a single byte and pick a different byte for the match */
if (op >= oend) {
stream->bytesLeft = 1;
break;
}
*op = SEQ_randByte(&stream->seed) & 0xFF;
do {
stream->saved = SEQ_randByte(&stream->seed) & 0xFF;
} while (*op == stream->saved);
++op;
/* State transition */
stream->state = ml_match_bytes;
stream->bytesLeft = value + 1;
/* fall-through */
case ml_match_bytes: {
/* Copy matchLength + 1 bytes to the output buffer */
size_t const setLength = MIN(stream->bytesLeft, (size_t)(oend - op));
if (setLength > 0) {
memset(op, stream->saved, setLength);
op += setLength;
stream->bytesLeft -= setLength;
}
if (stream->bytesLeft > 0)
break;
/* State transition */
stream->state = ml_last_byte;
}
/* fall-through */
case ml_last_byte:
/* Generate a single byte and pick a different byte for the match */
if (op >= oend) {
stream->bytesLeft = 1;
break;
}
do {
*op = SEQ_randByte(&stream->seed) & 0xFF;
} while (*op == stream->saved);
++op;
/* State transition */
/* fall-through */
default:
stream->state = 0;
stream->bytesLeft = 0;
break;
}
XXH64_update(&stream->xxh, ostart + out->pos, (op - ostart) - out->pos);
out->pos = op - ostart;
return stream->bytesLeft;
}
/* Saves the current seed then generates kMatchBytes random bytes >= 128.
* Generates literal length - kMatchBytes random bytes < 128.
* Generates another kMatchBytes using the saved seed to generate a match.
* This way the match is easy to find for the compressors.
*/
static size_t SEQ_gen_litLength(SEQ_stream* stream, unsigned value, SEQ_outBuffer* out)
{
typedef enum {
ll_start = 0,
ll_run_bytes,
ll_literals,
ll_run_match,
} ll_state;
BYTE* const ostart = (BYTE*)out->dst;
BYTE* const oend = ostart + out->size;
BYTE* op = ostart + out->pos;
switch ((ll_state)stream->state) {
case ll_start:
stream->state = ll_run_bytes;
stream->saved = stream->seed;
stream->bytesLeft = MIN(kMatchBytes, value);
/* fall-through */
case ll_run_bytes:
while (stream->bytesLeft > 0 && op < oend) {
*op++ = SEQ_randByte(&stream->seed) | 0x80;
--stream->bytesLeft;
}
if (stream->bytesLeft > 0)
break;
/* State transition */
stream->state = ll_literals;
stream->bytesLeft = value - MIN(kMatchBytes, value);
/* fall-through */
case ll_literals:
while (stream->bytesLeft > 0 && op < oend) {
*op++ = SEQ_randByte(&stream->seed) & 0x7F;
--stream->bytesLeft;
}
if (stream->bytesLeft > 0)
break;
/* State transition */
stream->state = ll_run_match;
stream->bytesLeft = MIN(kMatchBytes, value);
/* fall-through */
case ll_run_match: {
while (stream->bytesLeft > 0 && op < oend) {
*op++ = SEQ_randByte(&stream->saved) | 0x80;
--stream->bytesLeft;
}
if (stream->bytesLeft > 0)
break;
}
/* fall-through */
default:
stream->state = 0;
stream->bytesLeft = 0;
break;
}
XXH64_update(&stream->xxh, ostart + out->pos, (op - ostart) - out->pos);
out->pos = op - ostart;
return stream->bytesLeft;
}
/* Saves the current seed then generates kMatchBytes random bytes >= 128.
* Generates offset - kMatchBytes of zeros to get a large offset without
* polluting the hash tables.
* Generates another kMatchBytes using the saved seed to generate a with the
* required offset.
*/
static size_t SEQ_gen_offset(SEQ_stream* stream, unsigned value, SEQ_outBuffer* out)
{
typedef enum {
of_start = 0,
of_run_bytes,
of_offset,
of_run_match,
} of_state;
BYTE* const ostart = (BYTE*)out->dst;
BYTE* const oend = ostart + out->size;
BYTE* op = ostart + out->pos;
switch ((of_state)stream->state) {
case of_start:
stream->state = of_run_bytes;
stream->saved = stream->seed;
stream->bytesLeft = MIN(value, kMatchBytes);
/* fall-through */
case of_run_bytes: {
while (stream->bytesLeft > 0 && op < oend) {
*op++ = SEQ_randByte(&stream->seed) | 0x80;
--stream->bytesLeft;
}
if (stream->bytesLeft > 0)
break;
/* State transition */
stream->state = of_offset;
stream->bytesLeft = value - MIN(value, kMatchBytes);
}
/* fall-through */
case of_offset: {
/* Copy matchLength + 1 bytes to the output buffer */
size_t const setLength = MIN(stream->bytesLeft, (size_t)(oend - op));
if (setLength > 0) {
memset(op, 0, setLength);
op += setLength;
stream->bytesLeft -= setLength;
}
if (stream->bytesLeft > 0)
break;
/* State transition */
stream->state = of_run_match;
stream->bytesLeft = MIN(value, kMatchBytes);
}
/* fall-through */
case of_run_match: {
while (stream->bytesLeft > 0 && op < oend) {
*op++ = SEQ_randByte(&stream->saved) | 0x80;
--stream->bytesLeft;
}
if (stream->bytesLeft > 0)
break;
}
/* fall-through */
default:
stream->state = 0;
stream->bytesLeft = 0;
break;
}
XXH64_update(&stream->xxh, ostart + out->pos, (op - ostart) - out->pos);
out->pos = op - ostart;
return stream->bytesLeft;
}
/* Returns the number of bytes left to generate.
* Must pass the same type/value until it returns 0.
*/
size_t SEQ_gen(SEQ_stream* stream, SEQ_gen_type type, unsigned value, SEQ_outBuffer* out)
{
switch (type) {
case SEQ_gen_ml: return SEQ_gen_matchLength(stream, value, out);
case SEQ_gen_ll: return SEQ_gen_litLength(stream, value, out);
case SEQ_gen_of: return SEQ_gen_offset(stream, value, out);
case SEQ_gen_max: /* fall-through */
default: return 0;
}
}
/* Returns the xxhash of the data produced so far */
XXH64_hash_t SEQ_digest(SEQ_stream const* stream)
{
return XXH64_digest(&stream->xxh);
}
-58
View File
@@ -1,58 +0,0 @@
/*
* Copyright (c) 2017-present, Facebook, Inc.
* 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.
*/
#ifndef SEQGEN_H
#define SEQGEN_H
#define XXH_STATIC_LINKING_ONLY
#include "xxhash.h"
#include <stddef.h> /* size_t */
typedef enum {
SEQ_gen_ml = 0,
SEQ_gen_ll,
SEQ_gen_of,
SEQ_gen_max /* Must be the last value */
} SEQ_gen_type;
/* Internal state, do not use */
typedef struct {
XXH64_state_t xxh; /* xxh state for all the data produced so far (seed=0) */
unsigned seed;
int state; /* enum to control state machine (clean=0) */
unsigned saved;
size_t bytesLeft;
} SEQ_stream;
SEQ_stream SEQ_initStream(unsigned seed);
typedef struct {
void* dst;
size_t size;
size_t pos;
} SEQ_outBuffer;
/* Returns non-zero until the current type/value has been generated.
* Must pass the same type/value until it returns 0.
*
* Recommended to pick a value in the middle of the range you want, since there
* may be some noise that causes actual results to be slightly different.
* We try to be more accurate for smaller values.
*
* NOTE: Very small values don't work well (< 6).
*/
size_t SEQ_gen(SEQ_stream* stream, SEQ_gen_type type, unsigned value,
SEQ_outBuffer* out);
/* Returns the xxhash of the data produced so far */
XXH64_hash_t SEQ_digest(SEQ_stream const* stream);
#endif /* SEQGEN_H */
+18 -14
View File
@@ -24,6 +24,7 @@
**************************************/ **************************************/
#include <stdlib.h> /* free */ #include <stdlib.h> /* free */
#include <stdio.h> /* fgets, sscanf */ #include <stdio.h> /* fgets, sscanf */
#include <time.h> /* clock_t, clock() */
#include <string.h> /* strcmp */ #include <string.h> /* strcmp */
#include "mem.h" #include "mem.h"
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel */ #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel */
@@ -33,7 +34,6 @@
#include "datagen.h" /* RDG_genBuffer */ #include "datagen.h" /* RDG_genBuffer */
#define XXH_STATIC_LINKING_ONLY #define XXH_STATIC_LINKING_ONLY
#include "xxhash.h" /* XXH64_* */ #include "xxhash.h" /* XXH64_* */
#include "util.h"
/*-************************************ /*-************************************
@@ -58,24 +58,26 @@ static const U32 prime2 = 2246822519U;
#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
static U32 g_displayLevel = 2; static U32 g_displayLevel = 2;
static const U64 g_refreshRate = SEC_TO_MICRO / 6;
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \ if ((FUZ_GetClockSpan(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \ { g_displayClock = clock(); DISPLAY(__VA_ARGS__); \
if (g_displayLevel>=4) fflush(stderr); } } if (g_displayLevel>=4) fflush(stderr); } }
static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100;
static clock_t g_displayClock = 0;
static U64 g_clockTime = 0; static clock_t g_clockTime = 0;
/*-******************************************************* /*-*******************************************************
* Fuzzer functions * Fuzzer functions
*********************************************************/ *********************************************************/
#undef MIN
#undef MAX
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b))
static clock_t FUZ_GetClockSpan(clock_t clockStart)
{
return clock() - clockStart; /* works even when overflow. Max span ~ 30 mn */
}
/*! FUZ_rand() : /*! FUZ_rand() :
@return : a 27 bits random value, from a 32-bits `seed`. @return : a 27 bits random value, from a 32-bits `seed`.
`seed` is also modified */ `seed` is also modified */
@@ -254,6 +256,8 @@ static size_t FUZ_randomLength(U32* seed, U32 maxLog)
return FUZ_rLogLength(seed, logLength); return FUZ_rLogLength(seed, logLength);
} }
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
#define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \ #define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; } DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; }
@@ -274,7 +278,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
U32 coreSeed = seed; U32 coreSeed = seed;
ZBUFF_CCtx* zc; ZBUFF_CCtx* zc;
ZBUFF_DCtx* zd; ZBUFF_DCtx* zd;
UTIL_time_t startClock = UTIL_getTime(); clock_t startClock = clock();
/* allocations */ /* allocations */
zc = ZBUFF_createCCtx(); zc = ZBUFF_createCCtx();
@@ -304,7 +308,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
FUZ_rand(&coreSeed); FUZ_rand(&coreSeed);
/* test loop */ /* test loop */
for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) { for ( ; (testNb <= nbTests) || (FUZ_GetClockSpan(startClock) < g_clockTime) ; testNb++ ) {
U32 lseed; U32 lseed;
const BYTE* srcBuffer; const BYTE* srcBuffer;
const BYTE* dict; const BYTE* dict;
@@ -353,7 +357,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
{ ZSTD_parameters params = ZSTD_getParams(cLevel, 0, dictSize); { ZSTD_parameters params = ZSTD_getParams(cLevel, 0, dictSize);
params.fParams.checksumFlag = FUZ_rand(&lseed) & 1; params.fParams.checksumFlag = FUZ_rand(&lseed) & 1;
params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1; params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1;
{ size_t const initError = ZBUFF_compressInit_advanced(zc, dict, dictSize, params, ZSTD_CONTENTSIZE_UNKNOWN); { size_t const initError = ZBUFF_compressInit_advanced(zc, dict, dictSize, params, 0);
CHECK (ZBUFF_isError(initError),"init error : %s", ZBUFF_getErrorName(initError)); CHECK (ZBUFF_isError(initError),"init error : %s", ZBUFF_getErrorName(initError));
} } } } } }
@@ -544,7 +548,7 @@ int main(int argc, const char** argv)
} }
if (*argument=='m') g_clockTime *=60, argument++; if (*argument=='m') g_clockTime *=60, argument++;
if (*argument=='n') argument++; if (*argument=='n') argument++;
g_clockTime *= SEC_TO_MICRO; g_clockTime *= CLOCKS_PER_SEC;
break; break;
case 's': case 's':
+99 -280
View File
@@ -24,6 +24,7 @@
**************************************/ **************************************/
#include <stdlib.h> /* free */ #include <stdlib.h> /* free */
#include <stdio.h> /* fgets, sscanf */ #include <stdio.h> /* fgets, sscanf */
#include <time.h> /* clock_t, clock() */
#include <string.h> /* strcmp */ #include <string.h> /* strcmp */
#include <assert.h> /* assert */ #include <assert.h> /* assert */
#include "mem.h" #include "mem.h"
@@ -35,8 +36,6 @@
#include "datagen.h" /* RDG_genBuffer */ #include "datagen.h" /* RDG_genBuffer */
#define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ #define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
#include "xxhash.h" /* XXH64_* */ #include "xxhash.h" /* XXH64_* */
#include "seqgen.h"
#include "util.h"
/*-************************************ /*-************************************
@@ -62,24 +61,26 @@ static const U32 prime32 = 2654435761U;
if (g_displayLevel>=4) fflush(stderr); } if (g_displayLevel>=4) fflush(stderr); }
static U32 g_displayLevel = 2; static U32 g_displayLevel = 2;
static const U64 g_refreshRate = SEC_TO_MICRO / 6;
static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \ if ((FUZ_GetClockSpan(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
{ g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \ { g_displayClock = clock(); DISPLAY(__VA_ARGS__); \
if (g_displayLevel>=4) fflush(stderr); } } if (g_displayLevel>=4) fflush(stderr); } }
static const clock_t g_refreshRate = CLOCKS_PER_SEC / 6;
static clock_t g_displayClock = 0;
static U64 g_clockTime = 0; static clock_t g_clockTime = 0;
/*-******************************************************* /*-*******************************************************
* Fuzzer functions * Fuzzer functions
*********************************************************/ *********************************************************/
#undef MIN
#undef MAX
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b))
static clock_t FUZ_GetClockSpan(clock_t clockStart)
{
return clock() - clockStart; /* works even when overflow. Max span ~ 30 mn */
}
/*! FUZ_rand() : /*! FUZ_rand() :
@return : a 27 bits random value, from a 32-bits `seed`. @return : a 27 bits random value, from a 32-bits `seed`.
`seed` is also modified */ `seed` is also modified */
@@ -95,20 +96,14 @@ unsigned int FUZ_rand(unsigned int* seedPtr)
return rand32 >> 5; return rand32 >> 5;
} }
#define CHECK(cond, ...) { \
if (cond) { \
DISPLAY("Error => "); \
DISPLAY(__VA_ARGS__); \
DISPLAY(" (seed %u, test nb %u, line %u) \n", \
seed, testNb, __LINE__); \
goto _output_error; \
} }
#define CHECK_Z(f) { \ #define CHECK_Z(f) { \
size_t const err = f; \ size_t const err = f; \
CHECK(ZSTD_isError(err), "%s : %s ", \ if (ZSTD_isError(err)) { \
#f, ZSTD_getErrorName(err)); \ DISPLAY("Error => %s : %s ", \
} #f, ZSTD_getErrorName(err)); \
DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); \
goto _output_error; \
} }
/*====================================================== /*======================================================
@@ -149,69 +144,12 @@ static void FUZ_freeDictionary(buffer_t dict)
free(dict.start); free(dict.start);
} }
/* Round trips data and updates xxh with the decompressed data produced */
static size_t SEQ_roundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
XXH64_state_t* xxh, void* data, size_t size,
ZSTD_EndDirective endOp)
{
static BYTE compressed[1024];
static BYTE uncompressed[1024];
ZSTD_inBuffer cin = {data, size, 0}; static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem customMem)
size_t cret;
do {
ZSTD_outBuffer cout = {compressed, sizeof(compressed), 0};
ZSTD_inBuffer din = {compressed, 0, 0};
ZSTD_outBuffer dout = {uncompressed, 0, 0};
cret = ZSTD_compress_generic(cctx, &cout, &cin, endOp);
if (ZSTD_isError(cret))
return cret;
din.size = cout.pos;
while (din.pos < din.size || (endOp == ZSTD_e_end && cret == 0)) {
size_t dret;
dout.pos = 0;
dout.size = sizeof(uncompressed);
dret = ZSTD_decompressStream(dctx, &dout, &din);
if (ZSTD_isError(dret))
return dret;
XXH64_update(xxh, dout.dst, dout.pos);
if (dret == 0)
break;
}
} while (cin.pos < cin.size || (endOp != ZSTD_e_continue && cret != 0));
return 0;
}
/* Generates some data and round trips it */
static size_t SEQ_generateRoundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
XXH64_state_t* xxh, SEQ_stream* seq,
SEQ_gen_type type, unsigned value)
{
static BYTE data[1024];
size_t gen;
do {
SEQ_outBuffer sout = {data, sizeof(data), 0};
size_t ret;
gen = SEQ_gen(seq, type, value, &sout);
ret = SEQ_roundTrip(cctx, dctx, xxh, sout.dst, sout.pos, ZSTD_e_continue);
if (ZSTD_isError(ret))
return ret;
} while (gen != 0);
return 0;
}
static int basicUnitTests(U32 seed, double compressibility)
{ {
size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH; size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH;
void* CNBuffer = malloc(CNBufferSize); void* CNBuffer = malloc(CNBufferSize);
size_t const skippableFrameSize = 200 KB; size_t const skippableFrameSize = 11;
size_t const compressedBufferSize = (8 + skippableFrameSize) + ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH); size_t const compressedBufferSize = (8 + skippableFrameSize) + ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH);
void* compressedBuffer = malloc(compressedBufferSize); void* compressedBuffer = malloc(compressedBufferSize);
size_t const decodedBufferSize = CNBufferSize; size_t const decodedBufferSize = CNBufferSize;
@@ -219,8 +157,8 @@ static int basicUnitTests(U32 seed, double compressibility)
size_t cSize; size_t cSize;
int testResult = 0; int testResult = 0;
U32 testNb = 1; U32 testNb = 1;
ZSTD_CStream* zc = ZSTD_createCStream(); ZSTD_CStream* zc = ZSTD_createCStream_advanced(customMem);
ZSTD_DStream* zd = ZSTD_createDStream(); ZSTD_DStream* zd = ZSTD_createDStream_advanced(customMem);
ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2); ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2);
ZSTD_inBuffer inBuff, inBuff2; ZSTD_inBuffer inBuff, inBuff2;
@@ -245,32 +183,16 @@ static int basicUnitTests(U32 seed, double compressibility)
} }
dictID = ZDICT_getDictID(dictionary.start, dictionary.filled); dictID = ZDICT_getDictID(dictionary.start, dictionary.filled);
/* Basic compression test */
DISPLAYLEVEL(3, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
CHECK_Z( ZSTD_initCStream(zc, 1 /* cLevel */) );
outBuff.dst = (char*)(compressedBuffer);
outBuff.size = compressedBufferSize;
outBuff.pos = 0;
inBuff.src = CNBuffer;
inBuff.size = CNBufferSize;
inBuff.pos = 0;
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
{ size_t const r = ZSTD_endStream(zc, &outBuff);
if (r != 0) goto _output_error; } /* error, or some data not flushed */
DISPLAYLEVEL(3, "OK (%u bytes)\n", (U32)outBuff.pos);
/* generate skippable frame */ /* generate skippable frame */
MEM_writeLE32(compressedBuffer, ZSTD_MAGIC_SKIPPABLE_START); MEM_writeLE32(compressedBuffer, ZSTD_MAGIC_SKIPPABLE_START);
MEM_writeLE32(((char*)compressedBuffer)+4, (U32)skippableFrameSize); MEM_writeLE32(((char*)compressedBuffer)+4, (U32)skippableFrameSize);
cSize = skippableFrameSize + 8; cSize = skippableFrameSize + 8;
/* Basic compression test using dict */ /* Basic compression test */
DISPLAYLEVEL(3, "test%3i : skipframe + compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH); DISPLAYLEVEL(3, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
CHECK_Z( ZSTD_initCStream_usingDict(zc, CNBuffer, dictSize, 1 /* cLevel */) ); CHECK_Z( ZSTD_initCStream_usingDict(zc, CNBuffer, dictSize, 1) );
outBuff.dst = (char*)(compressedBuffer)+cSize; outBuff.dst = (char*)(compressedBuffer)+cSize;
assert(compressedBufferSize > cSize); outBuff.size = compressedBufferSize;
outBuff.size = compressedBufferSize - cSize;
outBuff.pos = 0; outBuff.pos = 0;
inBuff.src = CNBuffer; inBuff.src = CNBuffer;
inBuff.size = CNBufferSize; inBuff.size = CNBufferSize;
@@ -444,7 +366,7 @@ static int basicUnitTests(U32 seed, double compressibility)
/* Complex context re-use scenario */ /* Complex context re-use scenario */
DISPLAYLEVEL(3, "test%3i : context re-use : ", testNb++); DISPLAYLEVEL(3, "test%3i : context re-use : ", testNb++);
ZSTD_freeCStream(zc); ZSTD_freeCStream(zc);
zc = ZSTD_createCStream(); zc = ZSTD_createCStream_advanced(customMem);
if (zc==NULL) goto _output_error; /* memory allocation issue */ if (zc==NULL) goto _output_error; /* memory allocation issue */
/* use 1 */ /* use 1 */
{ size_t const inSize = 513; { size_t const inSize = 513;
@@ -486,7 +408,6 @@ static int basicUnitTests(U32 seed, double compressibility)
DISPLAYLEVEL(3, "test%3i : digested dictionary : ", testNb++); DISPLAYLEVEL(3, "test%3i : digested dictionary : ", testNb++);
{ ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, 1 /*byRef*/ ); { ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, 1 /*byRef*/ );
size_t const initError = ZSTD_initCStream_usingCDict(zc, cdict); size_t const initError = ZSTD_initCStream_usingCDict(zc, cdict);
DISPLAYLEVEL(5, "ZSTD_initCStream_usingCDict result : %u ", (U32)initError);
if (ZSTD_isError(initError)) goto _output_error; if (ZSTD_isError(initError)) goto _output_error;
cSize = 0; cSize = 0;
outBuff.dst = compressedBuffer; outBuff.dst = compressedBuffer;
@@ -495,13 +416,10 @@ static int basicUnitTests(U32 seed, double compressibility)
inBuff.src = CNBuffer; inBuff.src = CNBuffer;
inBuff.size = CNBufferSize; inBuff.size = CNBufferSize;
inBuff.pos = 0; inBuff.pos = 0;
DISPLAYLEVEL(5, "- starting ZSTD_compressStream ");
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
{ size_t const r = ZSTD_endStream(zc, &outBuff); { size_t const r = ZSTD_endStream(zc, &outBuff);
DISPLAYLEVEL(5, "- ZSTD_endStream result : %u ", (U32)r); if (r != 0) goto _output_error; } /* error, or some data not flushed */
if (r != 0) goto _output_error; /* error, or some data not flushed */
}
cSize = outBuff.pos; cSize = outBuff.pos;
ZSTD_freeCDict(cdict); ZSTD_freeCDict(cdict);
DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100); DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/CNBufferSize*100);
@@ -524,12 +442,12 @@ static int basicUnitTests(U32 seed, double compressibility)
{ ZSTD_DDict* const ddict = ZSTD_createDDict(dictionary.start, dictionary.filled); { ZSTD_DDict* const ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
size_t const initError = ZSTD_initDStream_usingDDict(zd, ddict); size_t const initError = ZSTD_initDStream_usingDDict(zd, ddict);
if (ZSTD_isError(initError)) goto _output_error; if (ZSTD_isError(initError)) goto _output_error;
outBuff.dst = decodedBuffer;
outBuff.size = CNBufferSize;
outBuff.pos = 0;
inBuff.src = compressedBuffer; inBuff.src = compressedBuffer;
inBuff.size = cSize; inBuff.size = cSize;
inBuff.pos = 0; inBuff.pos = 0;
outBuff.dst = decodedBuffer;
outBuff.size = CNBufferSize;
outBuff.pos = 0;
{ size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff); { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
if (r != 0) goto _output_error; } /* should reach end of frame == 0; otherwise, some data left, or an error */ if (r != 0) goto _output_error; } /* should reach end of frame == 0; otherwise, some data left, or an error */
if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */ if (outBuff.pos != CNBufferSize) goto _output_error; /* should regenerate the same amount */
@@ -548,12 +466,12 @@ static int basicUnitTests(U32 seed, double compressibility)
DISPLAYLEVEL(3, "test%3i : maxWindowSize < frame requirement : ", testNb++); DISPLAYLEVEL(3, "test%3i : maxWindowSize < frame requirement : ", testNb++);
ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize); ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
CHECK_Z( ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000) ); /* too small limit */ CHECK_Z( ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1000) ); /* too small limit */
outBuff.dst = decodedBuffer;
outBuff.size = CNBufferSize;
outBuff.pos = 0;
inBuff.src = compressedBuffer; inBuff.src = compressedBuffer;
inBuff.size = cSize; inBuff.size = cSize;
inBuff.pos = 0; inBuff.pos = 0;
outBuff.dst = decodedBuffer;
outBuff.size = CNBufferSize;
outBuff.pos = 0;
{ size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff); { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
if (!ZSTD_isError(r)) goto _output_error; /* must fail : frame requires > 100 bytes */ if (!ZSTD_isError(r)) goto _output_error; /* must fail : frame requires > 100 bytes */
DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r)); } DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r)); }
@@ -561,7 +479,7 @@ static int basicUnitTests(U32 seed, double compressibility)
DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++); DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++);
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled); { ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled);
ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */}; ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */};
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dm_auto, cParams, ZSTD_defaultCMem); ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dm_auto, cParams, customMem);
size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize); size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize);
if (ZSTD_isError(initError)) goto _output_error; if (ZSTD_isError(initError)) goto _output_error;
cSize = 0; cSize = 0;
@@ -640,14 +558,14 @@ static int basicUnitTests(U32 seed, double compressibility)
DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced with pledgedSrcSize=0 and dict : ", testNb++); DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced with pledgedSrcSize=0 and dict : ", testNb++);
{ ZSTD_parameters params = ZSTD_getParams(5, 0, 0); { ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
params.fParams.contentSizeFlag = 1; params.fParams.contentSizeFlag = 1;
CHECK_Z( ZSTD_initCStream_advanced(zc, dictionary.start, dictionary.filled, params, 0 /* pledgedSrcSize==0 means "empty" when params.fParams.contentSizeFlag is set */) ); CHECK_Z( ZSTD_initCStream_advanced(zc, dictionary.start, dictionary.filled, params, 0) );
} /* cstream advanced shall write content size = 0 */ } /* cstream advanced shall write content size = 0 */
outBuff.dst = compressedBuffer;
outBuff.size = compressedBufferSize;
outBuff.pos = 0;
inBuff.src = CNBuffer; inBuff.src = CNBuffer;
inBuff.size = 0; inBuff.size = 0;
inBuff.pos = 0; inBuff.pos = 0;
outBuff.dst = compressedBuffer;
outBuff.size = compressedBufferSize;
outBuff.pos = 0;
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error; if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
cSize = outBuff.pos; cSize = outBuff.pos;
@@ -671,12 +589,12 @@ static int basicUnitTests(U32 seed, double compressibility)
if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error; if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
ZSTD_resetCStream(zc, 0); /* resetCStream should treat 0 as unknown */ ZSTD_resetCStream(zc, 0); /* resetCStream should treat 0 as unknown */
outBuff.dst = compressedBuffer;
outBuff.size = compressedBufferSize;
outBuff.pos = 0;
inBuff.src = CNBuffer; inBuff.src = CNBuffer;
inBuff.size = 0; inBuff.size = 0;
inBuff.pos = 0; inBuff.pos = 0;
outBuff.dst = compressedBuffer;
outBuff.size = compressedBufferSize;
outBuff.pos = 0;
CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) ); CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error; if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
cSize = outBuff.pos; cSize = outBuff.pos;
@@ -688,7 +606,7 @@ static int basicUnitTests(U32 seed, double compressibility)
{ ZSTD_parameters const params = ZSTD_getParams(1, 0, 0); { ZSTD_parameters const params = ZSTD_getParams(1, 0, 0);
CHECK_Z( ZSTDMT_initCStream_advanced(mtctx, CNBuffer, dictSize, params, CNBufferSize) ); CHECK_Z( ZSTDMT_initCStream_advanced(mtctx, CNBuffer, dictSize, params, CNBufferSize) );
} }
outBuff.dst = compressedBuffer; outBuff.dst = (char*)(compressedBuffer);
outBuff.size = compressedBufferSize; outBuff.size = compressedBufferSize;
outBuff.pos = 0; outBuff.pos = 0;
inBuff.src = CNBuffer; inBuff.src = CNBuffer;
@@ -700,108 +618,6 @@ static int basicUnitTests(U32 seed, double compressibility)
if (r != 0) goto _output_error; } /* error, or some data not flushed */ if (r != 0) goto _output_error; } /* error, or some data not flushed */
DISPLAYLEVEL(3, "OK \n"); DISPLAYLEVEL(3, "OK \n");
/* Complex multithreading + dictionary test */
{ U32 const nbThreads = 2;
size_t const jobSize = 4 * 1 MB;
size_t const srcSize = jobSize * nbThreads; /* we want each job to have predictable size */
size_t const segLength = 2 KB;
size_t const offset = 600 KB; /* must be larger than window defined in cdict */
size_t const start = jobSize + (offset-1);
const BYTE* const srcToCopy = (const BYTE*)CNBuffer + start;
BYTE* const dst = (BYTE*)CNBuffer + start - offset;
DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads + dictionary : ", testNb++, (U32)srcSize);
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_compressionLevel, 3) );
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_nbThreads, 2) );
CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_p_jobSize, jobSize) );
assert(start > offset);
assert(start + segLength < COMPRESSIBLE_NOISE_LENGTH);
memcpy(dst, srcToCopy, segLength); /* create a long repetition at long distance for job 2 */
outBuff.dst = compressedBuffer;
outBuff.size = compressedBufferSize;
outBuff.pos = 0;
inBuff.src = CNBuffer;
inBuff.size = srcSize; assert(srcSize < COMPRESSIBLE_NOISE_LENGTH);
inBuff.pos = 0;
}
{ ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, 4 KB, dictionary.filled); /* intentionnally lies on estimatedSrcSize, to push cdict into targeting a small window size */
ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem);
DISPLAYLEVEL(5, "cParams.windowLog = %u : ", cParams.windowLog);
CHECK_Z( ZSTD_CCtx_refCDict(zc, cdict) );
CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, ZSTD_e_end) );
CHECK_Z( ZSTD_CCtx_refCDict(zc, NULL) ); /* do not keep a reference to cdict, as its lifetime ends */
ZSTD_freeCDict(cdict);
}
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
cSize = outBuff.pos;
DISPLAYLEVEL(3, "OK \n");
DISPLAYLEVEL(3, "test%3i : decompress large frame created from multiple threads + dictionary : ", testNb++);
{ ZSTD_DStream* const dstream = ZSTD_createDCtx();
ZSTD_frameHeader zfh;
ZSTD_getFrameHeader(&zfh, compressedBuffer, cSize);
DISPLAYLEVEL(5, "frame windowsize = %u : ", (U32)zfh.windowSize);
outBuff.dst = decodedBuffer;
outBuff.size = CNBufferSize;
outBuff.pos = 0;
inBuff.src = compressedBuffer;
inBuff.pos = 0;
CHECK_Z( ZSTD_initDStream_usingDict(dstream, dictionary.start, dictionary.filled) );
inBuff.size = 1; /* avoid shortcut to single-pass mode */
CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
inBuff.size = cSize;
CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */
ZSTD_freeDStream(dstream);
}
DISPLAYLEVEL(3, "OK \n");
DISPLAYLEVEL(3, "test%3i : check dictionary FSE tables can represent every code : ", testNb++);
{ unsigned const kMaxWindowLog = 24;
unsigned value;
ZSTD_compressionParameters cParams = ZSTD_getCParams(3, 1U << kMaxWindowLog, 1024);
ZSTD_CDict* cdict;
ZSTD_DDict* ddict;
SEQ_stream seq = SEQ_initStream(0x87654321);
SEQ_gen_type type;
XXH64_state_t xxh;
XXH64_reset(&xxh, 0);
cParams.windowLog = kMaxWindowLog;
cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dm_fullDict, cParams, ZSTD_defaultCMem);
ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
if (!cdict || !ddict) goto _output_error;
ZSTD_CCtx_reset(zc);
ZSTD_resetDStream(zd);
CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
CHECK_Z(ZSTD_initDStream_usingDDict(zd, ddict));
CHECK_Z(ZSTD_setDStreamParameter(zd, DStream_p_maxWindowSize, 1U << kMaxWindowLog));
/* Test all values < 300 */
for (value = 0; value < 300; ++value) {
for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
}
}
/* Test values 2^8 to 2^17 */
for (value = (1 << 8); value < (1 << 17); value <<= 1) {
for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value + (value >> 2)));
}
}
/* Test offset values up to the max window log */
for (value = 8; value <= kMaxWindowLog; ++value) {
CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, SEQ_gen_of, (1U << value) - 1));
}
CHECK_Z(SEQ_roundTrip(zc, zd, &xxh, NULL, 0, ZSTD_e_end));
CHECK(SEQ_digest(&seq) != XXH64_digest(&xxh), "SEQ XXH64 does not match");
ZSTD_freeCDict(cdict);
ZSTD_freeDDict(ddict);
}
DISPLAYLEVEL(3, "OK \n");
/* Overlen overwriting window data bug */ /* Overlen overwriting window data bug */
DISPLAYLEVEL(3, "test%3i : wildcopy doesn't overwrite potential match data : ", testNb++); DISPLAYLEVEL(3, "test%3i : wildcopy doesn't overwrite potential match data : ", testNb++);
@@ -883,6 +699,8 @@ static size_t FUZ_randomLength(U32* seed, U32 maxLog)
return FUZ_rLogLength(seed, logLength); return FUZ_rLogLength(seed, logLength);
} }
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
/* Return value in range minVal <= v <= maxVal */ /* Return value in range minVal <= v <= maxVal */
static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal) static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal)
{ {
@@ -890,6 +708,14 @@ static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal)
return (U32)((FUZ_rand(seed) % mod) + minVal); return (U32)((FUZ_rand(seed) % mod) + minVal);
} }
#define CHECK(cond, ...) { \
if (cond) { \
DISPLAY("Error => "); \
DISPLAY(__VA_ARGS__); \
DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); \
goto _output_error; \
} }
static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests) static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibility, int bigTests)
{ {
U32 const maxSrcLog = bigTests ? 24 : 22; U32 const maxSrcLog = bigTests ? 24 : 22;
@@ -908,7 +734,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
ZSTD_CStream* zc = ZSTD_createCStream(); /* will be re-created sometimes */ ZSTD_CStream* zc = ZSTD_createCStream(); /* will be re-created sometimes */
ZSTD_DStream* zd = ZSTD_createDStream(); /* will be re-created sometimes */ ZSTD_DStream* zd = ZSTD_createDStream(); /* will be re-created sometimes */
ZSTD_DStream* const zd_noise = ZSTD_createDStream(); ZSTD_DStream* const zd_noise = ZSTD_createDStream();
UTIL_time_t const startClock = UTIL_getTime(); clock_t const startClock = clock();
const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */ const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */
size_t dictSize = 0; size_t dictSize = 0;
U32 oldTestLog = 0; U32 oldTestLog = 0;
@@ -938,7 +764,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
FUZ_rand(&coreSeed); FUZ_rand(&coreSeed);
/* test loop */ /* test loop */
for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) { for ( ; (testNb <= nbTests) || (FUZ_GetClockSpan(startClock) < g_clockTime) ; testNb++ ) {
U32 lseed; U32 lseed;
const BYTE* srcBuffer; const BYTE* srcBuffer;
size_t totalTestSize, totalGenSize, cSize; size_t totalTestSize, totalGenSize, cSize;
@@ -1006,11 +832,10 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
{ size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize); { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
dict = srcBuffer + dictStart; dict = srcBuffer + dictStart;
} }
{ U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize; { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize;
ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize); ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize);
params.fParams.checksumFlag = FUZ_rand(&lseed) & 1; params.fParams.checksumFlag = FUZ_rand(&lseed) & 1;
params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1; params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1;
params.fParams.contentSizeFlag = FUZ_rand(&lseed) & 1;
CHECK_Z ( ZSTD_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) ); CHECK_Z ( ZSTD_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) );
} } } }
@@ -1021,7 +846,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres
for (n=0, cSize=0, totalTestSize=0 ; totalTestSize < maxTestSize ; n++) { for (n=0, cSize=0, totalTestSize=0 ; totalTestSize < maxTestSize ; n++) {
/* compress random chunks into randomly sized dst buffers */ /* compress random chunks into randomly sized dst buffers */
{ size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog); { size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize); size_t const srcSize = MIN (maxTestSize-totalTestSize, randomSrcSize);
size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize); size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog); size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize); size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
@@ -1158,7 +983,7 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
ZSTDMT_CCtx* zc = ZSTDMT_createCCtx(nbThreads); /* will be reset sometimes */ ZSTDMT_CCtx* zc = ZSTDMT_createCCtx(nbThreads); /* will be reset sometimes */
ZSTD_DStream* zd = ZSTD_createDStream(); /* will be reset sometimes */ ZSTD_DStream* zd = ZSTD_createDStream(); /* will be reset sometimes */
ZSTD_DStream* const zd_noise = ZSTD_createDStream(); ZSTD_DStream* const zd_noise = ZSTD_createDStream();
UTIL_time_t const startClock = UTIL_getTime(); clock_t const startClock = clock();
const BYTE* dict=NULL; /* can keep same dict on 2 consecutive tests */ const BYTE* dict=NULL; /* can keep same dict on 2 consecutive tests */
size_t dictSize = 0; size_t dictSize = 0;
U32 oldTestLog = 0; U32 oldTestLog = 0;
@@ -1189,7 +1014,7 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
FUZ_rand(&coreSeed); FUZ_rand(&coreSeed);
/* test loop */ /* test loop */
for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) { for ( ; (testNb <= nbTests) || (FUZ_GetClockSpan(startClock) < g_clockTime) ; testNb++ ) {
U32 lseed; U32 lseed;
const BYTE* srcBuffer; const BYTE* srcBuffer;
size_t totalTestSize, totalGenSize, cSize; size_t totalTestSize, totalGenSize, cSize;
@@ -1261,17 +1086,17 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
{ size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize); { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
dict = srcBuffer + dictStart; dict = srcBuffer + dictStart;
} }
{ U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize; { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize;
ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize); ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize);
DISPLAYLEVEL(5, "Init with windowLog = %u, pledgedSrcSize = %u, dictSize = %u \n", DISPLAYLEVEL(5, "Init with windowLog = %u and pledgedSrcSize = %u \n",
params.cParams.windowLog, (U32)pledgedSrcSize, (U32)dictSize); params.cParams.windowLog, (U32)pledgedSrcSize);
params.fParams.checksumFlag = FUZ_rand(&lseed) & 1; params.fParams.checksumFlag = FUZ_rand(&lseed) & 1;
params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1; params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1;
params.fParams.contentSizeFlag = FUZ_rand(&lseed) & 1; params.fParams.contentSizeFlag = pledgedSrcSize>0;
DISPLAYLEVEL(5, "checksumFlag : %u \n", params.fParams.checksumFlag); DISPLAYLEVEL(5, "checksumFlag : %u \n", params.fParams.checksumFlag);
CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_overlapSectionLog, FUZ_rand(&lseed) % 12) );
CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_jobSize, FUZ_rand(&lseed) % (2*maxTestSize+1)) ); /* custome job size */
CHECK_Z( ZSTDMT_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) ); CHECK_Z( ZSTDMT_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) );
CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_overlapSectionLog, FUZ_rand(&lseed) % 12) );
CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_sectionSize, FUZ_rand(&lseed) % (2*maxTestSize+1)) );
} } } }
/* multi-segments compression test */ /* multi-segments compression test */
@@ -1288,9 +1113,9 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 }; ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
outBuff.size = outBuff.pos + dstBuffSize; outBuff.size = outBuff.pos + dstBuffSize;
DISPLAYLEVEL(6, "Sending %u bytes to compress \n", (U32)srcSize); DISPLAYLEVEL(5, "Sending %u bytes to compress \n", (U32)srcSize);
CHECK_Z( ZSTDMT_compressStream(zc, &outBuff, &inBuff) ); CHECK_Z( ZSTDMT_compressStream(zc, &outBuff, &inBuff) );
DISPLAYLEVEL(6, "%u bytes read by ZSTDMT_compressStream \n", (U32)inBuff.pos); DISPLAYLEVEL(5, "%u bytes read by ZSTDMT_compressStream \n", (U32)inBuff.pos);
XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos); XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos); memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
@@ -1337,10 +1162,10 @@ static int fuzzerTests_MT(U32 seed, U32 nbTests, unsigned startTest, double comp
size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize); size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
inBuff.size = inBuff.pos + readCSrcSize; inBuff.size = inBuff.pos + readCSrcSize;
outBuff.size = outBuff.pos + dstBuffSize; outBuff.size = outBuff.pos + dstBuffSize;
DISPLAYLEVEL(6, "ZSTD_decompressStream input %u bytes \n", (U32)readCSrcSize); DISPLAYLEVEL(5, "ZSTD_decompressStream input %u bytes \n", (U32)readCSrcSize);
decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff); decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult)); CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
DISPLAYLEVEL(6, "inBuff.pos = %u \n", (U32)readCSrcSize); DISPLAYLEVEL(5, "inBuff.pos = %u \n", (U32)readCSrcSize);
} }
CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize); CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (U32)outBuff.pos, (U32)totalTestSize);
CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize); CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (U32)inBuff.pos, (U32)cSize);
@@ -1430,7 +1255,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
ZSTD_CCtx* zc = ZSTD_createCCtx(); /* will be reset sometimes */ ZSTD_CCtx* zc = ZSTD_createCCtx(); /* will be reset sometimes */
ZSTD_DStream* zd = ZSTD_createDStream(); /* will be reset sometimes */ ZSTD_DStream* zd = ZSTD_createDStream(); /* will be reset sometimes */
ZSTD_DStream* const zd_noise = ZSTD_createDStream(); ZSTD_DStream* const zd_noise = ZSTD_createDStream();
UTIL_time_t const startClock = UTIL_getTime(); clock_t const startClock = clock();
const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */ const BYTE* dict = NULL; /* can keep same dict on 2 consecutive tests */
size_t dictSize = 0; size_t dictSize = 0;
U32 oldTestLog = 0; U32 oldTestLog = 0;
@@ -1463,7 +1288,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
FUZ_rand(&coreSeed); FUZ_rand(&coreSeed);
/* test loop */ /* test loop */
for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) { for ( ; (testNb <= nbTests) || (FUZ_GetClockSpan(startClock) < g_clockTime) ; testNb++ ) {
U32 lseed; U32 lseed;
const BYTE* srcBuffer; const BYTE* srcBuffer;
size_t totalTestSize, totalGenSize, cSize; size_t totalTestSize, totalGenSize, cSize;
@@ -1527,7 +1352,7 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
(MAX(testLog, dictLog) / 2))) + (MAX(testLog, dictLog) / 2))) +
1; 1;
U32 const cLevel = MIN(cLevelCandidate, cLevelMax); U32 const cLevel = MIN(cLevelCandidate, cLevelMax);
DISPLAYLEVEL(5, "t%u: base cLevel : %u \n", testNb, cLevel); DISPLAYLEVEL(5, "t%u: cLevel : %u \n", testNb, cLevel);
maxTestSize = FUZ_rLogLength(&lseed, testLog); maxTestSize = FUZ_rLogLength(&lseed, testLog);
DISPLAYLEVEL(5, "t%u: maxTestSize : %u \n", testNb, (U32)maxTestSize); DISPLAYLEVEL(5, "t%u: maxTestSize : %u \n", testNb, (U32)maxTestSize);
oldTestLog = testLog; oldTestLog = testLog;
@@ -1552,47 +1377,43 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
cParams = ZSTD_adjustCParams(cParams, 0, 0); cParams = ZSTD_adjustCParams(cParams, 0, 0);
if (FUZ_rand(&lseed) & 1) { if (FUZ_rand(&lseed) & 1) {
DISPLAYLEVEL(5, "t%u: windowLog : %u \n", testNb, cParams.windowLog);
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_windowLog, cParams.windowLog, useOpaqueAPI) ); CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_windowLog, cParams.windowLog, useOpaqueAPI) );
assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN); /* guaranteed by ZSTD_adjustCParams() */ assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN); /* guaranteed by ZSTD_adjustCParams() */
windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5; windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5;
DISPLAYLEVEL(5, "t%u: windowLog : %u \n", testNb, cParams.windowLog);
} }
if (FUZ_rand(&lseed) & 1) { if (FUZ_rand(&lseed) & 1) {
DISPLAYLEVEL(5, "t%u: hashLog : %u \n", testNb, cParams.hashLog);
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_hashLog, cParams.hashLog, useOpaqueAPI) ); CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_hashLog, cParams.hashLog, useOpaqueAPI) );
DISPLAYLEVEL(5, "t%u: hashLog : %u \n", testNb, cParams.hashLog);
} }
if (FUZ_rand(&lseed) & 1) { if (FUZ_rand(&lseed) & 1) {
DISPLAYLEVEL(5, "t%u: chainLog : %u \n", testNb, cParams.chainLog);
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_chainLog, cParams.chainLog, useOpaqueAPI) ); CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_chainLog, cParams.chainLog, useOpaqueAPI) );
DISPLAYLEVEL(5, "t%u: chainLog : %u \n", testNb, cParams.chainLog);
} }
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_searchLog, cParams.searchLog, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_searchLog, cParams.searchLog, useOpaqueAPI) );
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_minMatch, cParams.searchLength, useOpaqueAPI) );
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_targetLength, cParams.targetLength, useOpaqueAPI) );
/* mess with long distance matching parameters */ /* mess with long distance matching parameters */
if (bigTests) { if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) );
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), useOpaqueAPI) );
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), useOpaqueAPI) ); if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmMinMatch, FUZ_randomClampedLength(&lseed, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX), useOpaqueAPI) );
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmMinMatch, FUZ_randomClampedLength(&lseed, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX), useOpaqueAPI) ); if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_LDM_BUCKETSIZELOG_MAX), useOpaqueAPI) );
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_LDM_BUCKETSIZELOG_MAX), useOpaqueAPI) ); if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashEveryLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN), useOpaqueAPI) );
if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_ldmHashEveryLog, FUZ_randomClampedLength(&lseed, 0, ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN), useOpaqueAPI) );
}
/* mess with frame parameters */ /* mess with frame parameters */
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_checksumFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_checksumFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_dictIDFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_contentSizeFlag, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
if (FUZ_rand(&lseed) & 1) { if (FUZ_rand(&lseed) & 1) CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
DISPLAYLEVEL(5, "t%u: pledgedSrcSize : %u \n", testNb, (U32)pledgedSrcSize); DISPLAYLEVEL(5, "t%u: pledgedSrcSize : %u \n", testNb, (U32)pledgedSrcSize);
CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
}
/* multi-threading parameters */ /* multi-threading parameters */
{ U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1; { U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1;
U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1; U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1;
U32 const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax); U32 const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax);
DISPLAYLEVEL(5, "t%u: nbThreads : %u \n", testNb, nbThreads);
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbThreads, nbThreads, useOpaqueAPI) ); CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_nbThreads, nbThreads, useOpaqueAPI) );
DISPLAYLEVEL(5, "t%u: nbThreads : %u \n", testNb, nbThreads);
if (nbThreads > 1) { if (nbThreads > 1) {
U32 const jobLog = FUZ_rand(&lseed) % (testLog+1); U32 const jobLog = FUZ_rand(&lseed) % (testLog+1);
CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10, useOpaqueAPI) ); CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_overlapSizeLog, FUZ_rand(&lseed) % 10, useOpaqueAPI) );
@@ -1600,11 +1421,10 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
} }
} }
if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_p_forceMaxWindow, FUZ_rand(&lseed) & 1, useOpaqueAPI) ); if (FUZ_rand(&lseed) & 1) CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_p_forceMaxWindow, FUZ_rand(&lseed) & 1, useOpaqueAPI) );
/* Apply parameters */ /* Apply parameters */
if (useOpaqueAPI) { if (useOpaqueAPI) {
DISPLAYLEVEL(6," t%u: applying CCtxParams \n", testNb);
CHECK_Z (ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams) ); CHECK_Z (ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams) );
} }
@@ -1644,8 +1464,8 @@ static int fuzzerTests_newAPI(U32 seed, U32 nbTests, unsigned startTest, double
outBuff.size = outBuff.pos + dstBuffSize; outBuff.size = outBuff.pos + dstBuffSize;
CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, flush) ); CHECK_Z( ZSTD_compress_generic(zc, &outBuff, &inBuff, flush) );
DISPLAYLEVEL(6, "t%u: compress consumed %u bytes (total : %u) \n", DISPLAYLEVEL(6, "compress consumed %u bytes (total : %u) \n",
testNb, (U32)inBuff.pos, (U32)(totalTestSize + inBuff.pos)); (U32)inBuff.pos, (U32)(totalTestSize + inBuff.pos));
XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos); XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos); memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
@@ -1773,23 +1593,24 @@ typedef enum { simple_api, mt_api, advanced_api } e_api;
int main(int argc, const char** argv) int main(int argc, const char** argv)
{ {
U32 seed = 0; U32 seed=0;
int seedset = 0; int seedset=0;
int argNb;
int nbTests = nbTestsDefault; int nbTests = nbTestsDefault;
int testNb = 0; int testNb = 0;
int proba = FUZ_COMPRESSIBILITY_DEFAULT; int proba = FUZ_COMPRESSIBILITY_DEFAULT;
int result = 0; int result=0;
int mainPause = 0; int mainPause = 0;
int bigTests = (sizeof(size_t) == 8); int bigTests = (sizeof(size_t) == 8);
e_api selected_api = simple_api; e_api selected_api = simple_api;
const char* const programName = argv[0]; const char* const programName = argv[0];
ZSTD_customMem const customNULL = ZSTD_defaultCMem;
U32 useOpaqueAPI = 0; U32 useOpaqueAPI = 0;
int argNb;
/* Check command line */ /* Check command line */
for(argNb=1; argNb<argc; argNb++) { for(argNb=1; argNb<argc; argNb++) {
const char* argument = argv[argNb]; const char* argument = argv[argNb];
assert(argument != NULL); if(!argument) continue; /* Protection if argument empty */
/* Parsing commands. Aggregated commands are allowed */ /* Parsing commands. Aggregated commands are allowed */
if (argument[0]=='-') { if (argument[0]=='-') {
@@ -1839,17 +1660,15 @@ int main(int argc, const char** argv)
g_clockTime += *argument - '0'; g_clockTime += *argument - '0';
argument++; argument++;
} }
if (*argument=='m') { /* -T1m == -T60 */ if (*argument=='m') g_clockTime *=60, argument++;
g_clockTime *=60, argument++; if (*argument=='n') argument++;
if (*argument=='n') argument++; /* -T1mn == -T60 */ g_clockTime *= CLOCKS_PER_SEC;
} else if (*argument=='s') argument++; /* -T10s == -T10 */
g_clockTime *= SEC_TO_MICRO;
break; break;
case 's': /* manually select seed */ case 's': /* manually select seed */
argument++; argument++;
seedset=1;
seed=0; seed=0;
seedset=1;
while ((*argument>='0') && (*argument<='9')) { while ((*argument>='0') && (*argument<='9')) {
seed *= 10; seed *= 10;
seed += *argument - '0'; seed += *argument - '0';
@@ -1899,7 +1718,7 @@ int main(int argc, const char** argv)
if (nbTests<=0) nbTests=1; if (nbTests<=0) nbTests=1;
if (testNb==0) { if (testNb==0) {
result = basicUnitTests(0, ((double)proba) / 100); /* constant seed for predictability */ result = basicUnitTests(0, ((double)proba) / 100, customNULL); /* constant seed for predictability */
} }
if (!result) { if (!result) {
+1 -1
View File
@@ -12,7 +12,7 @@ cxx_library(
deps=[ deps=[
'//lib:zstd', '//lib:zstd',
'//lib:zstd_common', '//lib:zstd_common',
], ]
) )
cxx_binary( cxx_binary(
+3 -10
View File
@@ -684,11 +684,6 @@ static void BMK_loadFiles(void* buffer, size_t bufferSize,
fileSizes[n] = 0; fileSizes[n] = 0;
continue; continue;
} }
if (fileSize == UTIL_FILESIZE_UNKNOWN) {
DISPLAYLEVEL(2, "Cannot determine size of %s ... \n", fileNamesTable[n]);
fileSizes[n] = 0;
continue;
}
f = fopen(fileNamesTable[n], "rb"); f = fopen(fileNamesTable[n], "rb");
if (f==NULL) EXM_THROW(10, "impossible to open file %s", fileNamesTable[n]); if (f==NULL) EXM_THROW(10, "impossible to open file %s", fileNamesTable[n]);
DISPLAYUPDATE(2, "Loading %s... \r", fileNamesTable[n]); DISPLAYUPDATE(2, "Loading %s... \r", fileNamesTable[n]);
@@ -719,13 +714,11 @@ static void BMK_benchFileTable(const char** fileNamesTable, unsigned nbFiles,
/* Load dictionary */ /* Load dictionary */
if (dictFileName != NULL) { if (dictFileName != NULL) {
U64 const dictFileSize = UTIL_getFileSize(dictFileName); U64 dictFileSize = UTIL_getFileSize(dictFileName);
if (dictFileSize > 64 MB) if (dictFileSize > 64 MB) EXM_THROW(10, "dictionary file %s too large", dictFileName);
EXM_THROW(10, "dictionary file %s too large", dictFileName);
dictBufferSize = (size_t)dictFileSize; dictBufferSize = (size_t)dictFileSize;
dictBuffer = malloc(dictBufferSize); dictBuffer = malloc(dictBufferSize);
if (dictBuffer==NULL) if (dictBuffer==NULL) EXM_THROW(11, "not enough memory for dictionary (%u bytes)", (U32)dictBufferSize);
EXM_THROW(11, "not enough memory for dictionary (%u bytes)", (U32)dictBufferSize);
BMK_loadFiles(dictBuffer, dictBufferSize, fileSizes, &dictFileName, 1); BMK_loadFiles(dictBuffer, dictBufferSize, fileSizes, &dictFileName, 1);
} }
+3 -3
View File
@@ -270,7 +270,7 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm,
zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem);
if (zwc->zbc == NULL) return ZWRAPC_finishWithError(zwc, strm, 0); if (zwc->zbc == NULL) return ZWRAPC_finishWithError(zwc, strm, 0);
} }
{ int res = ZWRAP_initializeCStream(zwc, dictionary, dictLength, ZSTD_CONTENTSIZE_UNKNOWN); { int res = ZWRAP_initializeCStream(zwc, dictionary, dictLength, 0);
if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); } if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); }
zwc->comprState = ZWRAP_useReset; zwc->comprState = ZWRAP_useReset;
} }
@@ -295,7 +295,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush))
if (zwc->zbc == NULL) { if (zwc->zbc == NULL) {
zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem);
if (zwc->zbc == NULL) return ZWRAPC_finishWithError(zwc, strm, 0); if (zwc->zbc == NULL) return ZWRAPC_finishWithError(zwc, strm, 0);
{ int const initErr = ZWRAP_initializeCStream(zwc, NULL, 0, (flush == Z_FINISH) ? strm->avail_in : ZSTD_CONTENTSIZE_UNKNOWN); { int const initErr = ZWRAP_initializeCStream(zwc, NULL, 0, (flush == Z_FINISH) ? strm->avail_in : 0);
if (initErr != Z_OK) return ZWRAPC_finishWithError(zwc, strm, initErr); } if (initErr != Z_OK) return ZWRAPC_finishWithError(zwc, strm, initErr); }
if (flush != Z_FINISH) zwc->comprState = ZWRAP_useReset; if (flush != Z_FINISH) zwc->comprState = ZWRAP_useReset;
} else { } else {
@@ -308,7 +308,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush))
return ZWRAPC_finishWithError(zwc, strm, 0); return ZWRAPC_finishWithError(zwc, strm, 0);
} }
} else { } else {
int const res = ZWRAP_initializeCStream(zwc, NULL, 0, (flush == Z_FINISH) ? strm->avail_in : ZSTD_CONTENTSIZE_UNKNOWN); int const res = ZWRAP_initializeCStream(zwc, NULL, 0, (flush == Z_FINISH) ? strm->avail_in : 0);
if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res);
if (flush != Z_FINISH) zwc->comprState = ZWRAP_useReset; if (flush != Z_FINISH) zwc->comprState = ZWRAP_useReset;
} }