Introduce ZSTD_getFrameProgression()
Produces 3 statistics for ongoing frame compression : - ingested - consumed (effectively compressed) - produced Ingested can be larger than consumed due to buffering effect. For the time being, this patch mostly fixes the % ratio issue, since it computes consumed / produced, instead of ingested / produced. That being said, update is not "smooth", because on a slow enough setting, fileio spends most of its time waiting for a worker to complete its job. This could be improved thanks to more granular flushing i.e. start flushing before ongoing job is fully completed.
This commit is contained in:
@@ -754,6 +754,29 @@ size_t ZSTD_estimateCStreamSize(int compressionLevel) {
|
||||
return memBudget;
|
||||
}
|
||||
|
||||
/* ZSTD_getFrameProgression():
|
||||
* tells how much data has been consumed (input) and produced (output) for current frame.
|
||||
* able to count progression inside worker threads (non-blocking mode).
|
||||
*/
|
||||
ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
|
||||
{
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
if ((cctx->appliedParams.nbThreads > 1) || (cctx->appliedParams.nonBlockingMode)) {
|
||||
return ZSTDMT_getFrameProgression(cctx->mtctx);
|
||||
}
|
||||
#endif
|
||||
{ ZSTD_frameProgression fp;
|
||||
size_t const buffered = (cctx->inBuff == NULL) ? 0 :
|
||||
cctx->inBuffPos - cctx->inToCompress;
|
||||
if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
|
||||
assert(buffered <= ZSTD_BLOCKSIZE_MAX);
|
||||
fp.ingested = cctx->consumedSrcSize + buffered;
|
||||
fp.consumed = cctx->consumedSrcSize;
|
||||
fp.produced = cctx->producedCSize;
|
||||
return fp;
|
||||
} }
|
||||
|
||||
|
||||
static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
|
||||
ZSTD_compressionParameters cParams2)
|
||||
{
|
||||
@@ -850,6 +873,7 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pl
|
||||
cctx->appliedParams = params;
|
||||
cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
|
||||
cctx->consumedSrcSize = 0;
|
||||
cctx->producedCSize = 0;
|
||||
if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
|
||||
cctx->appliedParams.fParams.contentSizeFlag = 0;
|
||||
DEBUGLOG(4, "pledged content size : %u ; flag : %u",
|
||||
@@ -1007,6 +1031,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
zc->appliedParams = params;
|
||||
zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
|
||||
zc->consumedSrcSize = 0;
|
||||
zc->producedCSize = 0;
|
||||
if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
|
||||
zc->appliedParams.fParams.contentSizeFlag = 0;
|
||||
DEBUGLOG(4, "pledged content size : %u ; flag : %u",
|
||||
@@ -2063,6 +2088,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
|
||||
ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
|
||||
if (ZSTD_isError(cSize)) return cSize;
|
||||
cctx->consumedSrcSize += srcSize;
|
||||
cctx->producedCSize += (cSize + fhSize);
|
||||
return cSize + fhSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +172,7 @@ struct ZSTD_CCtx_s {
|
||||
size_t blockSize;
|
||||
U64 pledgedSrcSizePlusOne; /* this way, 0 (default) == unknown */
|
||||
U64 consumedSrcSize;
|
||||
U64 producedCSize;
|
||||
XXH64_state_t xxhState;
|
||||
ZSTD_customMem customMem;
|
||||
size_t staticSize;
|
||||
|
||||
@@ -308,7 +308,7 @@ typedef struct {
|
||||
const void* srcStart;
|
||||
size_t prefixSize;
|
||||
size_t srcSize;
|
||||
size_t readSize;
|
||||
size_t consumed;
|
||||
buffer_t dstBuff;
|
||||
size_t cSize;
|
||||
size_t dstFlushed;
|
||||
@@ -382,8 +382,7 @@ void ZSTDMT_compressChunk(void* jobDescription)
|
||||
ZSTD_compressEnd (cctx, dstBuff.start, dstBuff.size, src, job->srcSize) :
|
||||
ZSTD_compressContinue(cctx, dstBuff.start, dstBuff.size, src, job->srcSize);
|
||||
#else
|
||||
if (sizeof(size_t) > sizeof(int))
|
||||
assert(job->srcSize < ((size_t)INT_MAX) * ZSTD_BLOCKSIZE_MAX); /* check overflow */
|
||||
if (sizeof(size_t) > sizeof(int)) assert(job->srcSize < ((size_t)INT_MAX) * ZSTD_BLOCKSIZE_MAX); /* check overflow */
|
||||
{ int const nbBlocks = (int)((job->srcSize + (ZSTD_BLOCKSIZE_MAX-1)) / ZSTD_BLOCKSIZE_MAX);
|
||||
const BYTE* ip = (const BYTE*) src;
|
||||
BYTE* const ostart = (BYTE*)dstBuff.start;
|
||||
@@ -399,7 +398,7 @@ void ZSTDMT_compressChunk(void* jobDescription)
|
||||
op += cSize; assert(op < oend);
|
||||
/* stats */
|
||||
job->cSize += cSize;
|
||||
job->readSize = ZSTD_BLOCKSIZE_MAX * blockNb;
|
||||
job->consumed = ZSTD_BLOCKSIZE_MAX * blockNb;
|
||||
}
|
||||
/* last block */
|
||||
if ((nbBlocks > 0) | job->lastChunk /*need to output a "last block" flag*/ ) {
|
||||
@@ -412,7 +411,7 @@ void ZSTDMT_compressChunk(void* jobDescription)
|
||||
/* stats */
|
||||
job->cSize += cSize;
|
||||
}
|
||||
job->readSize = job->srcSize;
|
||||
job->consumed = job->srcSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -460,6 +459,8 @@ struct ZSTDMT_CCtx_s {
|
||||
unsigned frameEnded;
|
||||
unsigned allJobsCompleted;
|
||||
unsigned long long frameContentSize;
|
||||
unsigned long long consumed;
|
||||
unsigned long long produced;
|
||||
ZSTD_customMem cMem;
|
||||
ZSTD_CDict* cdictLocal;
|
||||
const ZSTD_CDict* cdict;
|
||||
@@ -501,15 +502,6 @@ size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThread
|
||||
return nbThreads;
|
||||
}
|
||||
|
||||
/* ZSTDMT_getNbThreads():
|
||||
* @return nb threads currently active in mtctx.
|
||||
* mtctx must be valid */
|
||||
unsigned ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx)
|
||||
{
|
||||
assert(mtctx != NULL);
|
||||
return mtctx->params.nbThreads;
|
||||
}
|
||||
|
||||
ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbThreads, ZSTD_customMem cMem)
|
||||
{
|
||||
ZSTDMT_CCtx* mtctx;
|
||||
@@ -553,6 +545,7 @@ ZSTDMT_CCtx* ZSTDMT_createCCtx(unsigned nbThreads)
|
||||
return ZSTDMT_createCCtx_advanced(nbThreads, ZSTD_defaultCMem);
|
||||
}
|
||||
|
||||
|
||||
/* ZSTDMT_releaseAllJobResources() :
|
||||
* note : ensure all workers are killed first ! */
|
||||
static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx)
|
||||
@@ -652,6 +645,43 @@ size_t ZSTDMT_setMTCtxParameter(ZSTDMT_CCtx* mtctx, ZSTDMT_parameter parameter,
|
||||
}
|
||||
}
|
||||
|
||||
/* ZSTDMT_getNbThreads():
|
||||
* @return nb threads currently active in mtctx.
|
||||
* mtctx must be valid */
|
||||
unsigned ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx)
|
||||
{
|
||||
assert(mtctx != NULL);
|
||||
return mtctx->params.nbThreads;
|
||||
}
|
||||
|
||||
/* ZSTDMT_getFrameProgression():
|
||||
* tells how much data has been consumed (input) and produced (output) for current frame.
|
||||
* able to count progression inside worker threads.
|
||||
* Note : mutex will be triggered during statistics collection. */
|
||||
ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx)
|
||||
{
|
||||
ZSTD_frameProgression fs;
|
||||
DEBUGLOG(5, "ZSTDMT_getFrameProgression");
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobCompleted_mutex);
|
||||
fs.consumed = mtctx->consumed;
|
||||
fs.produced = mtctx->produced;
|
||||
assert(mtctx->inBuff.filled >= mtctx->prefixSize);
|
||||
fs.ingested = mtctx->consumed + (mtctx->inBuff.filled - mtctx->prefixSize);
|
||||
{ unsigned jobNb;
|
||||
for (jobNb = mtctx->doneJobID ; jobNb < mtctx->nextJobID ; jobNb++) {
|
||||
unsigned const wJobID = jobNb & mtctx->jobIDMask;
|
||||
size_t const cResult = mtctx->jobs[wJobID].cSize;
|
||||
size_t const produced = ZSTD_isError(cResult) ? 0 : cResult;
|
||||
fs.consumed += mtctx->jobs[wJobID].consumed;
|
||||
fs.ingested += mtctx->jobs[wJobID].srcSize;
|
||||
fs.produced += produced;
|
||||
}
|
||||
}
|
||||
ZSTD_pthread_mutex_unlock(&mtctx->jobCompleted_mutex);
|
||||
return fs;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------ */
|
||||
/* ===== Multi-threaded compression ===== */
|
||||
/* ------------------------------------------ */
|
||||
@@ -900,6 +930,8 @@ size_t ZSTDMT_initCStream_internal(
|
||||
zcs->nextJobID = 0;
|
||||
zcs->frameEnded = 0;
|
||||
zcs->allJobsCompleted = 0;
|
||||
zcs->consumed = 0;
|
||||
zcs->produced = 0;
|
||||
if (params.fParams.checksumFlag) XXH64_reset(&zcs->xxhState, 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -963,7 +995,7 @@ static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* zcs, size_t srcSize, unsi
|
||||
zcs->jobs[jobID].src = zcs->inBuff.buffer;
|
||||
zcs->jobs[jobID].srcStart = zcs->inBuff.buffer.start;
|
||||
zcs->jobs[jobID].srcSize = srcSize;
|
||||
zcs->jobs[jobID].readSize = 0;
|
||||
zcs->jobs[jobID].consumed = 0;
|
||||
zcs->jobs[jobID].prefixSize = zcs->prefixSize;
|
||||
assert(zcs->inBuff.filled >= srcSize + zcs->prefixSize);
|
||||
zcs->jobs[jobID].params = zcs->params;
|
||||
@@ -1070,6 +1102,8 @@ static size_t ZSTDMT_flushNextJob(ZSTDMT_CCtx* zcs, ZSTD_outBuffer* output, unsi
|
||||
zcs->jobs[wJobID].dstBuff = g_nullBuffer;
|
||||
zcs->jobs[wJobID].jobCompleted = 0;
|
||||
zcs->doneJobID++;
|
||||
zcs->consumed += job.srcSize;
|
||||
zcs->produced += job.cSize;
|
||||
} else {
|
||||
zcs->jobs[wJobID].dstFlushed = job.dstFlushed;
|
||||
}
|
||||
|
||||
@@ -122,6 +122,13 @@ size_t ZSTDMT_CCtxParam_setNbThreads(ZSTD_CCtx_params* params, unsigned nbThread
|
||||
* mtctx must be valid */
|
||||
unsigned ZSTDMT_getNbThreads(const ZSTDMT_CCtx* mtctx);
|
||||
|
||||
/* ZSTDMT_getFrameProgression():
|
||||
* tells how much data has been consumed (input) and produced (output) for current frame.
|
||||
* able to count progression inside worker threads.
|
||||
*/
|
||||
ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx);
|
||||
|
||||
|
||||
/*! ZSTDMT_initCStream_internal() :
|
||||
* Private use only. Init streaming operation.
|
||||
* expects params to be valid.
|
||||
|
||||
+15
-1
@@ -711,11 +711,25 @@ ZSTDLIB_API size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const
|
||||
* If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN.
|
||||
* If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end.
|
||||
* For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs,
|
||||
* but it may change to mean "empty" in some future version, so prefer using macro ZSTD_CONTENTSIZE_UNKNOWN.
|
||||
* but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead.
|
||||
* @return : 0, or an error code (which can be tested using ZSTD_isError()) */
|
||||
ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned long long ingested;
|
||||
unsigned long long consumed;
|
||||
unsigned long long produced;
|
||||
} ZSTD_frameProgression;
|
||||
|
||||
/* ZSTD_getFrameProgression():
|
||||
* tells how much data has been consumed (input) and produced (output) for current frame.
|
||||
* able to count progression inside worker threads (non-blocking mode).
|
||||
*/
|
||||
ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx);
|
||||
|
||||
|
||||
|
||||
/*===== Advanced Streaming decompression functions =====*/
|
||||
typedef enum { DStream_p_maxWindowSize } ZSTD_DStreamParameter_e;
|
||||
ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); /* obsolete : this API will be removed in a future version */
|
||||
|
||||
Reference in New Issue
Block a user