2017-09-01 18:28:35 -07:00
/*
* Copyright ( c ) 2016 - present , Yann Collet , 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 ) .
2017-09-08 00:09:23 -07:00
* You may select , at your option , one of the above - listed licenses .
2017-09-01 18:28:35 -07:00
*/
2017-11-07 16:15:23 -08:00
# include "zstd_compress_internal.h"
2017-09-01 18:28:35 -07:00
# include "zstd_lazy.h"
/*-*************************************
* Binary Tree search
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
2017-12-12 16:51:00 -08:00
void ZSTD_updateDUBT (
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
const BYTE * ip , const BYTE * iend ,
U32 mls )
{
2017-12-12 16:51:00 -08:00
U32 * const hashTable = ms - > hashTable ;
U32 const hashLog = cParams - > hashLog ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
2017-12-12 16:51:00 -08:00
U32 * const bt = ms - > chainTable ;
U32 const btLog = cParams - > chainLog - 1 ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
U32 const btMask = ( 1 < < btLog ) - 1 ;
2018-02-23 16:48:18 -08:00
const BYTE * const base = ms - > window . base ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
U32 const target = ( U32 ) ( ip - base ) ;
2017-12-12 16:51:00 -08:00
U32 idx = ms - > nextToUpdate ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
2017-12-29 08:04:37 -08:00
if ( idx ! = target )
2017-12-29 10:08:51 -08:00
DEBUGLOG ( 7 , " ZSTD_updateDUBT, from %u to %u (dictLimit:%u) " ,
2018-02-23 16:48:18 -08:00
idx , target , ms - > window . dictLimit ) ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
assert ( ip + 8 < = iend ) ; /* condition for ZSTD_hashPtr */
( void ) iend ;
2018-02-23 16:48:18 -08:00
assert ( idx > = ms - > window . dictLimit ) ; /* condition for valid base+idx */
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
for ( ; idx < target ; idx + + ) {
size_t const h = ZSTD_hashPtr ( base + idx , hashLog , mls ) ; /* assumption : ip + 8 <= iend */
U32 const matchIndex = hashTable [ h ] ;
U32 * const nextCandidatePtr = bt + 2 * ( idx & btMask ) ;
U32 * const sortMarkPtr = nextCandidatePtr + 1 ;
2017-12-30 06:12:59 -08:00
DEBUGLOG ( 8 , " ZSTD_updateDUBT: insert %u " , idx ) ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
hashTable [ h ] = idx ; /* Update Hash Table */
* nextCandidatePtr = matchIndex ; /* update BT like a chain */
2017-12-29 10:08:51 -08:00
* sortMarkPtr = ZSTD_DUBT_UNSORTED_MARK ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
}
2017-12-12 16:51:00 -08:00
ms - > nextToUpdate = target ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
}
/** ZSTD_insertDUBT1() :
* sort one already inserted but unsorted position
* assumption : current > = btlow = = ( current - btmask )
* doesn ' t fail */
2017-12-12 16:51:00 -08:00
static void ZSTD_insertDUBT1 (
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
2017-12-30 06:12:59 -08:00
U32 current , const BYTE * inputEnd ,
2018-05-16 01:07:09 -07:00
U32 nbCompares , U32 btLow , const ZSTD_dictMode_e dictMode )
2017-09-01 18:28:35 -07:00
{
2017-12-12 16:51:00 -08:00
U32 * const bt = ms - > chainTable ;
U32 const btLog = cParams - > chainLog - 1 ;
2017-09-01 18:28:35 -07:00
U32 const btMask = ( 1 < < btLog ) - 1 ;
size_t commonLengthSmaller = 0 , commonLengthLarger = 0 ;
2018-02-23 16:48:18 -08:00
const BYTE * const base = ms - > window . base ;
const BYTE * const dictBase = ms - > window . dictBase ;
const U32 dictLimit = ms - > window . dictLimit ;
2017-12-30 06:12:59 -08:00
const BYTE * const ip = ( current > = dictLimit ) ? base + current : dictBase + current ;
const BYTE * const iend = ( current > = dictLimit ) ? inputEnd : dictBase + dictLimit ;
2017-09-01 18:28:35 -07:00
const BYTE * const dictEnd = dictBase + dictLimit ;
const BYTE * const prefixStart = base + dictLimit ;
const BYTE * match ;
U32 * smallerPtr = bt + 2 * ( current & btMask ) ;
U32 * largerPtr = smallerPtr + 1 ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
U32 matchIndex = * smallerPtr ;
2017-09-01 18:28:35 -07:00
U32 dummy32 ; /* to be nullified at the end */
2018-02-23 16:48:18 -08:00
U32 const windowLow = ms - > window . lowLimit ;
2017-09-01 18:28:35 -07:00
2017-12-29 08:04:37 -08:00
DEBUGLOG ( 8 , " ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u) " ,
current , dictLimit , windowLow ) ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
assert ( current > = btLow ) ;
2017-12-30 06:12:59 -08:00
assert ( ip < iend ) ; /* condition for ZSTD_count */
2017-09-01 18:28:35 -07:00
while ( nbCompares - - & & ( matchIndex > windowLow ) ) {
U32 * const nextPtr = bt + 2 * ( matchIndex & btMask ) ;
size_t matchLength = MIN ( commonLengthSmaller , commonLengthLarger ) ; /* guaranteed minimum nb of common bytes */
Fixed Btree update
ZSTD_updateTree() expected to be followed by a Bt match finder, which would update zc->nextToUpdate.
With the new optimal match finder, it's not necessarily the case : a match might be found during repcode or hash3, and stops there because it reaches sufficient_len, without even entering the binary tree.
Previous policy was to nonetheless update zc->nextToUpdate, but the current position would not be inserted, creating "holes" in the btree, aka positions that will no longer be searched.
Now, when current position is not inserted, zc->nextToUpdate is not update, expecting ZSTD_updateTree() to fill the tree later on.
Solution selected is that ZSTD_updateTree() takes care of properly setting zc->nextToUpdate,
so that it no longer depends on a future function to do this job.
It took time to get there, as the issue started with a memory sanitizer error.
The pb would have been easier to spot with a proper `assert()`.
So this patch add a few of them.
Additionnally, I discovered that `make test` does not enable `assert()` during CLI tests.
This patch enables them.
Unfortunately, these `assert()` triggered other (unrelated) bugs during CLI tests, mostly within zstdmt.
So this patch also fixes them.
- Changed packed structure for gcc memory access : memory sanitizer would complain that a read "might" reach out-of-bound position on the ground that the `union` is larger than the type accessed.
Now, to avoid this issue, each type is independent.
- ZSTD_CCtxParams_setParameter() : @return provides the value of parameter, clamped/fixed appropriately.
- ZSTDMT : changed constant name to ZSTDMT_JOBSIZE_MIN
- ZSTDMT : multithreading is automatically disabled when srcSize <= ZSTDMT_JOBSIZE_MIN, since only one thread will be used in this case (saves memory and runtime).
- ZSTDMT : nbThreads is automatically clamped on setting the value.
2017-11-16 12:18:56 -08:00
assert ( matchIndex < current ) ;
2017-09-01 18:28:35 -07:00
2018-05-16 01:07:09 -07:00
if ( ( dictMode ! = ZSTD_extDict )
2017-12-30 06:12:59 -08:00
| | ( matchIndex + matchLength > = dictLimit ) /* both in current segment*/
| | ( current < dictLimit ) /* both in extDict */ ) {
2018-05-16 01:07:09 -07:00
const BYTE * const mBase = ( ( dictMode ! = ZSTD_extDict )
| | ( matchIndex + matchLength > = dictLimit ) ) ?
base : dictBase ;
2017-12-30 06:12:59 -08:00
assert ( ( matchIndex + matchLength > = dictLimit ) /* might be wrong if extDict is incorrectly set to 0 */
| | ( current < dictLimit ) ) ;
match = mBase + matchIndex ;
2017-11-19 14:40:21 -08:00
matchLength + = ZSTD_count ( ip + matchLength , match + matchLength , iend ) ;
2017-09-01 18:28:35 -07:00
} else {
match = dictBase + matchIndex ;
matchLength + = ZSTD_count_2segments ( ip + matchLength , match + matchLength , iend , dictEnd , prefixStart ) ;
if ( matchIndex + matchLength > = dictLimit )
match = base + matchIndex ; /* to prepare for next usage of match[matchLength] */
}
2017-12-30 06:12:59 -08:00
DEBUGLOG ( 8 , " ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes " ,
current , matchIndex , ( U32 ) matchLength ) ;
2017-11-15 11:29:24 -08:00
if ( ip + matchLength = = iend ) { /* equal : no way to know if inf or sup */
2017-09-16 23:40:14 -07:00
break ; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
2017-11-15 11:29:24 -08:00
}
2017-09-01 18:28:35 -07:00
2017-09-16 23:40:14 -07:00
if ( match [ matchLength ] < ip [ matchLength ] ) { /* necessarily within buffer */
2017-11-15 13:44:24 -08:00
/* match is smaller than current */
2017-09-01 18:28:35 -07:00
* smallerPtr = matchIndex ; /* update smaller idx */
commonLengthSmaller = matchLength ; /* all smaller will now have at least this guaranteed common length */
2017-09-16 23:40:14 -07:00
if ( matchIndex < = btLow ) { smallerPtr = & dummy32 ; break ; } /* beyond tree size, stop searching */
2017-12-30 06:12:59 -08:00
DEBUGLOG ( 8 , " ZSTD_insertDUBT1: %u (>btLow=%u) is smaller : next => %u " ,
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
matchIndex , btLow , nextPtr [ 1 ] ) ;
2017-11-15 13:44:24 -08:00
smallerPtr = nextPtr + 1 ; /* new "candidate" => larger than match, which was smaller than target */
matchIndex = nextPtr [ 1 ] ; /* new matchIndex, larger than previous and closer to current */
2017-09-01 18:28:35 -07:00
} else {
/* match is larger than current */
* largerPtr = matchIndex ;
commonLengthLarger = matchLength ;
2017-09-16 23:40:14 -07:00
if ( matchIndex < = btLow ) { largerPtr = & dummy32 ; break ; } /* beyond tree size, stop searching */
2017-12-30 06:12:59 -08:00
DEBUGLOG ( 8 , " ZSTD_insertDUBT1: %u (>btLow=%u) is larger => %u " ,
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
matchIndex , btLow , nextPtr [ 0 ] ) ;
2017-09-01 18:28:35 -07:00
largerPtr = nextPtr ;
matchIndex = nextPtr [ 0 ] ;
} }
* smallerPtr = * largerPtr = 0 ;
Fixed Btree update
ZSTD_updateTree() expected to be followed by a Bt match finder, which would update zc->nextToUpdate.
With the new optimal match finder, it's not necessarily the case : a match might be found during repcode or hash3, and stops there because it reaches sufficient_len, without even entering the binary tree.
Previous policy was to nonetheless update zc->nextToUpdate, but the current position would not be inserted, creating "holes" in the btree, aka positions that will no longer be searched.
Now, when current position is not inserted, zc->nextToUpdate is not update, expecting ZSTD_updateTree() to fill the tree later on.
Solution selected is that ZSTD_updateTree() takes care of properly setting zc->nextToUpdate,
so that it no longer depends on a future function to do this job.
It took time to get there, as the issue started with a memory sanitizer error.
The pb would have been easier to spot with a proper `assert()`.
So this patch add a few of them.
Additionnally, I discovered that `make test` does not enable `assert()` during CLI tests.
This patch enables them.
Unfortunately, these `assert()` triggered other (unrelated) bugs during CLI tests, mostly within zstdmt.
So this patch also fixes them.
- Changed packed structure for gcc memory access : memory sanitizer would complain that a read "might" reach out-of-bound position on the ground that the `union` is larger than the type accessed.
Now, to avoid this issue, each type is independent.
- ZSTD_CCtxParams_setParameter() : @return provides the value of parameter, clamped/fixed appropriately.
- ZSTDMT : changed constant name to ZSTDMT_JOBSIZE_MIN
- ZSTDMT : multithreading is automatically disabled when srcSize <= ZSTDMT_JOBSIZE_MIN, since only one thread will be used in this case (saves memory and runtime).
- ZSTDMT : nbThreads is automatically clamped on setting the value.
2017-11-16 12:18:56 -08:00
}
2017-09-01 18:28:35 -07:00
2018-06-12 15:38:10 -07:00
static size_t ZSTD_DUBT_findBetterDictMatch (
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
const BYTE * const ip , const BYTE * const iend ,
size_t * offsetPtr ,
size_t bestLength ,
U32 nbCompares ,
U32 const mls ,
const ZSTD_dictMode_e dictMode ) {
const ZSTD_matchState_t * const dms = ms - > dictMatchState ;
const U32 * const dictHashTable = dms - > hashTable ;
U32 const hashLog = cParams - > hashLog ;
size_t const h = ZSTD_hashPtr ( ip , hashLog , mls ) ;
U32 dictMatchIndex = dictHashTable [ h ] ;
const BYTE * const base = ms - > window . base ;
const BYTE * const prefixStart = base + ms - > window . dictLimit ;
U32 const current = ( U32 ) ( ip - base ) ;
const BYTE * const dictBase = dms - > window . base ;
const BYTE * const dictEnd = dms - > window . nextSrc ;
U32 const dictHighLimit = ( U32 ) ( dms - > window . nextSrc - dms - > window . base ) ;
U32 const dictLowLimit = dms - > window . lowLimit ;
U32 const dictIndexDelta = ms - > window . lowLimit - dictHighLimit ;
U32 * const dictBt = dms - > chainTable ;
U32 const btLog = cParams - > chainLog - 1 ;
U32 const btMask = ( 1 < < btLog ) - 1 ;
U32 const btLow = ( btMask > = dictHighLimit - dictLowLimit ) ? 0 : dictHighLimit - btMask ;
size_t commonLengthSmaller = 0 , commonLengthLarger = 0 ;
U32 matchEndIdx = current + 8 + 1 ;
( void ) dictMode ;
assert ( dictMode = = ZSTD_dictMatchState ) ;
while ( nbCompares - - & & ( dictMatchIndex > dictLowLimit ) ) {
U32 * const nextPtr = dictBt + 2 * ( dictMatchIndex & btMask ) ;
size_t matchLength = MIN ( commonLengthSmaller , commonLengthLarger ) ; /* guaranteed minimum nb of common bytes */
const BYTE * match = dictBase + dictMatchIndex ;
matchLength + = ZSTD_count_2segments ( ip + matchLength , match + matchLength , iend , dictEnd , prefixStart ) ;
if ( dictMatchIndex + matchLength > = dictHighLimit )
match = base + dictMatchIndex + dictIndexDelta ; /* to prepare for next usage of match[matchLength] */
if ( matchLength > bestLength ) {
U32 matchIndex = dictMatchIndex + dictIndexDelta ;
if ( matchLength > matchEndIdx - matchIndex )
matchEndIdx = matchIndex + ( U32 ) matchLength ;
if ( ( 4 * ( int ) ( matchLength - bestLength ) ) > ( int ) ( ZSTD_highbit32 ( current - matchIndex + 1 ) - ZSTD_highbit32 ( ( U32 ) offsetPtr [ 0 ] + 1 ) ) ) {
DEBUGLOG ( 9 , " ZSTD_DUBT_findBestDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u) " ,
current , ( U32 ) bestLength , ( U32 ) matchLength , ( U32 ) * offsetPtr , ZSTD_REP_MOVE + current - matchIndex , dictMatchIndex , matchIndex ) ;
bestLength = matchLength , * offsetPtr = ZSTD_REP_MOVE + current - matchIndex ;
}
if ( ip + matchLength = = iend ) { /* equal : no way to know if inf or sup */
break ; /* drop, to guarantee consistency (miss a little bit of compression) */
}
}
if ( match [ matchLength ] < ip [ matchLength ] ) {
if ( dictMatchIndex < = btLow ) { break ; } /* beyond tree size, stop the search */
commonLengthSmaller = matchLength ; /* all smaller will now have at least this guaranteed common length */
dictMatchIndex = nextPtr [ 1 ] ; /* new matchIndex larger than previous (closer to current) */
} else {
/* match is larger than current */
if ( dictMatchIndex < = btLow ) { break ; } /* beyond tree size, stop the search */
commonLengthLarger = matchLength ;
dictMatchIndex = nextPtr [ 0 ] ;
}
}
if ( bestLength > = MINMATCH ) {
U32 const mIndex = current - ( ( U32 ) * offsetPtr - ZSTD_REP_MOVE ) ; ( void ) mIndex ;
DEBUGLOG ( 8 , " ZSTD_DUBT_findBestDictMatch(%u) : found match of length %u and offsetCode %u (pos %u) " ,
current , ( U32 ) bestLength , ( U32 ) * offsetPtr , mIndex ) ;
}
return bestLength ;
}
2018-01-11 12:38:31 -08:00
static size_t ZSTD_DUBT_findBestMatch (
2017-12-12 16:51:00 -08:00
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
const BYTE * const ip , const BYTE * const iend ,
size_t * offsetPtr ,
2017-12-12 16:51:00 -08:00
U32 const mls ,
2018-05-16 01:07:09 -07:00
const ZSTD_dictMode_e dictMode )
2017-09-01 18:28:35 -07:00
{
2017-12-12 16:51:00 -08:00
U32 * const hashTable = ms - > hashTable ;
U32 const hashLog = cParams - > hashLog ;
2017-09-01 18:28:35 -07:00
size_t const h = ZSTD_hashPtr ( ip , hashLog , mls ) ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
U32 matchIndex = hashTable [ h ] ;
2018-02-23 16:48:18 -08:00
const BYTE * const base = ms - > window . base ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
U32 const current = ( U32 ) ( ip - base ) ;
2018-02-23 16:48:18 -08:00
U32 const windowLow = ms - > window . lowLimit ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
2017-12-12 16:51:00 -08:00
U32 * const bt = ms - > chainTable ;
U32 const btLog = cParams - > chainLog - 1 ;
2017-09-01 18:28:35 -07:00
U32 const btMask = ( 1 < < btLog ) - 1 ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
U32 const btLow = ( btMask > = current ) ? 0 : current - btMask ;
2017-12-29 08:04:37 -08:00
U32 const unsortLimit = MAX ( btLow , windowLow ) ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
U32 * nextCandidate = bt + 2 * ( matchIndex & btMask ) ;
U32 * unsortedMark = bt + 2 * ( matchIndex & btMask ) + 1 ;
2017-12-12 16:51:00 -08:00
U32 nbCompares = 1U < < cParams - > searchLog ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
U32 nbCandidates = nbCompares ;
U32 previousCandidate = 0 ;
2017-09-01 18:28:35 -07:00
2018-01-11 12:38:31 -08:00
DEBUGLOG ( 7 , " ZSTD_DUBT_findBestMatch (%u) " , current ) ;
2017-09-16 23:40:14 -07:00
assert ( ip < = iend - 8 ) ; /* required for h calculation */
2017-09-01 18:28:35 -07:00
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
/* reach end of unsorted candidates list */
2017-12-29 08:04:37 -08:00
while ( ( matchIndex > unsortLimit )
2017-12-29 10:08:51 -08:00
& & ( * unsortedMark = = ZSTD_DUBT_UNSORTED_MARK )
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
& & ( nbCandidates > 1 ) ) {
2018-01-11 12:38:31 -08:00
DEBUGLOG ( 8 , " ZSTD_DUBT_findBestMatch: candidate %u is unsorted " ,
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
matchIndex ) ;
* unsortedMark = previousCandidate ;
previousCandidate = matchIndex ;
matchIndex = * nextCandidate ;
nextCandidate = bt + 2 * ( matchIndex & btMask ) ;
unsortedMark = bt + 2 * ( matchIndex & btMask ) + 1 ;
nbCandidates - - ;
}
2017-09-01 18:28:35 -07:00
2017-12-29 08:04:37 -08:00
if ( ( matchIndex > unsortLimit )
2017-12-29 10:08:51 -08:00
& & ( * unsortedMark = = ZSTD_DUBT_UNSORTED_MARK ) ) {
2018-01-11 12:38:31 -08:00
DEBUGLOG ( 7 , " ZSTD_DUBT_findBestMatch: nullify last unsorted candidate %u " ,
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
matchIndex ) ;
2017-12-29 08:04:37 -08:00
* nextCandidate = * unsortedMark = 0 ; /* nullify next candidate if it's still unsorted (note : simplification, detrimental to compression ratio, beneficial for speed) */
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
}
2017-09-01 18:28:35 -07:00
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
/* batch sort stacked candidates */
matchIndex = previousCandidate ;
while ( matchIndex ) { /* will end on matchIndex == 0 */
U32 * const nextCandidateIdxPtr = bt + 2 * ( matchIndex & btMask ) + 1 ;
U32 const nextCandidateIdx = * nextCandidateIdxPtr ;
2017-12-12 16:51:00 -08:00
ZSTD_insertDUBT1 ( ms , cParams , matchIndex , iend ,
2018-05-16 01:07:09 -07:00
nbCandidates , unsortLimit , dictMode ) ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
matchIndex = nextCandidateIdx ;
nbCandidates + + ;
}
2017-09-01 18:28:35 -07:00
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
/* find longest match */
{ size_t commonLengthSmaller = 0 , commonLengthLarger = 0 ;
2018-02-23 16:48:18 -08:00
const BYTE * const dictBase = ms - > window . dictBase ;
const U32 dictLimit = ms - > window . dictLimit ;
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
const BYTE * const dictEnd = dictBase + dictLimit ;
const BYTE * const prefixStart = base + dictLimit ;
U32 * smallerPtr = bt + 2 * ( current & btMask ) ;
U32 * largerPtr = bt + 2 * ( current & btMask ) + 1 ;
U32 matchEndIdx = current + 8 + 1 ;
U32 dummy32 ; /* to be nullified at the end */
size_t bestLength = 0 ;
matchIndex = hashTable [ h ] ;
hashTable [ h ] = current ; /* Update Hash Table */
while ( nbCompares - - & & ( matchIndex > windowLow ) ) {
U32 * const nextPtr = bt + 2 * ( matchIndex & btMask ) ;
size_t matchLength = MIN ( commonLengthSmaller , commonLengthLarger ) ; /* guaranteed minimum nb of common bytes */
const BYTE * match ;
2018-05-16 01:07:09 -07:00
if ( ( dictMode ! = ZSTD_extDict ) | | ( matchIndex + matchLength > = dictLimit ) ) {
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
match = base + matchIndex ;
matchLength + = ZSTD_count ( ip + matchLength , match + matchLength , iend ) ;
} else {
match = dictBase + matchIndex ;
matchLength + = ZSTD_count_2segments ( ip + matchLength , match + matchLength , iend , dictEnd , prefixStart ) ;
if ( matchIndex + matchLength > = dictLimit )
match = base + matchIndex ; /* to prepare for next usage of match[matchLength] */
}
2017-09-01 18:28:35 -07:00
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
if ( matchLength > bestLength ) {
if ( matchLength > matchEndIdx - matchIndex )
matchEndIdx = matchIndex + ( U32 ) matchLength ;
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 ;
if ( ip + matchLength = = iend ) { /* equal : no way to know if inf or sup */
break ; /* drop, to guarantee consistency (miss a little bit of compression) */
}
}
2017-09-01 18:28:35 -07:00
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
if ( match [ matchLength ] < ip [ matchLength ] ) {
/* match is smaller than current */
* smallerPtr = matchIndex ; /* update smaller idx */
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 */
smallerPtr = nextPtr + 1 ; /* new "smaller" => larger of match */
matchIndex = nextPtr [ 1 ] ; /* new matchIndex larger than previous (closer to current) */
} else {
/* match is larger than current */
* largerPtr = matchIndex ;
commonLengthLarger = matchLength ;
if ( matchIndex < = btLow ) { largerPtr = & dummy32 ; break ; } /* beyond tree size, stop the search */
largerPtr = nextPtr ;
matchIndex = nextPtr [ 0 ] ;
} }
* smallerPtr = * largerPtr = 0 ;
2018-06-12 15:38:10 -07:00
if ( dictMode = = ZSTD_dictMatchState & & nbCompares ) {
bestLength = ZSTD_DUBT_findBetterDictMatch ( ms , cParams , ip , iend , offsetPtr , bestLength , nbCompares , mls , dictMode ) ;
}
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
assert ( matchEndIdx > current + 8 ) ; /* ensure nextToUpdate is increased */
2017-12-12 16:51:00 -08:00
ms - > nextToUpdate = matchEndIdx - 8 ; /* skip repetitive patterns */
2017-12-30 06:12:59 -08:00
if ( bestLength > = MINMATCH ) {
U32 const mIndex = current - ( ( U32 ) * offsetPtr - ZSTD_REP_MOVE ) ; ( void ) mIndex ;
2018-01-11 12:38:31 -08:00
DEBUGLOG ( 8 , " ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u) " ,
2017-12-30 06:12:59 -08:00
current , ( U32 ) bestLength , ( U32 ) * offsetPtr , mIndex ) ;
}
first implementation of delayed update for btlazy2
This is a pretty nice speed win.
The new strategy consists in stacking new candidates as if it was a hash chain.
Then, only if there is a need to actually consult the chain, they are batch-updated,
before starting the match search itself.
This is supposed to be beneficial when skipping positions,
which happens a lot when using lazy strategy.
The baseline performance for btlazy2 on my laptop is :
15#calgary.tar : 3265536 -> 955985 (3.416), 7.06 MB/s , 618.0 MB/s
15#enwik7 : 10000000 -> 3067341 (3.260), 4.65 MB/s , 521.2 MB/s
15#silesia.tar : 211984896 -> 58095131 (3.649), 6.20 MB/s , 682.4 MB/s
(only level 15 remains for btlazy2, as this strategy is squeezed between lazy2 and btopt)
After this patch, and keeping all parameters identical,
speed is increased by a pretty good margin (+30-50%),
but compression ratio suffers a bit :
15#calgary.tar : 3265536 -> 958060 (3.408), 9.12 MB/s , 621.1 MB/s
15#enwik7 : 10000000 -> 3078318 (3.249), 6.37 MB/s , 525.1 MB/s
15#silesia.tar : 211984896 -> 58444111 (3.627), 9.89 MB/s , 680.4 MB/s
That's because I kept `1<<searchLog` as a maximum number of candidates to update.
But for a hash chain, this represents the total number of candidates in the chain,
while for the binary, it represents the maximum depth of searches.
Keep in mind that a lot of candidates won't even be visited in the btree,
since they are filtered out by the binary sort.
As a consequence, in the new implementation,
the effective depth of the binary tree is substantially shorter.
To compensate, it's enough to increase `searchLog` value.
Here is the result after adding just +1 to searchLog (level 15 setting in this patch):
15#calgary.tar : 3265536 -> 956311 (3.415), 8.32 MB/s , 611.4 MB/s
15#enwik7 : 10000000 -> 3067655 (3.260), 5.43 MB/s , 535.5 MB/s
15#silesia.tar : 211984896 -> 58113144 (3.648), 8.35 MB/s , 679.3 MB/s
aka, almost the same compression ratio as before,
but with a noticeable speed increase (+20-30%).
This modification makes btlazy2 more competitive.
A new round of paramgrill will be necessary to determine which levels are impacted and could adopt the new strategy.
2017-12-28 07:58:57 -08:00
return bestLength ;
}
2017-09-01 18:28:35 -07:00
}
/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
2018-06-14 11:53:36 -07:00
FORCE_INLINE_TEMPLATE size_t ZSTD_BtFindBestMatch (
2017-12-12 16:51:00 -08:00
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
2017-09-01 18:28:35 -07:00
const BYTE * const ip , const BYTE * const iLimit ,
size_t * offsetPtr ,
2018-05-16 01:32:21 -07:00
const U32 mls /* template */ ,
const ZSTD_dictMode_e dictMode )
2017-09-01 18:28:35 -07:00
{
2017-12-30 06:12:59 -08:00
DEBUGLOG ( 7 , " ZSTD_BtFindBestMatch " ) ;
2018-02-23 16:48:18 -08:00
if ( ip < ms - > window . base + ms - > nextToUpdate ) return 0 ; /* skipped area */
2017-12-12 16:51:00 -08:00
ZSTD_updateDUBT ( ms , cParams , ip , iLimit , mls ) ;
2018-05-16 01:32:21 -07:00
return ZSTD_DUBT_findBestMatch ( ms , cParams , ip , iLimit , offsetPtr , mls , dictMode ) ;
2017-09-01 18:28:35 -07:00
}
static size_t ZSTD_BtFindBestMatch_selectMLS (
2017-12-12 16:51:00 -08:00
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
2017-09-01 18:28:35 -07:00
const BYTE * ip , const BYTE * const iLimit ,
2018-06-01 11:23:14 -07:00
size_t * offsetPtr )
{
switch ( cParams - > searchLength )
{
default : /* includes case 3 */
case 4 : return ZSTD_BtFindBestMatch ( ms , cParams , ip , iLimit , offsetPtr , 4 , ZSTD_noDict ) ;
case 5 : return ZSTD_BtFindBestMatch ( ms , cParams , ip , iLimit , offsetPtr , 5 , ZSTD_noDict ) ;
case 7 :
case 6 : return ZSTD_BtFindBestMatch ( ms , cParams , ip , iLimit , offsetPtr , 6 , ZSTD_noDict ) ;
}
}
static size_t ZSTD_BtFindBestMatch_dictMatchState_selectMLS (
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
const BYTE * ip , const BYTE * const iLimit ,
size_t * offsetPtr )
{
switch ( cParams - > searchLength )
{
default : /* includes case 3 */
case 4 : return ZSTD_BtFindBestMatch ( ms , cParams , ip , iLimit , offsetPtr , 4 , ZSTD_dictMatchState ) ;
case 5 : return ZSTD_BtFindBestMatch ( ms , cParams , ip , iLimit , offsetPtr , 5 , ZSTD_dictMatchState ) ;
case 7 :
case 6 : return ZSTD_BtFindBestMatch ( ms , cParams , ip , iLimit , offsetPtr , 6 , ZSTD_dictMatchState ) ;
}
}
static size_t ZSTD_BtFindBestMatch_extDict_selectMLS (
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
const BYTE * ip , const BYTE * const iLimit ,
size_t * offsetPtr )
2017-09-01 18:28:35 -07:00
{
2017-12-12 16:51:00 -08:00
switch ( cParams - > searchLength )
2017-09-01 18:28:35 -07:00
{
default : /* includes case 3 */
2018-06-01 11:23:14 -07:00
case 4 : return ZSTD_BtFindBestMatch ( ms , cParams , ip , iLimit , offsetPtr , 4 , ZSTD_extDict ) ;
case 5 : return ZSTD_BtFindBestMatch ( ms , cParams , ip , iLimit , offsetPtr , 5 , ZSTD_extDict ) ;
2017-09-01 18:28:35 -07:00
case 7 :
2018-06-01 11:23:14 -07:00
case 6 : return ZSTD_BtFindBestMatch ( ms , cParams , ip , iLimit , offsetPtr , 6 , ZSTD_extDict ) ;
2017-09-01 18:28:35 -07:00
}
}
/* *********************************
* Hash Chain
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
/* Update chains up to ip (excluded)
Assumption : always within prefix ( i . e . not within extDict ) */
2017-12-12 16:51:00 -08:00
static U32 ZSTD_insertAndFindFirstIndex_internal (
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
const BYTE * ip , U32 const mls )
2017-09-01 18:28:35 -07:00
{
2017-12-12 16:51:00 -08:00
U32 * const hashTable = ms - > hashTable ;
const U32 hashLog = cParams - > hashLog ;
U32 * const chainTable = ms - > chainTable ;
const U32 chainMask = ( 1 < < cParams - > chainLog ) - 1 ;
2018-02-23 16:48:18 -08:00
const BYTE * const base = ms - > window . base ;
2017-09-01 18:28:35 -07:00
const U32 target = ( U32 ) ( ip - base ) ;
2017-12-12 16:51:00 -08:00
U32 idx = ms - > nextToUpdate ;
2017-09-01 18:28:35 -07:00
while ( idx < target ) { /* catch up */
size_t const h = ZSTD_hashPtr ( base + idx , hashLog , mls ) ;
NEXT_IN_CHAIN ( idx , chainMask ) = hashTable [ h ] ;
hashTable [ h ] = idx ;
idx + + ;
}
2017-12-12 16:51:00 -08:00
ms - > nextToUpdate = target ;
2017-09-01 18:28:35 -07:00
return hashTable [ ZSTD_hashPtr ( ip , hashLog , mls ) ] ;
}
2017-12-12 16:51:00 -08:00
U32 ZSTD_insertAndFindFirstIndex (
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
const BYTE * ip )
{
return ZSTD_insertAndFindFirstIndex_internal ( ms , cParams , ip , cParams - > searchLength ) ;
}
2017-09-01 18:28:35 -07:00
/* inlining is important to hardwire a hot branch (template emulation) */
FORCE_INLINE_TEMPLATE
size_t ZSTD_HcFindBestMatch_generic (
2017-12-12 16:51:00 -08:00
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
2017-09-01 18:28:35 -07:00
const BYTE * const ip , const BYTE * const iLimit ,
size_t * offsetPtr ,
2018-05-16 01:07:09 -07:00
const U32 mls , const ZSTD_dictMode_e dictMode )
2017-09-01 18:28:35 -07:00
{
2017-12-12 16:51:00 -08:00
U32 * const chainTable = ms - > chainTable ;
const U32 chainSize = ( 1 < < cParams - > chainLog ) ;
2017-09-01 18:28:35 -07:00
const U32 chainMask = chainSize - 1 ;
2018-02-23 16:48:18 -08:00
const BYTE * const base = ms - > window . base ;
const BYTE * const dictBase = ms - > window . dictBase ;
const U32 dictLimit = ms - > window . dictLimit ;
2017-09-01 18:28:35 -07:00
const BYTE * const prefixStart = base + dictLimit ;
const BYTE * const dictEnd = dictBase + dictLimit ;
2018-02-23 16:48:18 -08:00
const U32 lowLimit = ms - > window . lowLimit ;
2017-09-01 18:28:35 -07:00
const U32 current = ( U32 ) ( ip - base ) ;
const U32 minChain = current > chainSize ? current - chainSize : 0 ;
2017-12-12 16:51:00 -08:00
U32 nbAttempts = 1U < < cParams - > searchLog ;
2017-09-01 18:28:35 -07:00
size_t ml = 4 - 1 ;
/* HC4 match finder */
2017-12-12 16:51:00 -08:00
U32 matchIndex = ZSTD_insertAndFindFirstIndex_internal ( ms , cParams , ip , mls ) ;
2017-09-01 18:28:35 -07:00
for ( ; ( matchIndex > lowLimit ) & ( nbAttempts > 0 ) ; nbAttempts - - ) {
size_t currentMl = 0 ;
2018-05-16 01:07:09 -07:00
if ( ( dictMode ! = ZSTD_extDict ) | | matchIndex > = dictLimit ) {
2017-11-19 14:40:21 -08:00
const BYTE * const match = base + matchIndex ;
2017-09-01 18:28:35 -07:00
if ( match [ ml ] = = ip [ ml ] ) /* potentially better */
currentMl = ZSTD_count ( ip , match , iLimit ) ;
} else {
2017-11-19 14:40:21 -08:00
const BYTE * const match = dictBase + matchIndex ;
assert ( match + 4 < = dictEnd ) ;
2017-09-01 18:28:35 -07:00
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 ;
}
/* save best solution */
if ( currentMl > ml ) {
ml = currentMl ;
* offsetPtr = current - matchIndex + ZSTD_REP_MOVE ;
if ( ip + currentMl = = iLimit ) break ; /* best possible, avoids read overflow on next attempt */
}
if ( matchIndex < = minChain ) break ;
matchIndex = NEXT_IN_CHAIN ( matchIndex , chainMask ) ;
}
2018-05-29 13:26:23 -07:00
if ( dictMode = = ZSTD_dictMatchState ) {
const ZSTD_matchState_t * const dms = ms - > dictMatchState ;
const U32 * const dmsChainTable = dms - > chainTable ;
const U32 dmsLowestIndex = dms - > window . dictLimit ;
const BYTE * const dmsBase = dms - > window . base ;
const BYTE * const dmsEnd = dms - > window . nextSrc ;
const U32 dmsSize = ( U32 ) ( dmsEnd - dmsBase ) ;
const U32 dmsIndexDelta = dictLimit - dmsSize ;
const U32 dmsMinChain = dmsSize > chainSize ? dmsSize - chainSize : 0 ;
matchIndex = dms - > hashTable [ ZSTD_hashPtr ( ip , cParams - > hashLog , mls ) ] ;
for ( ; ( matchIndex > dmsLowestIndex ) & ( nbAttempts > 0 ) ; nbAttempts - - ) {
size_t currentMl = 0 ;
const BYTE * const match = dmsBase + matchIndex ;
assert ( match + 4 < = dmsEnd ) ;
if ( MEM_read32 ( match ) = = MEM_read32 ( ip ) ) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
currentMl = ZSTD_count_2segments ( ip + 4 , match + 4 , iLimit , dmsEnd , prefixStart ) + 4 ;
/* save best solution */
if ( currentMl > ml ) {
ml = currentMl ;
* offsetPtr = current - ( matchIndex + dmsIndexDelta ) + ZSTD_REP_MOVE ;
if ( ip + currentMl = = iLimit ) break ; /* best possible, avoids read overflow on next attempt */
}
if ( matchIndex < = dmsMinChain ) break ;
matchIndex = dmsChainTable [ matchIndex & chainMask ] ;
}
}
2017-09-01 18:28:35 -07:00
return ml ;
}
FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
2017-12-12 16:51:00 -08:00
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
2017-09-01 18:28:35 -07:00
const BYTE * ip , const BYTE * const iLimit ,
2018-06-01 11:23:14 -07:00
size_t * offsetPtr )
{
switch ( cParams - > searchLength )
{
default : /* includes case 3 */
case 4 : return ZSTD_HcFindBestMatch_generic ( ms , cParams , ip , iLimit , offsetPtr , 4 , ZSTD_noDict ) ;
case 5 : return ZSTD_HcFindBestMatch_generic ( ms , cParams , ip , iLimit , offsetPtr , 5 , ZSTD_noDict ) ;
case 7 :
case 6 : return ZSTD_HcFindBestMatch_generic ( ms , cParams , ip , iLimit , offsetPtr , 6 , ZSTD_noDict ) ;
}
}
2018-06-07 13:55:13 -07:00
static size_t ZSTD_HcFindBestMatch_dictMatchState_selectMLS (
2018-06-01 11:23:14 -07:00
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
const BYTE * ip , const BYTE * const iLimit ,
size_t * offsetPtr )
{
switch ( cParams - > searchLength )
{
default : /* includes case 3 */
case 4 : return ZSTD_HcFindBestMatch_generic ( ms , cParams , ip , iLimit , offsetPtr , 4 , ZSTD_dictMatchState ) ;
case 5 : return ZSTD_HcFindBestMatch_generic ( ms , cParams , ip , iLimit , offsetPtr , 5 , ZSTD_dictMatchState ) ;
case 7 :
case 6 : return ZSTD_HcFindBestMatch_generic ( ms , cParams , ip , iLimit , offsetPtr , 6 , ZSTD_dictMatchState ) ;
}
}
FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
const BYTE * ip , const BYTE * const iLimit ,
size_t * offsetPtr )
2017-09-01 18:28:35 -07:00
{
2017-12-12 16:51:00 -08:00
switch ( cParams - > searchLength )
2017-09-01 18:28:35 -07:00
{
default : /* includes case 3 */
2018-06-01 11:23:14 -07:00
case 4 : return ZSTD_HcFindBestMatch_generic ( ms , cParams , ip , iLimit , offsetPtr , 4 , ZSTD_extDict ) ;
case 5 : return ZSTD_HcFindBestMatch_generic ( ms , cParams , ip , iLimit , offsetPtr , 5 , ZSTD_extDict ) ;
2017-09-01 18:28:35 -07:00
case 7 :
2018-06-01 11:23:14 -07:00
case 6 : return ZSTD_HcFindBestMatch_generic ( ms , cParams , ip , iLimit , offsetPtr , 6 , ZSTD_extDict ) ;
2017-09-01 18:28:35 -07:00
}
}
/* *******************************
* Common parser - lazy strategy
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
FORCE_INLINE_TEMPLATE
2017-12-12 16:51:00 -08:00
size_t ZSTD_compressBlock_lazy_generic (
ZSTD_matchState_t * ms , seqStore_t * seqStore ,
U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams ,
const void * src , size_t srcSize ,
2018-05-15 23:26:07 -07:00
const U32 searchMethod , const U32 depth ,
ZSTD_dictMode_e const dictMode )
2017-09-01 18:28:35 -07:00
{
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 ;
2018-05-23 12:06:24 -07:00
const BYTE * const base = ms - > window . base ;
const U32 prefixLowestIndex = ms - > window . dictLimit ;
const BYTE * const prefixLowest = base + prefixLowestIndex ;
2017-09-01 18:28:35 -07:00
2017-12-12 16:51:00 -08:00
typedef size_t ( * searchMax_f ) (
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
2018-06-01 11:23:14 -07:00
const BYTE * ip , const BYTE * iLimit , size_t * offsetPtr ) ;
searchMax_f const searchMax = dictMode = = ZSTD_dictMatchState ?
( searchMethod ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS : ZSTD_HcFindBestMatch_dictMatchState_selectMLS ) :
( searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS ) ;
2017-12-12 16:51:00 -08:00
U32 offset_1 = rep [ 0 ] , offset_2 = rep [ 1 ] , savedOffset = 0 ;
2017-09-01 18:28:35 -07:00
2018-05-23 11:13:16 -07:00
const ZSTD_matchState_t * const dms = ms - > dictMatchState ;
const U32 dictLowestIndex = dictMode = = ZSTD_dictMatchState ?
dms - > window . dictLimit : 0 ;
const BYTE * const dictBase = dictMode = = ZSTD_dictMatchState ?
dms - > window . base : NULL ;
const BYTE * const dictLowest = dictMode = = ZSTD_dictMatchState ?
dictBase + dictLowestIndex : NULL ;
const BYTE * const dictEnd = dictMode = = ZSTD_dictMatchState ?
dms - > window . nextSrc : NULL ;
2018-05-23 12:06:24 -07:00
const U32 dictIndexDelta = dictMode = = ZSTD_dictMatchState ?
prefixLowestIndex - ( U32 ) ( dictEnd - dictBase ) :
0 ;
2018-05-23 11:13:16 -07:00
const U32 dictAndPrefixLength = ( U32 ) ( ip - prefixLowest + dictEnd - dictLowest ) ;
2018-05-15 23:26:07 -07:00
( void ) dictMode ;
2017-09-01 18:28:35 -07:00
/* init */
2018-05-23 11:13:16 -07:00
ip + = ( dictAndPrefixLength = = 0 ) ;
2017-12-12 16:51:00 -08:00
ms - > nextToUpdate3 = ms - > nextToUpdate ;
2018-05-23 11:13:16 -07:00
if ( dictMode = = ZSTD_noDict ) {
U32 const maxRep = ( U32 ) ( ip - prefixLowest ) ;
2017-09-01 18:28:35 -07:00
if ( offset_2 > maxRep ) savedOffset = offset_2 , offset_2 = 0 ;
if ( offset_1 > maxRep ) savedOffset = offset_1 , offset_1 = 0 ;
}
2018-05-23 11:13:16 -07:00
if ( dictMode = = ZSTD_dictMatchState ) {
/* dictMatchState repCode checks don't currently handle repCode == 0
* disabling . */
assert ( offset_1 < = dictAndPrefixLength ) ;
assert ( offset_2 < = dictAndPrefixLength ) ;
}
2017-09-01 18:28:35 -07:00
/* Match Loop */
while ( ip < ilimit ) {
size_t matchLength = 0 ;
size_t offset = 0 ;
const BYTE * start = ip + 1 ;
/* check repCode */
2018-06-06 16:54:13 -07:00
if ( dictMode = = ZSTD_dictMatchState ) {
const U32 repIndex = ( U32 ) ( ip - base ) + 1 - offset_1 ;
const BYTE * repMatch = ( dictMode = = ZSTD_dictMatchState
& & repIndex < prefixLowestIndex ) ?
dictBase + ( repIndex - dictIndexDelta ) :
base + repIndex ;
if ( ( ( U32 ) ( ( prefixLowestIndex - 1 ) - repIndex ) > = 3 /* intentional underflow */ )
& & ( MEM_read32 ( repMatch ) = = MEM_read32 ( ip + 1 ) ) ) {
const BYTE * repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend ;
matchLength = ZSTD_count_2segments ( ip + 1 + 4 , repMatch + 4 , iend , repMatchEnd , prefixLowest ) + 4 ;
if ( depth = = 0 ) goto _storeSequence ;
}
}
if ( dictMode = = ZSTD_noDict
& & ( ( offset_1 > 0 ) & ( MEM_read32 ( ip + 1 - offset_1 ) = = MEM_read32 ( ip + 1 ) ) ) ) {
2018-05-23 12:06:24 -07:00
matchLength = ZSTD_count ( ip + 1 + 4 , ip + 1 + 4 - offset_1 , iend ) + 4 ;
2017-09-01 18:28:35 -07:00
if ( depth = = 0 ) goto _storeSequence ;
}
/* first search (depth 0) */
{ size_t offsetFound = 99999999 ;
2018-06-01 11:23:14 -07:00
size_t const ml2 = searchMax ( ms , cParams , ip , iend , & offsetFound ) ;
2017-09-01 18:28:35 -07:00
if ( ml2 > matchLength )
matchLength = ml2 , start = ip , offset = offsetFound ;
}
if ( matchLength < 4 ) {
2018-02-02 16:31:20 -08:00
ip + = ( ( ip - anchor ) > > kSearchStrength ) + 1 ; /* jump faster over incompressible sections */
2017-09-01 18:28:35 -07:00
continue ;
}
/* let's try to find a better solution */
if ( depth > = 1 )
while ( ip < ilimit ) {
ip + + ;
2018-06-06 16:54:13 -07:00
if ( ( dictMode = = ZSTD_noDict )
& & ( offset ) & & ( ( offset_1 > 0 ) & ( MEM_read32 ( ip ) = = MEM_read32 ( ip - offset_1 ) ) ) ) {
2017-09-01 18:28:35 -07:00
size_t const mlRep = ZSTD_count ( ip + 4 , ip + 4 - offset_1 , iend ) + 4 ;
int const gain2 = ( int ) ( mlRep * 3 ) ;
int const gain1 = ( int ) ( matchLength * 3 - ZSTD_highbit32 ( ( U32 ) offset + 1 ) + 1 ) ;
if ( ( mlRep > = 4 ) & & ( gain2 > gain1 ) )
matchLength = mlRep , offset = 0 , start = ip ;
}
2018-06-06 16:54:13 -07:00
if ( dictMode = = ZSTD_dictMatchState ) {
const U32 repIndex = ( U32 ) ( ip - base ) - offset_1 ;
const BYTE * repMatch = repIndex < prefixLowestIndex ?
dictBase + ( repIndex - dictIndexDelta ) :
base + repIndex ;
if ( ( ( U32 ) ( ( prefixLowestIndex - 1 ) - repIndex ) > = 3 /* intentional underflow */ )
& & ( MEM_read32 ( repMatch ) = = MEM_read32 ( ip ) ) ) {
const BYTE * repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend ;
size_t const mlRep = ZSTD_count_2segments ( ip + 4 , repMatch + 4 , iend , repMatchEnd , prefixLowest ) + 4 ;
int const gain2 = ( int ) ( mlRep * 3 ) ;
int const gain1 = ( int ) ( matchLength * 3 - ZSTD_highbit32 ( ( U32 ) offset + 1 ) + 1 ) ;
if ( ( mlRep > = 4 ) & & ( gain2 > gain1 ) )
matchLength = mlRep , offset = 0 , start = ip ;
}
}
2017-09-01 18:28:35 -07:00
{ size_t offset2 = 99999999 ;
2018-06-01 11:23:14 -07:00
size_t const ml2 = searchMax ( ms , cParams , ip , iend , & offset2 ) ;
2017-09-01 18:28:35 -07:00
int const gain2 = ( int ) ( ml2 * 4 - ZSTD_highbit32 ( ( U32 ) offset2 + 1 ) ) ; /* raw approx */
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit32 ( ( U32 ) offset + 1 ) + 4 ) ;
if ( ( ml2 > = 4 ) & & ( gain2 > gain1 ) ) {
matchLength = ml2 , offset = offset2 , start = ip ;
continue ; /* search a better one */
} }
/* let's find an even better one */
if ( ( depth = = 2 ) & & ( ip < ilimit ) ) {
ip + + ;
2018-06-06 16:54:13 -07:00
if ( ( dictMode = = ZSTD_noDict )
& & ( offset ) & & ( ( offset_1 > 0 ) & ( MEM_read32 ( ip ) = = MEM_read32 ( ip - offset_1 ) ) ) ) {
size_t const mlRep = ZSTD_count ( ip + 4 , ip + 4 - offset_1 , iend ) + 4 ;
int const gain2 = ( int ) ( mlRep * 4 ) ;
2017-09-01 18:28:35 -07:00
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit32 ( ( U32 ) offset + 1 ) + 1 ) ;
2018-06-06 16:54:13 -07:00
if ( ( mlRep > = 4 ) & & ( gain2 > gain1 ) )
matchLength = mlRep , offset = 0 , start = ip ;
}
if ( dictMode = = ZSTD_dictMatchState ) {
const U32 repIndex = ( U32 ) ( ip - base ) - offset_1 ;
const BYTE * repMatch = repIndex < prefixLowestIndex ?
dictBase + ( repIndex - dictIndexDelta ) :
base + repIndex ;
if ( ( ( U32 ) ( ( prefixLowestIndex - 1 ) - repIndex ) > = 3 /* intentional underflow */ )
& & ( MEM_read32 ( repMatch ) = = MEM_read32 ( ip ) ) ) {
const BYTE * repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend ;
size_t const mlRep = ZSTD_count_2segments ( ip + 4 , repMatch + 4 , iend , repMatchEnd , prefixLowest ) + 4 ;
int const gain2 = ( int ) ( mlRep * 4 ) ;
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit32 ( ( U32 ) offset + 1 ) + 1 ) ;
if ( ( mlRep > = 4 ) & & ( gain2 > gain1 ) )
matchLength = mlRep , offset = 0 , start = ip ;
}
2017-09-01 18:28:35 -07:00
}
{ size_t offset2 = 99999999 ;
2018-06-01 11:23:14 -07:00
size_t const ml2 = searchMax ( ms , cParams , ip , iend , & offset2 ) ;
2017-09-01 18:28:35 -07:00
int const gain2 = ( int ) ( ml2 * 4 - ZSTD_highbit32 ( ( U32 ) offset2 + 1 ) ) ; /* raw approx */
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit32 ( ( U32 ) offset + 1 ) + 7 ) ;
if ( ( ml2 > = 4 ) & & ( gain2 > gain1 ) ) {
matchLength = ml2 , offset = offset2 , start = ip ;
continue ;
} } }
break ; /* nothing found : store previous solution */
}
/* NOTE:
* start [ - offset + ZSTD_REP_MOVE - 1 ] is undefined behavior .
* ( - offset + ZSTD_REP_MOVE - 1 ) is unsigned , and is added to start , which
* overflows the pointer , which is undefined behavior .
*/
/* catch up */
if ( offset ) {
2018-06-08 12:06:47 -07:00
if ( dictMode = = ZSTD_noDict ) {
while ( ( ( start > anchor ) & ( start - ( offset - ZSTD_REP_MOVE ) > prefixLowest ) )
& & ( start [ - 1 ] = = ( start - ( offset - ZSTD_REP_MOVE ) ) [ - 1 ] ) ) /* only search for offset within prefix */
{ start - - ; matchLength + + ; }
}
if ( dictMode = = ZSTD_dictMatchState ) {
U32 const matchIndex = ( U32 ) ( ( start - base ) - ( offset - ZSTD_REP_MOVE ) ) ;
const BYTE * match = ( matchIndex < prefixLowestIndex ) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex ;
const BYTE * const mStart = ( matchIndex < prefixLowestIndex ) ? dictLowest : prefixLowest ;
while ( ( start > anchor ) & & ( match > mStart ) & & ( start [ - 1 ] = = match [ - 1 ] ) ) { start - - ; match - - ; matchLength + + ; } /* catch up */
}
2017-09-01 18:28:35 -07:00
offset_2 = offset_1 ; offset_1 = ( U32 ) ( offset - ZSTD_REP_MOVE ) ;
}
/* store sequence */
_storeSequence :
{ size_t const litLength = start - anchor ;
2017-12-12 16:51:00 -08:00
ZSTD_storeSeq ( seqStore , litLength , anchor , ( U32 ) offset , matchLength - MINMATCH ) ;
2017-09-01 18:28:35 -07:00
anchor = ip = start + matchLength ;
}
/* check immediate repcode */
2018-05-23 12:49:43 -07:00
if ( dictMode = = ZSTD_dictMatchState ) {
while ( ip < = ilimit ) {
U32 const current2 = ( U32 ) ( ip - base ) ;
2018-06-06 16:54:13 -07:00
U32 const repIndex = current2 - offset_2 ;
const BYTE * repMatch = dictMode = = ZSTD_dictMatchState
& & repIndex < prefixLowestIndex ?
dictBase - dictIndexDelta + repIndex :
base + repIndex ;
if ( ( ( U32 ) ( ( prefixLowestIndex - 1 ) - ( U32 ) repIndex ) > = 3 /* intentional overflow */ )
& & ( MEM_read32 ( repMatch ) = = MEM_read32 ( ip ) ) ) {
const BYTE * const repEnd2 = repIndex < prefixLowestIndex ? dictEnd : iend ;
matchLength = ZSTD_count_2segments ( ip + 4 , repMatch + 4 , iend , repEnd2 , prefixLowest ) + 4 ;
2018-06-09 14:19:04 -07:00
offset = offset_2 ; offset_2 = offset_1 ; offset_1 = ( U32 ) offset ; /* swap offset_2 <=> offset_1 */
2018-05-23 12:49:43 -07:00
ZSTD_storeSeq ( seqStore , 0 , anchor , 0 , matchLength - MINMATCH ) ;
ip + = matchLength ;
anchor = ip ;
continue ;
}
break ;
}
}
if ( dictMode = = ZSTD_noDict ) {
while ( ( ( ip < = ilimit ) & ( offset_2 > 0 ) )
& & ( MEM_read32 ( ip ) = = MEM_read32 ( ip - offset_2 ) ) ) {
/* store sequence */
matchLength = ZSTD_count ( ip + 4 , ip + 4 - offset_2 , iend ) + 4 ;
offset = offset_2 ; offset_2 = offset_1 ; offset_1 = ( U32 ) offset ; /* swap repcodes */
ZSTD_storeSeq ( seqStore , 0 , anchor , 0 , matchLength - MINMATCH ) ;
ip + = matchLength ;
anchor = ip ;
continue ; /* faster when present ... (?) */
} } }
2017-09-01 18:28:35 -07:00
/* Save reps for next block */
2017-12-12 16:51:00 -08:00
rep [ 0 ] = offset_1 ? offset_1 : savedOffset ;
rep [ 1 ] = offset_2 ? offset_2 : savedOffset ;
2017-09-01 18:28:35 -07:00
2017-09-06 15:56:32 -07:00
/* Return the last literals size */
return iend - anchor ;
2017-09-01 18:28:35 -07:00
}
2017-12-12 16:51:00 -08:00
size_t ZSTD_compressBlock_btlazy2 (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
2017-09-01 18:28:35 -07:00
{
2018-05-15 23:26:07 -07:00
return ZSTD_compressBlock_lazy_generic ( ms , seqStore , rep , cParams , src , srcSize , 1 , 2 , ZSTD_noDict ) ;
2017-09-01 18:28:35 -07:00
}
2017-12-12 16:51:00 -08:00
size_t ZSTD_compressBlock_lazy2 (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
2017-09-01 18:28:35 -07:00
{
2018-05-15 23:26:07 -07:00
return ZSTD_compressBlock_lazy_generic ( ms , seqStore , rep , cParams , src , srcSize , 0 , 2 , ZSTD_noDict ) ;
2017-09-01 18:28:35 -07:00
}
2017-12-12 16:51:00 -08:00
size_t ZSTD_compressBlock_lazy (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
2017-09-01 18:28:35 -07:00
{
2018-05-15 23:26:07 -07:00
return ZSTD_compressBlock_lazy_generic ( ms , seqStore , rep , cParams , src , srcSize , 0 , 1 , ZSTD_noDict ) ;
2017-09-01 18:28:35 -07:00
}
2017-12-12 16:51:00 -08:00
size_t ZSTD_compressBlock_greedy (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
2017-09-01 18:28:35 -07:00
{
2018-05-15 23:26:07 -07:00
return ZSTD_compressBlock_lazy_generic ( ms , seqStore , rep , cParams , src , srcSize , 0 , 0 , ZSTD_noDict ) ;
2017-09-01 18:28:35 -07:00
}
2018-05-15 23:30:20 -07:00
size_t ZSTD_compressBlock_btlazy2_dictMatchState (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
{
return ZSTD_compressBlock_lazy_generic ( ms , seqStore , rep , cParams , src , srcSize , 1 , 2 , ZSTD_dictMatchState ) ;
}
size_t ZSTD_compressBlock_lazy2_dictMatchState (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
{
return ZSTD_compressBlock_lazy_generic ( ms , seqStore , rep , cParams , src , srcSize , 0 , 2 , ZSTD_dictMatchState ) ;
}
size_t ZSTD_compressBlock_lazy_dictMatchState (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
{
return ZSTD_compressBlock_lazy_generic ( ms , seqStore , rep , cParams , src , srcSize , 0 , 1 , ZSTD_dictMatchState ) ;
}
size_t ZSTD_compressBlock_greedy_dictMatchState (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
{
return ZSTD_compressBlock_lazy_generic ( ms , seqStore , rep , cParams , src , srcSize , 0 , 0 , ZSTD_dictMatchState ) ;
}
2017-09-01 18:28:35 -07:00
FORCE_INLINE_TEMPLATE
2017-12-12 16:51:00 -08:00
size_t ZSTD_compressBlock_lazy_extDict_generic (
ZSTD_matchState_t * ms , seqStore_t * seqStore ,
U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams ,
const void * src , size_t srcSize ,
const U32 searchMethod , const U32 depth )
2017-09-01 18:28:35 -07:00
{
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 ;
2018-02-23 16:48:18 -08:00
const BYTE * const base = ms - > window . base ;
const U32 dictLimit = ms - > window . dictLimit ;
const U32 lowestIndex = ms - > window . lowLimit ;
2017-09-01 18:28:35 -07:00
const BYTE * const prefixStart = base + dictLimit ;
2018-02-23 16:48:18 -08:00
const BYTE * const dictBase = ms - > window . dictBase ;
2017-09-01 18:28:35 -07:00
const BYTE * const dictEnd = dictBase + dictLimit ;
2018-02-23 16:48:18 -08:00
const BYTE * const dictStart = dictBase + lowestIndex ;
2017-09-01 18:28:35 -07:00
2017-12-12 16:51:00 -08:00
typedef size_t ( * searchMax_f ) (
ZSTD_matchState_t * ms , ZSTD_compressionParameters const * cParams ,
2018-06-01 11:23:14 -07:00
const BYTE * ip , const BYTE * iLimit , size_t * offsetPtr ) ;
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS ;
2017-09-01 18:28:35 -07:00
2017-12-12 16:51:00 -08:00
U32 offset_1 = rep [ 0 ] , offset_2 = rep [ 1 ] ;
2017-09-01 18:28:35 -07:00
/* init */
2017-12-12 16:51:00 -08:00
ms - > nextToUpdate3 = ms - > nextToUpdate ;
2017-09-01 18:28:35 -07:00
ip + = ( ip = = prefixStart ) ;
/* Match Loop */
while ( ip < ilimit ) {
size_t matchLength = 0 ;
size_t offset = 0 ;
const BYTE * start = ip + 1 ;
U32 current = ( U32 ) ( ip - base ) ;
/* check repCode */
{ const U32 repIndex = ( U32 ) ( current + 1 - offset_1 ) ;
const BYTE * const repBase = repIndex < dictLimit ? dictBase : base ;
const BYTE * const repMatch = repBase + repIndex ;
if ( ( ( U32 ) ( ( dictLimit - 1 ) - repIndex ) > = 3 ) & ( repIndex > lowestIndex ) ) /* intentional overflow */
if ( MEM_read32 ( ip + 1 ) = = MEM_read32 ( repMatch ) ) {
/* repcode detected we should take it */
const BYTE * const repEnd = repIndex < dictLimit ? dictEnd : iend ;
matchLength = ZSTD_count_2segments ( ip + 1 + 4 , repMatch + 4 , iend , repEnd , prefixStart ) + 4 ;
if ( depth = = 0 ) goto _storeSequence ;
} }
/* first search (depth 0) */
{ size_t offsetFound = 99999999 ;
2018-06-01 11:23:14 -07:00
size_t const ml2 = searchMax ( ms , cParams , ip , iend , & offsetFound ) ;
2017-09-01 18:28:35 -07:00
if ( ml2 > matchLength )
matchLength = ml2 , start = ip , offset = offsetFound ;
}
if ( matchLength < 4 ) {
2018-02-02 16:31:20 -08:00
ip + = ( ( ip - anchor ) > > kSearchStrength ) + 1 ; /* jump faster over incompressible sections */
2017-09-01 18:28:35 -07:00
continue ;
}
/* let's try to find a better solution */
if ( depth > = 1 )
while ( ip < ilimit ) {
ip + + ;
current + + ;
/* check repCode */
if ( offset ) {
const U32 repIndex = ( U32 ) ( current - offset_1 ) ;
const BYTE * const repBase = repIndex < dictLimit ? dictBase : base ;
const BYTE * const repMatch = repBase + repIndex ;
if ( ( ( U32 ) ( ( dictLimit - 1 ) - repIndex ) > = 3 ) & ( repIndex > lowestIndex ) ) /* intentional overflow */
if ( MEM_read32 ( ip ) = = MEM_read32 ( repMatch ) ) {
/* repcode detected */
const BYTE * const repEnd = repIndex < dictLimit ? dictEnd : iend ;
size_t const repLength = ZSTD_count_2segments ( ip + 4 , repMatch + 4 , iend , repEnd , prefixStart ) + 4 ;
int const gain2 = ( int ) ( repLength * 3 ) ;
int const gain1 = ( int ) ( matchLength * 3 - ZSTD_highbit32 ( ( U32 ) offset + 1 ) + 1 ) ;
if ( ( repLength > = 4 ) & & ( gain2 > gain1 ) )
matchLength = repLength , offset = 0 , start = ip ;
} }
/* search match, depth 1 */
{ size_t offset2 = 99999999 ;
2018-06-01 11:23:14 -07:00
size_t const ml2 = searchMax ( ms , cParams , ip , iend , & offset2 ) ;
2017-09-01 18:28:35 -07:00
int const gain2 = ( int ) ( ml2 * 4 - ZSTD_highbit32 ( ( U32 ) offset2 + 1 ) ) ; /* raw approx */
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit32 ( ( U32 ) offset + 1 ) + 4 ) ;
if ( ( ml2 > = 4 ) & & ( gain2 > gain1 ) ) {
matchLength = ml2 , offset = offset2 , start = ip ;
continue ; /* search a better one */
} }
/* let's find an even better one */
if ( ( depth = = 2 ) & & ( ip < ilimit ) ) {
ip + + ;
current + + ;
/* check repCode */
if ( offset ) {
const U32 repIndex = ( U32 ) ( current - offset_1 ) ;
const BYTE * const repBase = repIndex < dictLimit ? dictBase : base ;
const BYTE * const repMatch = repBase + repIndex ;
if ( ( ( U32 ) ( ( dictLimit - 1 ) - repIndex ) > = 3 ) & ( repIndex > lowestIndex ) ) /* intentional overflow */
if ( MEM_read32 ( ip ) = = MEM_read32 ( repMatch ) ) {
/* repcode detected */
const BYTE * const repEnd = repIndex < dictLimit ? dictEnd : iend ;
size_t const repLength = ZSTD_count_2segments ( ip + 4 , repMatch + 4 , iend , repEnd , prefixStart ) + 4 ;
int const gain2 = ( int ) ( repLength * 4 ) ;
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit32 ( ( U32 ) offset + 1 ) + 1 ) ;
if ( ( repLength > = 4 ) & & ( gain2 > gain1 ) )
matchLength = repLength , offset = 0 , start = ip ;
} }
/* search match, depth 2 */
{ size_t offset2 = 99999999 ;
2018-06-01 11:23:14 -07:00
size_t const ml2 = searchMax ( ms , cParams , ip , iend , & offset2 ) ;
2017-09-01 18:28:35 -07:00
int const gain2 = ( int ) ( ml2 * 4 - ZSTD_highbit32 ( ( U32 ) offset2 + 1 ) ) ; /* raw approx */
int const gain1 = ( int ) ( matchLength * 4 - ZSTD_highbit32 ( ( U32 ) offset + 1 ) + 7 ) ;
if ( ( ml2 > = 4 ) & & ( gain2 > gain1 ) ) {
matchLength = ml2 , offset = offset2 , start = ip ;
continue ;
} } }
break ; /* nothing found : store previous solution */
}
/* catch up */
if ( offset ) {
U32 const matchIndex = ( U32 ) ( ( start - base ) - ( offset - ZSTD_REP_MOVE ) ) ;
const BYTE * match = ( matchIndex < dictLimit ) ? dictBase + matchIndex : base + matchIndex ;
const BYTE * const mStart = ( matchIndex < dictLimit ) ? dictStart : prefixStart ;
while ( ( start > anchor ) & & ( match > mStart ) & & ( start [ - 1 ] = = match [ - 1 ] ) ) { start - - ; match - - ; matchLength + + ; } /* catch up */
offset_2 = offset_1 ; offset_1 = ( U32 ) ( offset - ZSTD_REP_MOVE ) ;
}
/* store sequence */
_storeSequence :
{ size_t const litLength = start - anchor ;
2017-12-12 16:51:00 -08:00
ZSTD_storeSeq ( seqStore , litLength , anchor , ( U32 ) offset , matchLength - MINMATCH ) ;
2017-09-01 18:28:35 -07:00
anchor = ip = start + matchLength ;
}
/* check immediate repcode */
while ( ip < = ilimit ) {
const U32 repIndex = ( U32 ) ( ( ip - base ) - offset_2 ) ;
const BYTE * const repBase = repIndex < dictLimit ? dictBase : base ;
const BYTE * const repMatch = repBase + repIndex ;
if ( ( ( U32 ) ( ( dictLimit - 1 ) - repIndex ) > = 3 ) & ( repIndex > lowestIndex ) ) /* intentional overflow */
if ( MEM_read32 ( ip ) = = MEM_read32 ( repMatch ) ) {
/* repcode detected we should take it */
const BYTE * const repEnd = repIndex < dictLimit ? dictEnd : iend ;
matchLength = ZSTD_count_2segments ( ip + 4 , repMatch + 4 , iend , repEnd , prefixStart ) + 4 ;
offset = offset_2 ; offset_2 = offset_1 ; offset_1 = ( U32 ) offset ; /* swap offset history */
2017-12-12 16:51:00 -08:00
ZSTD_storeSeq ( seqStore , 0 , anchor , 0 , matchLength - MINMATCH ) ;
2017-09-01 18:28:35 -07:00
ip + = matchLength ;
anchor = ip ;
continue ; /* faster when present ... (?) */
}
break ;
} }
/* Save reps for next block */
2017-12-12 16:51:00 -08:00
rep [ 0 ] = offset_1 ;
rep [ 1 ] = offset_2 ;
2017-09-01 18:28:35 -07:00
2017-09-06 15:56:32 -07:00
/* Return the last literals size */
return iend - anchor ;
2017-09-01 18:28:35 -07:00
}
2017-12-12 16:51:00 -08:00
size_t ZSTD_compressBlock_greedy_extDict (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
2017-09-01 18:28:35 -07:00
{
2017-12-12 16:51:00 -08:00
return ZSTD_compressBlock_lazy_extDict_generic ( ms , seqStore , rep , cParams , src , srcSize , 0 , 0 ) ;
2017-09-01 18:28:35 -07:00
}
2017-12-12 16:51:00 -08:00
size_t ZSTD_compressBlock_lazy_extDict (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
2017-09-01 18:28:35 -07:00
{
2017-12-12 16:51:00 -08:00
return ZSTD_compressBlock_lazy_extDict_generic ( ms , seqStore , rep , cParams , src , srcSize , 0 , 1 ) ;
2017-09-01 18:28:35 -07:00
}
2017-12-12 16:51:00 -08:00
size_t ZSTD_compressBlock_lazy2_extDict (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
2017-09-01 18:28:35 -07:00
{
2017-12-12 16:51:00 -08:00
return ZSTD_compressBlock_lazy_extDict_generic ( ms , seqStore , rep , cParams , src , srcSize , 0 , 2 ) ;
2017-09-01 18:28:35 -07:00
}
2017-12-12 16:51:00 -08:00
size_t ZSTD_compressBlock_btlazy2_extDict (
ZSTD_matchState_t * ms , seqStore_t * seqStore , U32 rep [ ZSTD_REP_NUM ] ,
ZSTD_compressionParameters const * cParams , void const * src , size_t srcSize )
2017-09-01 18:28:35 -07:00
{
2017-12-12 16:51:00 -08:00
return ZSTD_compressBlock_lazy_extDict_generic ( ms , seqStore , rep , cParams , src , srcSize , 1 , 2 ) ;
2017-09-01 18:28:35 -07:00
}