]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
Fixed Btree update
authorYann Collet <cyan@fb.com>
Thu, 16 Nov 2017 20:18:56 +0000 (12:18 -0800)
committerYann Collet <cyan@fb.com>
Thu, 16 Nov 2017 20:18:56 +0000 (12:18 -0800)
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.

Makefile
lib/common/mem.h
lib/compress/zstd_compress.c
lib/compress/zstd_compress_internal.h
lib/compress/zstd_lazy.c
lib/compress/zstd_opt.c
lib/compress/zstdmt_compress.c
lib/compress/zstdmt_compress.h
lib/zstd.h

index f2487c59113cdedd25efa21d58f5f28b5a9cd49e..9f4b1fe4d536a0af0c8d17ced0bf0cd8cda45ee1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -77,7 +77,7 @@ check: shortest
 
 .PHONY: test shortest
 test shortest:
-       $(MAKE) -C $(PRGDIR) allVariants
+       $(MAKE) -C $(PRGDIR) allVariants MOREFLAGS="-g -DZSTD_DEBUG=1"
        $(MAKE) -C $(TESTDIR) $@
 
 .PHONY: examples
index 23335c3146d75791188ec641ea9419a194557956..2ec328733b483c8b53f506c98c9805747d969260 100644 (file)
@@ -123,20 +123,26 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
 /* currently only defined for gcc and icc */
 #if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))
     __pragma( pack(push, 1) )
-    typedef union { U16 u16; U32 u32; U64 u64; size_t st; } unalign;
+    typedef struct { U16 v; } unalign16;
+    typedef struct { U32 v; } unalign32;
+    typedef struct { U64 v; } unalign64;
+    typedef struct { size_t v; } unalignArch;
     __pragma( pack(pop) )
 #else
-    typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign;
+    typedef struct { U16 v; } __attribute__((packed)) unalign16;
+    typedef struct { U32 v; } __attribute__((packed)) unalign32;
+    typedef struct { U64 v; } __attribute__((packed)) unalign64;
+    typedef struct { size_t v; } __attribute__((packed)) unalignArch;
 #endif
 
-MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
-MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
-MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
-MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalign*)ptr)->st; }
+MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; }
+MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; }
+MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; }
+MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; }
 
-MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
-MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
-MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; }
+MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; }
+MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; }
+MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; }
 
 #else
 
index f49e14b38c735760ee68300cafde35877098de87..0bdcc26abdc2f4d304b9d59db5eaeaf258c8a1f6 100644 (file)
@@ -142,17 +142,17 @@ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStor
 #define ZSTD_CLEVEL_CUSTOM 999
 
 static ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
-        ZSTD_CCtx_params params, U64 srcSizeHint, size_t dictSize)
+        ZSTD_CCtx_params CCtxParams, U64 srcSizeHint, size_t dictSize)
 {
-    return (params.compressionLevel == ZSTD_CLEVEL_CUSTOM ?
-                    params.cParams :
-                    ZSTD_getCParams(params.compressionLevel, srcSizeHint, dictSize));
+    return (CCtxParams.compressionLevel == ZSTD_CLEVEL_CUSTOM) ?
+                CCtxParams.cParams :
+                ZSTD_getCParams(CCtxParams.compressionLevel, srcSizeHint, dictSize);
 }
 
-static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* params, U64 srcSize)
+static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* CCtxParams, U64 srcSize)
 {
-    params->cParams = ZSTD_getCParamsFromCCtxParams(*params, srcSize, 0);
-    params->compressionLevel = ZSTD_CLEVEL_CUSTOM;
+    CCtxParams->cParams = ZSTD_getCParamsFromCCtxParams(*CCtxParams, srcSize, 0);
+    CCtxParams->compressionLevel = ZSTD_CLEVEL_CUSTOM;
 }
 
 static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx)
@@ -161,9 +161,9 @@ static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx)
             &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1);
 }
 
-static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* params)
+static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* CCtxParams)
 {
-    ZSTD_cLevelToCCtxParams_srcSize(params, 0);
+    ZSTD_cLevelToCCtxParams_srcSize(CCtxParams, 0);
 }
 
 static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
@@ -314,148 +314,157 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned v
 }
 
 size_t ZSTD_CCtxParam_setParameter(
-        ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value)
+        ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, unsigned value)
 {
     switch(param)
     {
     case ZSTD_p_format :
         if (value > (unsigned)ZSTD_f_zstd1_magicless)
             return ERROR(parameter_unsupported);
-        params->format = (ZSTD_format_e)value;
-        return 0;
+        CCtxParams->format = (ZSTD_format_e)value;
+        return (size_t)CCtxParams->format;
 
     case ZSTD_p_compressionLevel :
         if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel();
-        if (value == 0) return 0;
-        params->compressionLevel = value;
-        return 0;
+        if (value)  /* 0 : does not change current level */
+            CCtxParams->compressionLevel = value;
+        return CCtxParams->compressionLevel;
 
     case ZSTD_p_windowLog :
-        if (value == 0) return 0;
-        CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
-        ZSTD_cLevelToCCtxParams(params);
-        params->cParams.windowLog = value;
-        return 0;
+        if (value) {  /* 0 : does not change current windowLog */
+            CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
+            ZSTD_cLevelToCCtxParams(CCtxParams);
+            CCtxParams->cParams.windowLog = value;
+        }
+        return CCtxParams->cParams.windowLog;
 
     case ZSTD_p_hashLog :
-        if (value == 0) return 0;
-        CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
-        ZSTD_cLevelToCCtxParams(params);
-        params->cParams.hashLog = value;
-        return 0;
+        if (value) { /* 0 : does not change current hashLog */
+            CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
+            ZSTD_cLevelToCCtxParams(CCtxParams);
+            CCtxParams->cParams.hashLog = value;
+        }
+        return CCtxParams->cParams.hashLog;
 
     case ZSTD_p_chainLog :
-        if (value == 0) return 0;
-        CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
-        ZSTD_cLevelToCCtxParams(params);
-        params->cParams.chainLog = value;
-        return 0;
+        if (value) { /* 0 : does not change current chainLog */
+            CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
+            ZSTD_cLevelToCCtxParams(CCtxParams);
+            CCtxParams->cParams.chainLog = value;
+        }
+        return CCtxParams->cParams.chainLog;
 
     case ZSTD_p_searchLog :
-        if (value == 0) return 0;
-        CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
-        ZSTD_cLevelToCCtxParams(params);
-        params->cParams.searchLog = value;
-        return 0;
+        if (value) { /* 0 : does not change current searchLog */
+            CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
+            ZSTD_cLevelToCCtxParams(CCtxParams);
+            CCtxParams->cParams.searchLog = value;
+        }
+        return value;
 
     case ZSTD_p_minMatch :
-        if (value == 0) return 0;
-        CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
-        ZSTD_cLevelToCCtxParams(params);
-        params->cParams.searchLength = value;
-        return 0;
+        if (value) { /* 0 : does not change current minMatch length */
+            CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
+            ZSTD_cLevelToCCtxParams(CCtxParams);
+            CCtxParams->cParams.searchLength = value;
+        }
+        return CCtxParams->cParams.searchLength;
 
     case ZSTD_p_targetLength :
-        if (value == 0) return 0;
-        CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
-        ZSTD_cLevelToCCtxParams(params);
-        params->cParams.targetLength = value;
-        return 0;
+        if (value) { /* 0 : does not change current sufficient_len */
+            CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
+            ZSTD_cLevelToCCtxParams(CCtxParams);
+            CCtxParams->cParams.targetLength = value;
+        }
+        return CCtxParams->cParams.targetLength;
 
     case ZSTD_p_compressionStrategy :
-        if (value == 0) return 0;
-        CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
-        ZSTD_cLevelToCCtxParams(params);
-        params->cParams.strategy = (ZSTD_strategy)value;
-        return 0;
+        if (value) { /* 0 : does not change currentstrategy */
+            CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
+            ZSTD_cLevelToCCtxParams(CCtxParams);
+            CCtxParams->cParams.strategy = (ZSTD_strategy)value;
+        }
+        return (size_t)CCtxParams->cParams.strategy;
 
     case ZSTD_p_contentSizeFlag :
         /* Content size written in frame header _when known_ (default:1) */
         DEBUGLOG(4, "set content size flag = %u", (value>0));
-        params->fParams.contentSizeFlag = value > 0;
-        return 0;
+        CCtxParams->fParams.contentSizeFlag = value > 0;
+        return CCtxParams->fParams.contentSizeFlag;
 
     case ZSTD_p_checksumFlag :
         /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
-        params->fParams.checksumFlag = value > 0;
-        return 0;
+        CCtxParams->fParams.checksumFlag = value > 0;
+        return CCtxParams->fParams.checksumFlag;
 
     case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
         DEBUGLOG(4, "set dictIDFlag = %u", (value>0));
-        params->fParams.noDictIDFlag = (value == 0);
-        return 0;
+        CCtxParams->fParams.noDictIDFlag = (value == 0);
+        return !CCtxParams->fParams.noDictIDFlag;
 
     case ZSTD_p_forceMaxWindow :
-        params->forceWindow = value > 0;
-        return 0;
+        CCtxParams->forceWindow = (value > 0);
+        return CCtxParams->forceWindow;
 
     case ZSTD_p_nbThreads :
-        if (value == 0) return 0;
+        if (value == 0) return CCtxParams->nbThreads;
 #ifndef ZSTD_MULTITHREAD
         if (value > 1) return ERROR(parameter_unsupported);
-        return 0;
+        return 1;
 #else
-        return ZSTDMT_initializeCCtxParameters(params, value);
+        return ZSTDMT_CCtxParam_setNbThreads(CCtxParams, value);
 #endif
 
     case ZSTD_p_jobSize :
 #ifndef ZSTD_MULTITHREAD
         return ERROR(parameter_unsupported);
 #else
-        if (params->nbThreads <= 1) return ERROR(parameter_unsupported);
-        return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_sectionSize, value);
+        if (CCtxParams->nbThreads <= 1) return ERROR(parameter_unsupported);
+        return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_sectionSize, value);
 #endif
 
     case ZSTD_p_overlapSizeLog :
 #ifndef ZSTD_MULTITHREAD
         return ERROR(parameter_unsupported);
 #else
-        if (params->nbThreads <= 1) return ERROR(parameter_unsupported);
-        return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_overlapSectionLog, value);
+        if (CCtxParams->nbThreads <= 1) return ERROR(parameter_unsupported);
+        return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_overlapSectionLog, value);
 #endif
 
     case ZSTD_p_enableLongDistanceMatching :
         if (value != 0) {
-            ZSTD_cLevelToCCtxParams(params);
-            params->cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
+            ZSTD_cLevelToCCtxParams(CCtxParams);
+            CCtxParams->cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
         }
-        return ZSTD_ldm_initializeParameters(&params->ldmParams, value);
+        return ZSTD_ldm_initializeParameters(&CCtxParams->ldmParams, value);
 
     case ZSTD_p_ldmHashLog :
-        if (value == 0) return 0;
-        CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
-        params->ldmParams.hashLog = value;
-        return 0;
+        if (value) { /* 0 : does not change current ldmHashLog */
+            CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
+            CCtxParams->ldmParams.hashLog = value;
+        }
+        return CCtxParams->ldmParams.hashLog;
 
     case ZSTD_p_ldmMinMatch :
-        if (value == 0) return 0;
-        CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX);
-        params->ldmParams.minMatchLength = value;
-        return 0;
+        if (value) { /* 0 : does not change current ldmMinMatch */
+            CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX);
+            CCtxParams->ldmParams.minMatchLength = value;
+        }
+        return CCtxParams->ldmParams.minMatchLength;
 
     case ZSTD_p_ldmBucketSizeLog :
         if (value > ZSTD_LDM_BUCKETSIZELOG_MAX) {
             return ERROR(parameter_outOfBound);
         }
-        params->ldmParams.bucketSizeLog = value;
-        return 0;
+        CCtxParams->ldmParams.bucketSizeLog = value;
+        return value;
 
     case ZSTD_p_ldmHashEveryLog :
         if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN) {
             return ERROR(parameter_outOfBound);
         }
-        params->ldmParams.hashEveryLog = value;
-        return 0;
+        CCtxParams->ldmParams.hashEveryLog = value;
+        return value;
 
     default: return ERROR(parameter_unsupported);
     }
@@ -768,12 +777,26 @@ static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1,
             ldmParams1.hashEveryLog == ldmParams2.hashEveryLog);
 }
 
+typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
+
+/* ZSTD_equivalentBuffPolicy() :
+ * check internal buffers exist for streaming if buffPol == ZSTDb_buffered .
+ * Note : they are assumed to be correctly sized if ZSTD_equivalentCParams()==1 */
+static U32 ZSTD_equivalentBuffPolicy(size_t bufferSize, ZSTD_buffered_policy_e buffPol)
+{
+    if ((buffPol == ZSTDb_buffered) & (!bufferSize)) return 0;
+    return 1;
+}
+
 /** Equivalence for resetCCtx purposes */
 static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
-                                 ZSTD_CCtx_params params2)
+                                 ZSTD_CCtx_params params2,
+                                 size_t buffSize1,
+                                 ZSTD_buffered_policy_e buffPol2)
 {
     return ZSTD_equivalentCParams(params1.cParams, params2.cParams) &&
-           ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams);
+           ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams) &&
+           ZSTD_equivalentBuffPolicy(buffSize1, buffPol2);
 }
 
 /*! ZSTD_continueCCtx() :
@@ -802,7 +825,6 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pl
 }
 
 typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
-typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
 
 /*! ZSTD_resetCCtx_internal() :
     note : `params` are assumed fully validated at this stage */
@@ -815,8 +837,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
     assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
 
     if (crp == ZSTDcrp_continue) {
-        if (ZSTD_equivalentParams(params, zc->appliedParams)) {
-            DEBUGLOG(4, "ZSTD_equivalentParams()==1");
+        if (ZSTD_equivalentParams(params, zc->appliedParams, zc->inBuffSize, zbuff)) {
+            DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode");
             assert(!(params.ldmParams.enableLdm &&
                      params.ldmParams.hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET));
             zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
@@ -825,6 +847,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
             zc->entropy->litlength_repeatMode = FSE_repeat_none;
             return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
     }   }
+    DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx");
 
     if (params.ldmParams.enableLdm) {
         /* Adjust long distance matching parameters */
@@ -863,11 +886,15 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
                 : 0;
             size_t const neededSpace = entropySpace + optSpace + ldmSpace +
                                        tableSpace + tokenSpace + bufferSpace;
+            DEBUGLOG(4, "Need %uKB workspace, including %uKB for tables",
+                        (U32)(neededSpace>>10), (U32)(tableSpace>>10));
+            DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
+                        (U32)chainSize, (U32)hSize, (U32)h3Size);
 
             if (zc->workSpaceSize < neededSpace) {  /* too small : resize */
-                DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n",
-                            (unsigned)zc->workSpaceSize>>10,
-                            (unsigned)neededSpace>>10);
+                DEBUGLOG(4, "Need to update workSpaceSize from %uK to %uK",
+                            (unsigned)(zc->workSpaceSize>>10),
+                            (unsigned)(neededSpace>>10));
                 /* static cctx : no resize, error out */
                 if (zc->staticSize) return ERROR(memory_allocation);
 
@@ -916,7 +943,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
 
         /* opt parser space */
         if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) {
-            DEBUGLOG(5, "reserving optimal parser space");
+            DEBUGLOG(4, "reserving optimal parser space");
             assert(((size_t)ptr & 3) == 0);  /* ensure ptr is properly aligned */
             zc->optState.litFreq = (U32*)ptr;
             zc->optState.litLengthFreq = zc->optState.litFreq + (1<<Litbits);
@@ -940,6 +967,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
         }
 
         /* table Space */
+        DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset);
         if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace);   /* reset tables only */
         assert(((size_t)ptr & 3) == 0);  /* ensure ptr is properly aligned */
         zc->hashTable = (U32*)(ptr);
@@ -1753,7 +1781,6 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
                 !params.fParams.noDictIDFlag, dictID,  dictIDSizeCode);
 
     if (params.format == ZSTD_f_zstd1) {
-        DEBUGLOG(4, "writing zstd magic number");
         MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
         pos = 4;
     }
@@ -1787,8 +1814,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
     const BYTE* const ip = (const BYTE*) src;
     size_t fhSize = 0;
 
-    DEBUGLOG(5, "ZSTD_compressContinue_internal");
-    DEBUGLOG(5, "stage: %u", cctx->stage);
+    DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u", cctx->stage);
     if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong);   /* missing init (ZSTD_compressBegin) */
 
     if (frame && (cctx->stage==ZSTDcs_init)) {
@@ -2017,7 +2043,7 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
                                        const void* dict, size_t dictSize,
                                              ZSTD_dictMode_e dictMode)
 {
-    DEBUGLOG(5, "ZSTD_compress_insertDictionary");
+    DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
     if ((dict==NULL) || (dictSize<=8)) return 0;
 
     /* dict restricted modes */
@@ -2026,7 +2052,7 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
 
     if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
         if (dictMode == ZSTD_dm_auto) {
-            DEBUGLOG(5, "raw content dictionary detected");
+            DEBUGLOG(4, "raw content dictionary detected");
             return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
         }
         if (dictMode == ZSTD_dm_fullDict)
@@ -2097,6 +2123,7 @@ size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t di
     ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
     ZSTD_CCtx_params const cctxParams =
             ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
+    DEBUGLOG(4, "ZSTD_compressBegin_usingDict");
     return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
                                        cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
 }
@@ -2179,6 +2206,7 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
 {
     ZSTD_CCtx_params const cctxParams =
             ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
+    DEBUGLOG(4, "ZSTD_compress_internal");
     return ZSTD_compress_advanced_internal(cctx,
                                           dst, dstCapacity,
                                           src, srcSize,
@@ -2192,6 +2220,7 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
                          const void* dict,size_t dictSize,
                                ZSTD_parameters params)
 {
+    DEBUGLOG(4, "ZSTD_compress_advanced");
     CHECK_F(ZSTD_checkCParams(params.cParams));
     return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
 }
@@ -2204,6 +2233,7 @@ size_t ZSTD_compress_advanced_internal(
         const void* dict,size_t dictSize,
         ZSTD_CCtx_params params)
 {
+    DEBUGLOG(4, "ZSTD_compress_advanced_internal");
     CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
                                          params, srcSize, ZSTDb_not_buffered) );
     return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
@@ -2214,6 +2244,8 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, co
 {
     ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize ? srcSize : 1, dict ? dictSize : 0);
     params.fParams.contentSizeFlag = 1;
+    DEBUGLOG(4, "ZSTD_compress_usingDict (level=%i, srcSize=%u, dictSize=%u)",
+                compressionLevel, (U32)srcSize, (U32)dictSize);
     return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
 }
 
@@ -2270,7 +2302,7 @@ static size_t ZSTD_initCDict_internal(
                     ZSTD_dictMode_e dictMode,
                     ZSTD_compressionParameters cParams)
 {
-    DEBUGLOG(5, "ZSTD_initCDict_internal, mode %u", (U32)dictMode);
+    DEBUGLOG(4, "ZSTD_initCDict_internal, mode %u", (U32)dictMode);
     if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
         cdict->dictBuffer = NULL;
         cdict->dictContent = dictBuffer;
@@ -2409,11 +2441,11 @@ size_t ZSTD_compressBegin_usingCDict_advanced(
     ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
     ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
 {
+    DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
     if (cdict==NULL) return ERROR(dictionary_wrong);
     {   ZSTD_CCtx_params params = cctx->requestedParams;
         params.cParams = ZSTD_getCParamsFromCDict(cdict);
         params.fParams = fParams;
-        DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
         return ZSTD_compressBegin_internal(cctx,
                                            NULL, 0, ZSTD_dm_auto,
                                            cdict,
@@ -2811,16 +2843,17 @@ size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
 
     /* transparent initialization stage */
     if (cctx->streamStage == zcss_init) {
-        ZSTD_prefixDict const prefixDict = cctx->prefixDict;
         ZSTD_CCtx_params params = cctx->requestedParams;
-        if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1;
-        params.cParams = ZSTD_getCParamsFromCCtxParams(
-                cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
+        ZSTD_prefixDict const prefixDict = cctx->prefixDict;
         memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));  /* single usage */
         assert(prefixDict.dict==NULL || cctx->cdict==NULL);   /* only one can be set */
         DEBUGLOG(4, "ZSTD_compress_generic : transparent init stage");
+        if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1;  /* auto-fix pledgedSrcSize */
+        params.cParams = ZSTD_getCParamsFromCCtxParams(
+                cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
 
 #ifdef ZSTD_MULTITHREAD
+        if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) params.nbThreads = 1; /* do not invoke multi-threading when src size is too small */
         if (params.nbThreads > 1) {
             if (cctx->mtctx == NULL || cctx->appliedParams.nbThreads != params.nbThreads) {
                 ZSTDMT_freeCCtx(cctx->mtctx);
@@ -2897,8 +2930,7 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
     {   size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE;
         size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4;
         size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize + lastBlockSize + checksumSize;
-        DEBUGLOG(5, "ZSTD_endStream : remaining to flush : %u",
-                (unsigned)toFlush);
+        DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (U32)toFlush);
         return toFlush;
     }
 }
index a9ef7ad1cdd8b9335cf7890790e022b58158e16a..efcbc45016789e4bf2c30ebc55b8d4486b1a50aa 100644 (file)
@@ -237,7 +237,6 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const v
     static const BYTE* g_start = NULL;
     if (g_start==NULL) g_start = (const BYTE*)literals;  /* note : index only works for compression within a single segment */
     {   U32 const pos = (U32)((const BYTE*)literals - g_start);
-        g_debuglog_enable = ((pos >= 3670500) & (pos < 3673800));
         DEBUGLOG(6, "Cpos%7u :%3u literals, match%3u bytes at dist.code%7u",
                pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offsetCode);
     }
index 2794d99bceee116f8676a3107734e8303b218f38..d7ef039f0ad8d38dfc237f92993628ac7dc055ae 100644 (file)
@@ -18,8 +18,9 @@
 /** ZSTD_insertBt1() : add one or multiple positions to tree.
 *   ip : assumed <= iend-8 .
 *   @return : nb of positions added */
-static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
-                          U32 extDict)
+static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
+                const BYTE* const ip, const BYTE* const iend,
+                U32 nbCompares, U32 const mls, U32 const extDict)
 {
     U32*   const hashTable = zc->hashTable;
     U32    const hashLog = zc->appliedParams.cParams.hashLog;
@@ -58,6 +59,7 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co
     while (nbCompares-- && (matchIndex > windowLow)) {
         U32* const nextPtr = bt + 2*(matchIndex & btMask);
         size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
+        assert(matchIndex < current);
 
 #ifdef ZSTD_C_PREDICT   /* note : can create issues when hlog small <= 11 */
         const U32* predictPtr = bt + 2*((matchIndex-1) & btMask);   /* written this way, as bt is a roll buffer */
@@ -124,6 +126,36 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co
     return 1;
 }
 
+FORCE_INLINE_TEMPLATE
+void ZSTD_updateTree_internal(ZSTD_CCtx* zc,
+                const BYTE* const ip, const BYTE* const iend,
+                const U32 nbCompares, const U32 mls, const U32 extDict)
+{
+    const BYTE* const base = zc->base;
+    U32 const target = (U32)(ip - base);
+    U32 idx = zc->nextToUpdate;
+    DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u  (extDict:%u)",
+                idx, target, extDict);
+
+    while(idx < target)
+        idx += ZSTD_insertBt1(zc, base+idx, iend, nbCompares, mls, extDict);
+    zc->nextToUpdate = target;
+}
+
+void ZSTD_updateTree(ZSTD_CCtx* zc,
+                const BYTE* const ip, const BYTE* const iend,
+                const U32 nbCompares, const U32 mls)
+{
+    return ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 0 /*extDict*/);
+}
+
+void ZSTD_updateTree_extDict(ZSTD_CCtx* zc,
+                const BYTE* const ip, const BYTE* const iend,
+                const U32 nbCompares, const U32 mls)
+{
+    return ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 1 /*extDict*/);
+}
+
 
 static size_t ZSTD_insertBtAndFindBestMatch (
                         ZSTD_CCtx* zc,
@@ -206,16 +238,6 @@ static size_t ZSTD_insertBtAndFindBestMatch (
 }
 
 
-void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
-{
-    const BYTE* const base = zc->base;
-    const U32 target = (U32)(ip - base);
-    U32 idx = zc->nextToUpdate;
-
-    while(idx < target)
-        idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
-}
-
 /** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
 static size_t ZSTD_BtFindBestMatch (
                         ZSTD_CCtx* zc,
@@ -246,16 +268,6 @@ static size_t ZSTD_BtFindBestMatch_selectMLS (
 }
 
 
-void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
-{
-    const BYTE* const base = zc->base;
-    const U32 target = (U32)(ip - base);
-    U32 idx = zc->nextToUpdate;
-
-    while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
-}
-
-
 /** Tree updater, providing best match */
 static size_t ZSTD_BtFindBestMatch_extDict (
                         ZSTD_CCtx* zc,
index c3814f8d2ac044bdb884d53b4ecf6a14fdbc51f9..52486bd3cba26f57034f1ebe2f17325fb5ec3195 100644 (file)
@@ -148,7 +148,7 @@ FORCE_INLINE_TEMPLATE U32 ZSTD_getPrice(optState_t* optPtr, U32 litLength, const
         return ZSTD_getLiteralPrice(optPtr, litLength, literals) + ZSTD_highbit32((U32)mlBase+1) + 16 + offCode;
 
     price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1);
-    if (!ultra /*static*/ && offCode >= 20) price += (offCode-19)*2; /* handicap for long matches, favor decompression speed */
+    if (!ultra /*static*/ && offCode >= 20) price += (offCode-19)*2; /* handicap for long distance offsets, favor decompression speed */
 
     /* match Length */
     {   U32 const mlCode = ZSTD_MLcode(mlBase);
@@ -231,8 +231,8 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* zc, const BYTE* ip)
 /*-*************************************
 *  Binary Tree search
 ***************************************/
-FORCE_INLINE_TEMPLATE
- U32 ZSTD_insertBtAndGetAllMatches (
+//FORCE_INLINE_TEMPLATE
+U32 ZSTD_insertBtAndGetAllMatches (
                         ZSTD_CCtx* zc,
                         const BYTE* const ip, const BYTE* const iLimit, const int extDict,
                         U32 nbCompares, U32 const mls,
@@ -240,22 +240,22 @@ FORCE_INLINE_TEMPLATE
                         ZSTD_match_t* matches, const U32 minMatchLen)
 {
     const BYTE* const base = zc->base;
-    const U32 current = (U32)(ip-base);
-    const U32 hashLog = zc->appliedParams.cParams.hashLog;
-    const size_t h  = ZSTD_hashPtr(ip, hashLog, mls);
+    U32 const current = (U32)(ip-base);
+    U32 const hashLog = zc->appliedParams.cParams.hashLog;
     U32 const minMatch = (mls==3) ? 3 : 4;
     U32* const hashTable = zc->hashTable;
+    size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
     U32 matchIndex  = hashTable[h];
     U32* const bt   = zc->chainTable;
-    const U32 btLog = zc->appliedParams.cParams.chainLog - 1;
-    const U32 btMask= (1U << btLog) - 1;
+    U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
+    U32 const btMask= (1U << btLog) - 1;
     size_t commonLengthSmaller=0, commonLengthLarger=0;
     const BYTE* const dictBase = zc->dictBase;
-    const U32 dictLimit = zc->dictLimit;
+    U32 const dictLimit = zc->dictLimit;
     const BYTE* const dictEnd = dictBase + dictLimit;
     const BYTE* const prefixStart = base + dictLimit;
-    const U32 btLow = btMask >= current ? 0 : current - btMask;
-    const U32 windowLow = zc->lowLimit;
+    U32 const btLow = btMask >= current ? 0 : current - btMask;
+    U32 const windowLow = zc->lowLimit;
     U32* smallerPtr = bt + 2*(current&btMask);
     U32* largerPtr  = bt + 2*(current&btMask) + 1;
     U32 matchEndIdx = current+8;   /* farthest referenced position of any match => detects repetitive patterns */
@@ -263,6 +263,7 @@ FORCE_INLINE_TEMPLATE
     U32 mnum = 0;
 
     size_t bestLength = minMatchLen-1;
+    DEBUGLOG(7, "ZSTD_insertBtAndGetAllMatches");
 
     /* check repCode */
     {   U32 const lastR = ZSTD_REP_NUM + ll0;
@@ -272,20 +273,23 @@ FORCE_INLINE_TEMPLATE
             U32 const repIndex = current - repOffset;
             U32 repLen = 0;
             assert(current >= dictLimit);
-            if (!extDict /*static*/ || (repIndex>=dictLimit)) {
-                if ( (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit)  /* within current mem segment */
-                  && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch))) {
+            if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) {  /* equivalent to `current > repIndex >= dictLimit` */
+                if (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch)) {
                     repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
                 }
-            } else {  /* extDict */
+            } else {  /* repIndex < dictLimit || repIndex >= current */
                 const BYTE* const repMatch = dictBase + repIndex;
-                if ( ((repOffset-1) /*intentional overflow*/ < current)
-                   & (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ & (repIndex > windowLow))
+                assert(current >= windowLow);
+                if ( extDict /* this case only valid in extDict mode */
+                  && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow)  /* equivalent to `current > repIndex >= windowLow` */
+                     & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */)
                   && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
                     repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch;
             }   }
             /* save longer solution */
             if (repLen > bestLength) {
+                DEBUGLOG(8, "found rep-match %u of length %u",
+                            repCode - ll0, (U32)repLen);
                 bestLength = repLen;
                 matches[mnum].off = repCode - ll0;
                 matches[mnum].len = (U32)repLen;
@@ -298,7 +302,7 @@ FORCE_INLINE_TEMPLATE
     /* HC3 match finder */
     if ((mls == 3) /*static*/ && (bestLength < mls)) {
         U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip);
-        if ((matchIndex3>windowLow)
+        if ((matchIndex3 > windowLow)
           & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
             size_t mlen;
             if ((!extDict) /*static*/ || (matchIndex3 >= dictLimit)) {
@@ -311,6 +315,8 @@ FORCE_INLINE_TEMPLATE
 
             /* save best solution */
             if (mlen >= mls /* == 3 > bestLength */) {
+                DEBUGLOG(8, "found small match with hlog3, of length %u",
+                            (U32)mlen);
                 bestLength = mlen;
                 assert(current > matchIndex3);
                 assert(mnum==0);  /* no prior solution */
@@ -344,6 +350,8 @@ FORCE_INLINE_TEMPLATE
         }
 
         if (matchLength > bestLength) {
+            DEBUGLOG(8, "found match of length %u at distance %u",
+                    (U32)matchLength, current - matchIndex);
             assert(matchEndIdx > matchIndex);
             if (matchLength > matchEndIdx - matchIndex)
                 matchEndIdx = matchIndex + (U32)matchLength;
@@ -386,6 +394,7 @@ FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
                         U32 rep[ZSTD_REP_NUM], U32 const ll0,
                         ZSTD_match_t* matches, const U32 minMatchLen)
 {
+    DEBUGLOG(7, "ZSTD_BtGetAllMatches");
     if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */
     if (extDict) ZSTD_updateTree_extDict(zc, ip, iHighLimit, maxNbAttempts, matchLengthSearch);
     else ZSTD_updateTree(zc, ip, iHighLimit, maxNbAttempts, matchLengthSearch);
@@ -465,6 +474,7 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
     U32 rep[ZSTD_REP_NUM];
 
     /* init */
+    DEBUGLOG(5, "ZSTD_compressBlock_opt_generic");
     ctx->nextToUpdate3 = ctx->nextToUpdate;
     ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
     ip += (ip==prefixStart);
@@ -653,6 +663,7 @@ _shortestPath:   /* cur, last_pos, best_mlen, best_off have to be set */
 
 size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
 {
+    DEBUGLOG(5, "ZSTD_compressBlock_btopt");
     return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0 /*ultra*/, 0 /*extDict*/);
 }
 
index 0b9173f3b48d8f094fc40bcdd7a5d44ccef15748..2926d3b487f88594a242654fe258610cde4de511 100644 (file)
@@ -412,13 +412,14 @@ struct ZSTDMT_CCtx_s {
     ZSTDMT_CCtxPool* cctxPool;
     ZSTD_pthread_mutex_t jobCompleted_mutex;
     ZSTD_pthread_cond_t jobCompleted_cond;
+    ZSTD_CCtx_params params;
     size_t targetSectionSize;
     size_t inBuffSize;
     size_t dictSize;
     size_t targetDictSize;
     inBuff_t inBuff;
-    ZSTD_CCtx_params params;
     XXH64_state_t xxhState;
+    unsigned singleThreaded;
     unsigned jobIDMask;
     unsigned doneJobID;
     unsigned nextJobID;
@@ -439,20 +440,23 @@ static ZSTDMT_jobDescription* ZSTDMT_allocJobsTable(U32* nbJobsPtr, ZSTD_customM
                             nbJobs * sizeof(ZSTDMT_jobDescription), cMem);
 }
 
-/* Internal only */
-size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads)
+/* ZSTDMT_CCtxParam_setNbThreads():
+ * Internal use only */
+size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThreads)
 {
+    if (nbThreads > ZSTDMT_NBTHREADS_MAX) nbThreads = ZSTDMT_NBTHREADS_MAX;
+    if (nbThreads < 1) nbThreads = 1;
     params->nbThreads = nbThreads;
     params->overlapSizeLog = ZSTDMT_OVERLAPLOG_DEFAULT;
     params->jobSize = 0;
-    return 0;
+    return nbThreads;
 }
 
 ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
 {
     ZSTDMT_CCtx* mtctx;
     U32 nbJobs = nbThreads + 2;
-    DEBUGLOG(3, "ZSTDMT_createCCtx_advanced");
+    DEBUGLOG(3, "ZSTDMT_createCCtx_advanced (nbThreads = %u)", nbThreads);
 
     if (nbThreads < 1) return NULL;
     nbThreads = MIN(nbThreads , ZSTDMT_NBTHREADS_MAX);
@@ -462,7 +466,7 @@ ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
 
     mtctx = (ZSTDMT_CCtx*) ZSTD_calloc(sizeof(ZSTDMT_CCtx), cMem);
     if (!mtctx) return NULL;
-    ZSTDMT_initializeCCtxParameters(&mtctx->params, nbThreads);
+    ZSTDMT_CCtxParam_setNbThreads(&mtctx->params, nbThreads);
     mtctx->cMem = cMem;
     mtctx->allJobsCompleted = 1;
     mtctx->factory = POOL_create_advanced(nbThreads, 0, cMem);
@@ -559,12 +563,16 @@ size_t ZSTDMT_CCtxParam_setMTCtxParameter(
     switch(parameter)
     {
     case ZSTDMT_p_sectionSize :
+        if ( (value > 0)  /* value==0 => automatic job size */
+           & (value < ZSTDMT_JOBSIZE_MIN) )
+            value = ZSTDMT_JOBSIZE_MIN;
         params->jobSize = value;
-        return 0;
+        return value;
     case ZSTDMT_p_overlapSectionLog :
+        if (value > 9) value = 9;
         DEBUGLOG(4, "ZSTDMT_p_overlapSectionLog : %u", value);
         params->overlapSizeLog = (value >= 9) ? 9 : value;
-        return 0;
+        return value;
     default :
         return ERROR(parameter_unsupported);
     }
@@ -763,13 +771,14 @@ size_t ZSTDMT_initCStream_internal(
         const ZSTD_CDict* cdict, ZSTD_CCtx_params params,
         unsigned long long pledgedSrcSize)
 {
-    DEBUGLOG(4, "ZSTDMT_initCStream_internal");
+    DEBUGLOG(4, "ZSTDMT_initCStream_internal (pledgedSrcSize=%u)", (U32)pledgedSrcSize);
     /* params are supposed to be fully validated at this point */
     assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
     assert(!((dict) && (cdict)));  /* either dict or cdict, not both */
     assert(zcs->cctxPool->totalCCtx == params.nbThreads);
+    zcs->singleThreaded = (params.nbThreads==1) | (pledgedSrcSize <= ZSTDMT_JOBSIZE_MIN);  /* do not trigger multi-threading when srcSize is too small */
 
-    if (params.nbThreads==1) {
+    if (zcs->singleThreaded) {
         ZSTD_CCtx_params const singleThreadParams = ZSTDMT_makeJobCCtxParams(params);
         DEBUGLOG(4, "single thread mode");
         assert(singleThreadParams.nbThreads == 0);
@@ -777,7 +786,7 @@ size_t ZSTDMT_initCStream_internal(
                                          dict, dictSize, cdict,
                                          singleThreadParams, pledgedSrcSize);
     }
-    DEBUGLOG(4, "multi - threading mode");
+    DEBUGLOG(4, "multi-threading mode (%u threads)", params.nbThreads);
 
     if (zcs->allJobsCompleted == 0) {   /* previous compression not correctly finished */
         ZSTDMT_waitForAllJobsCompleted(zcs);
@@ -800,13 +809,13 @@ size_t ZSTDMT_initCStream_internal(
         zcs->cdict = cdict;
     }
 
+    assert(params.overlapSizeLog <= 9);
     zcs->targetDictSize = (params.overlapSizeLog==0) ? 0 : (size_t)1 << (params.cParams.windowLog - (9 - params.overlapSizeLog));
-    DEBUGLOG(4, "overlapLog : %u ", params.overlapSizeLog);
-    DEBUGLOG(4, "overlap Size : %u KB", (U32)(zcs->targetDictSize>>10));
+    DEBUGLOG(4, "overlapLog=%u => %u KB", params.overlapSizeLog, (U32)(zcs->targetDictSize>>10));
     zcs->targetSectionSize = params.jobSize ? params.jobSize : (size_t)1 << (params.cParams.windowLog + 2);
-    zcs->targetSectionSize = MAX(ZSTDMT_SECTION_SIZE_MIN, zcs->targetSectionSize);
-    zcs->targetSectionSize = MAX(zcs->targetDictSize, zcs->targetSectionSize);   /* one job size must be at least overlap */
-    DEBUGLOG(4, "Section Size : %u KB", (U32)(zcs->targetSectionSize>>10));
+    if (zcs->targetSectionSize < ZSTDMT_JOBSIZE_MIN) zcs->targetSectionSize = ZSTDMT_JOBSIZE_MIN;
+    if (zcs->targetSectionSize < zcs->targetDictSize) zcs->targetSectionSize = zcs->targetDictSize;  /* job size must be >= overlap size */
+    DEBUGLOG(4, "Job Size : %u KB", (U32)(zcs->targetSectionSize>>10));
     zcs->inBuffSize = zcs->targetDictSize + zcs->targetSectionSize;
     DEBUGLOG(4, "inBuff Size : %u KB", (U32)(zcs->inBuffSize>>10));
     ZSTDMT_setBufferSize(zcs->bufPool, MAX(zcs->inBuffSize, ZSTD_compressBound(zcs->targetSectionSize)) );
@@ -826,7 +835,7 @@ size_t ZSTDMT_initCStream_advanced(ZSTDMT_CCtx* mtctx,
                                    unsigned long long pledgedSrcSize)
 {
     ZSTD_CCtx_params cctxParams = mtctx->params;
-    DEBUGLOG(5, "ZSTDMT_initCStream_advanced");
+    DEBUGLOG(5, "ZSTDMT_initCStream_advanced (pledgedSrcSize=%u)", (U32)pledgedSrcSize);
     cctxParams.cParams = params.cParams;
     cctxParams.fParams = params.fParams;
     return ZSTDMT_initCStream_internal(mtctx, dict, dictSize, ZSTD_dm_auto, NULL,
@@ -1008,13 +1017,15 @@ size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
     DEBUGLOG(5, "ZSTDMT_compressStream_generic");
     assert(output->pos <= output->size);
     assert(input->pos  <= input->size);
+
+    if (mtctx->singleThreaded) {  /* delegate to single-thread (synchronous) */
+        return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
+    }
+
     if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) {
         /* current frame being ended. Only flush/end are allowed */
         return ERROR(stage_wrong);
     }
-    if (mtctx->params.nbThreads==1) {  /* delegate to single-thread (synchronous) */
-        return ZSTD_compressStream_generic(mtctx->cctxPool->cctx[0], output, input, endOp);
-    }
 
     /* single-pass shortcut (note : synchronous-mode) */
     if ( (mtctx->nextJobID == 0)     /* just started */
@@ -1083,32 +1094,32 @@ size_t ZSTDMT_compressStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, ZSTD_inBu
 }
 
 
-static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsigned endFrame)
+static size_t ZSTDMT_flushStream_internal(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, unsigned endFrame)
 {
-    size_t const srcSize = zcs->inBuff.filled - zcs->dictSize;
+    size_t const srcSize = mtctx->inBuff.filled - mtctx->dictSize;
 
-    if ( ((srcSize > 0) || (endFrame && !zcs->frameEnded))
-       && (zcs->nextJobID <= zcs->doneJobID + zcs->jobIDMask) ) {
-        CHECK_F( ZSTDMT_createCompressionJob(zcs, srcSize, endFrame) );
+    if ( ((srcSize > 0) || (endFrame && !mtctx->frameEnded))
+       && (mtctx->nextJobID <= mtctx->doneJobID + mtctx->jobIDMask) ) {
+        CHECK_F( ZSTDMT_createCompressionJob(mtctx, srcSize, endFrame) );
     }
 
     /* check if there is any data available to flush */
-    return ZSTDMT_flushNextJob(zcs, output, 1 /* blockToFlush */);
+    return ZSTDMT_flushNextJob(mtctx, output, 1 /* blockToFlush */);
 }
 
 
-size_t ZSTDMT_flushStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output)
+size_t ZSTDMT_flushStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
 {
     DEBUGLOG(5, "ZSTDMT_flushStream");
-    if (zcs->params.nbThreads==1)
-        return ZSTD_flushStream(zcs->cctxPool->cctx[0], output);
-    return ZSTDMT_flushStream_internal(zcs, output, 0 /* endFrame */);
+    if (mtctx->singleThreaded)
+        return ZSTD_flushStream(mtctx->cctxPool->cctx[0], output);
+    return ZSTDMT_flushStream_internal(mtctx, output, 0 /* endFrame */);
 }
 
-size_t ZSTDMT_endStream(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output)
+size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output)
 {
     DEBUGLOG(4, "ZSTDMT_endStream");
-    if (zcs->params.nbThreads==1)
-        return ZSTD_endStream(zcs->cctxPool->cctx[0], output);
-    return ZSTDMT_flushStream_internal(zcs, output, 1 /* endFrame */);
+    if (mtctx->singleThreaded)
+        return ZSTD_endStream(mtctx->cctxPool->cctx[0], output);
+    return ZSTDMT_flushStream_internal(mtctx, output, 1 /* endFrame */);
 }
index a7ce7c7dd63e2f777fa97ff932edb982a98a1de7..598e6daf58c952ea02f5b116358df58565b5ede0 100644 (file)
@@ -60,8 +60,8 @@ ZSTDLIB_API size_t ZSTDMT_endStream(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output);
 
 /* ===   Advanced functions and parameters  === */
 
-#ifndef ZSTDMT_SECTION_SIZE_MIN
-#  define ZSTDMT_SECTION_SIZE_MIN (1U << 20)   /* 1 MB - Minimum size of each compression job */
+#ifndef ZSTDMT_JOBSIZE_MIN
+#  define ZSTDMT_JOBSIZE_MIN (1U << 20)   /* 1 MB - Minimum size of each compression job */
 #endif
 
 ZSTDLIB_API size_t ZSTDMT_compress_advanced(ZSTDMT_CCtx* mtctx,
@@ -112,7 +112,7 @@ ZSTDLIB_API size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx,
 
 size_t ZSTDMT_CCtxParam_setMTCtxParameter(ZSTD_CCtx_params* params, ZSTDMT_parameter parameter, unsigned value);
 
-size_t ZSTDMT_initializeCCtxParameters(ZSTD_CCtx_params* params, unsigned nbThreads);
+size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThreads);
 
 /*! ZSTDMT_initCStream_internal() :
  *  Private use only. Init streaming operation.
index 6b7bfd03cefb75210ebc405093099eda4c46df5f..f07c9eed2f4d8f718d3bd4b0844ca3cd67d9246d 100644 (file)
@@ -1059,7 +1059,8 @@ typedef enum {
 /*! ZSTD_CCtx_setParameter() :
  *  Set one compression parameter, selected by enum ZSTD_cParameter.
  *  Note : when `value` is an enum, cast it to unsigned for proper type checking.
- *  @result : 0, or an error code (which can be tested with ZSTD_isError()). */
+ *  @result : informational value (typically, the one being set, possibly corrected),
+ *            or an error code (which can be tested with ZSTD_isError()). */
 ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value);
 
 /*! ZSTD_CCtx_setPledgedSrcSize() :