#define MB *(1 <<20)
#define GB *(1U<<30)
-static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t)(1ULL << ((sizeof(size_t)*8)-31));
+static const size_t maxMemory = (sizeof(size_t)==4) ?
+ /* 32-bit */ (2 GB - 64 MB) :
+ /* 64-bit */ (size_t)(1ULL << ((sizeof(size_t)*8)-31));
+
/* *************************************
* console display
return errorNum; \
}
-#define EXM_THROW(errorNum, retType, ...) { \
+#define RETURN_ERROR(errorNum, retType, ...) { \
retType r; \
memset(&r, 0, sizeof(retType)); \
DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
DISPLAYLEVEL(1, "Error %i : ", errorNum); \
DISPLAYLEVEL(1, __VA_ARGS__); \
DISPLAYLEVEL(1, " \n"); \
- r.error = errorNum; \
+ r.tag = errorNum; \
return r; \
}
/* error without displaying */
-#define EXM_THROW_ND(errorNum, retType, ...) { \
+#define RETURN_QUIET_ERROR(errorNum, retType, ...) { \
retType r; \
memset(&r, 0, sizeof(retType)); \
DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
DEBUGOUTPUT("Error %i : ", errorNum); \
DEBUGOUTPUT(__VA_ARGS__); \
DEBUGOUTPUT(" \n"); \
- r.error = errorNum; \
+ r.tag = errorNum; \
return r; \
}
***************************************/
BMK_advancedParams_t BMK_initAdvancedParams(void) {
- BMK_advancedParams_t res = {
+ BMK_advancedParams_t const res = {
BMK_both, /* mode */
- BMK_timeMode, /* loopMode */
BMK_TIMETEST_DEFAULT_S, /* nbSeconds */
0, /* blockSize */
0, /* nbWorkers */
size_t resSize;
} blockParam_t;
-struct BMK_timeState_t{
- unsigned nbLoops;
- U64 timeRemaining;
- UTIL_time_t coolTime;
- U64 fastestTime;
-};
-
#undef MIN
#undef MAX
#define MIN(a,b) ((a) < (b) ? (a) : (b))
ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize);
}
-
static void BMK_initDCtx(ZSTD_DCtx* dctx,
const void* dictBuffer, size_t dictBufferSize) {
ZSTD_DCtx_reset(dctx);
ZSTD_DCtx_loadDictionary(dctx, dictBuffer, dictBufferSize);
}
+
typedef struct {
- ZSTD_CCtx* ctx;
+ ZSTD_CCtx* cctx;
const void* dictBuffer;
size_t dictBufferSize;
int cLevel;
static size_t local_initCCtx(void* payload) {
BMK_initCCtxArgs* ag = (BMK_initCCtxArgs*)payload;
- BMK_initCCtx(ag->ctx, ag->dictBuffer, ag->dictBufferSize, ag->cLevel, ag->comprParams, ag->adv);
+ BMK_initCCtx(ag->cctx, ag->dictBuffer, ag->dictBufferSize, ag->cLevel, ag->comprParams, ag->adv);
return 0;
}
return 0;
}
-/* additional argument is just the context */
+
+/* `addArgs` is the context */
static size_t local_defaultCompress(
- const void* srcBuffer, size_t srcSize,
- void* dstBuffer, size_t dstSize,
- void* addArgs) {
+ const void* srcBuffer, size_t srcSize,
+ void* dstBuffer, size_t dstSize,
+ void* addArgs)
+{
size_t moreToFlush = 1;
- ZSTD_CCtx* ctx = (ZSTD_CCtx*)addArgs;
+ ZSTD_CCtx* const cctx = (ZSTD_CCtx*)addArgs;
ZSTD_inBuffer in;
ZSTD_outBuffer out;
- in.src = srcBuffer;
- in.size = srcSize;
- in.pos = 0;
- out.dst = dstBuffer;
- out.size = dstSize;
- out.pos = 0;
+ in.src = srcBuffer; in.size = srcSize; in.pos = 0;
+ out.dst = dstBuffer; out.size = dstSize; out.pos = 0;
while (moreToFlush) {
if(out.pos == out.size) {
return (size_t)-ZSTD_error_dstSize_tooSmall;
}
- moreToFlush = ZSTD_compress_generic(ctx, &out, &in, ZSTD_e_end);
+ moreToFlush = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
if (ZSTD_isError(moreToFlush)) {
return moreToFlush;
}
return out.pos;
}
-/* additional argument is just the context */
+/* `addArgs` is the context */
static size_t local_defaultDecompress(
- const void* srcBuffer, size_t srcSize,
- void* dstBuffer, size_t dstSize,
- void* addArgs) {
+ const void* srcBuffer, size_t srcSize,
+ void* dstBuffer, size_t dstSize,
+ void* addArgs)
+{
size_t moreToFlush = 1;
- ZSTD_DCtx* dctx = (ZSTD_DCtx*)addArgs;
+ ZSTD_DCtx* const dctx = (ZSTD_DCtx*)addArgs;
ZSTD_inBuffer in;
ZSTD_outBuffer out;
- in.src = srcBuffer;
- in.size = srcSize;
- in.pos = 0;
- out.dst = dstBuffer;
- out.size = dstSize;
- out.pos = 0;
+ in.src = srcBuffer; in.size = srcSize; in.pos = 0;
+ out.dst = dstBuffer; out.size = dstSize; out.pos = 0;
while (moreToFlush) {
if(out.pos == out.size) {
return (size_t)-ZSTD_error_dstSize_tooSmall;
}
- moreToFlush = ZSTD_decompress_generic(dctx,
- &out, &in);
+ moreToFlush = ZSTD_decompress_generic(dctx, &out, &in);
if (ZSTD_isError(moreToFlush)) {
return moreToFlush;
}
}
-/* initFn will be measured once, bench fn will be measured x times */
-/* benchFn should return error value or out Size */
+
+/*=== Benchmarking an arbitrary function ===*/
+
+int BMK_isSuccessful_runOutcome(BMK_runOutcome_t outcome)
+{
+ return outcome.tag == 0;
+}
+
+/* warning : this function will stop program execution if outcome is invalid !
+ * check outcome validity first, using BMK_isValid_runResult() */
+BMK_runTime_t BMK_extract_runTime(BMK_runOutcome_t outcome)
+{
+ assert(outcome.tag == 0);
+ return outcome.internal_never_use_directly;
+}
+
+static BMK_runOutcome_t BMK_setValid_runTime(BMK_runTime_t runTime)
+{
+ BMK_runOutcome_t outcome;
+ outcome.tag = 0;
+ outcome.internal_never_use_directly = runTime;
+ return outcome;
+}
+
+
+/* initFn will be measured once, benchFn will be measured `nbLoops` times */
+/* initFn is optional, provide NULL if none */
+/* benchFn must return size_t field compliant with ZSTD_isError for error valuee */
/* takes # of blocks and list of size & stuff for each. */
-/* only does looping */
-/* note time per loop could be zero if interval too short */
-BMK_customReturn_t BMK_benchFunction(
- BMK_benchFn_t benchFn, void* benchPayload,
- BMK_initFn_t initFn, void* initPayload,
- size_t blockCount,
- const void* const * const srcBlockBuffers, const size_t* srcBlockSizes,
- void* const * const dstBlockBuffers, const size_t* dstBlockCapacities, size_t* blockResult,
- unsigned nbLoops) {
+/* can report result of benchFn for each block into blockResult. */
+/* blockResult is optional, provide NULL if this information is not required */
+/* note : time per loop could be zero if run time < timer resolution */
+BMK_runOutcome_t BMK_benchFunction(
+ BMK_benchFn_t benchFn, void* benchPayload,
+ BMK_initFn_t initFn, void* initPayload,
+ size_t blockCount,
+ const void* const * srcBlockBuffers, const size_t* srcBlockSizes,
+ void* const * dstBlockBuffers, const size_t* dstBlockCapacities,
+ size_t* blockResult,
+ unsigned nbLoops)
+{
size_t dstSize = 0;
U64 totalTime;
- BMK_customReturn_t retval;
- UTIL_time_t clockStart;
-
if(!nbLoops) {
- EXM_THROW_ND(1, BMK_customReturn_t, "nbLoops must be nonzero \n");
+ RETURN_QUIET_ERROR(1, BMK_runOutcome_t, "nbLoops must be nonzero ");
}
- {
- size_t i;
+ /* init */
+ { size_t i;
for(i = 0; i < blockCount; i++) {
memset(dstBlockBuffers[i], 0xE5, dstBlockCapacities[i]); /* warm up and erase result buffer */
}
#endif
}
- {
- unsigned i, j;
- clockStart = UTIL_getTime();
- if(initFn != NULL) { initFn(initPayload); }
- for(i = 0; i < nbLoops; i++) {
- for(j = 0; j < blockCount; j++) {
- size_t res = benchFn(srcBlockBuffers[j], srcBlockSizes[j], dstBlockBuffers[j], dstBlockCapacities[j], benchPayload);
+ /* benchmark loop */
+ { UTIL_time_t const clockStart = UTIL_getTime();
+ unsigned loopNb, blockNb;
+ if (initFn != NULL) initFn(initPayload);
+ for (loopNb = 0; loopNb < nbLoops; loopNb++) {
+ for (blockNb = 0; blockNb < blockCount; blockNb++) {
+ size_t const res = benchFn(srcBlockBuffers[blockNb], srcBlockSizes[blockNb],
+ dstBlockBuffers[blockNb], dstBlockCapacities[blockNb],
+ benchPayload);
if(ZSTD_isError(res)) {
- EXM_THROW_ND(2, BMK_customReturn_t, "Function benchmarking failed on block %u of size %u : %s \n",
- j, (U32)dstBlockCapacities[j], ZSTD_getErrorName(res));
- } else if(i == nbLoops - 1) {
+ RETURN_QUIET_ERROR(2, BMK_runOutcome_t,
+ "Function benchmark failed on block %u of size %u : %s",
+ blockNb, (U32)dstBlockCapacities[blockNb], ZSTD_getErrorName(res));
+ } else if (loopNb == 0) {
dstSize += res;
- if(blockResult != NULL) {
- blockResult[j] = res;
- }
- }
- }
- }
+ if (blockResult != NULL) blockResult[blockNb] = res;
+ dstSize += res;
+ } }
+ } /* for (loopNb = 0; loopNb < nbLoops; loopNb++) */
totalTime = UTIL_clockSpanNano(clockStart);
}
- retval.error = 0;
- retval.result.nanoSecPerRun = totalTime / nbLoops;
- retval.result.sumOfReturn = dstSize;
- return retval;
+ { BMK_runTime_t rt;
+ rt.nanoSecPerRun = totalTime / nbLoops;
+ rt.sumOfReturn = dstSize;
+ return BMK_setValid_runTime(rt);
+ }
}
-#define MINUSABLETIME 500000000ULL /* 0.5 seconds in ns */
-void BMK_resetTimedFnState(BMK_timedFnState_t* r, unsigned nbSeconds) {
- r->nbLoops = 1;
- r->timeRemaining = (U64)nbSeconds * TIMELOOP_NANOSEC;
- r->coolTime = UTIL_getTime();
- r->fastestTime = (U64)(-1LL);
-}
+/* ==== Benchmarking any function, providing intermediate results ==== */
+
+struct BMK_timedFnState_s {
+ U64 timeSpent_ns;
+ U64 timeBudget_ns;
+ BMK_runTime_t fastestRun;
+ unsigned nbLoops;
+ UTIL_time_t coolTime;
+}; /* typedef'd to BMK_timedFnState_t within bench.h */
BMK_timedFnState_t* BMK_createTimedFnState(unsigned nbSeconds) {
- BMK_timedFnState_t* r = (BMK_timedFnState_t*)malloc(sizeof(struct BMK_timeState_t));
- if(r == NULL) {
- return r;
- }
+ BMK_timedFnState_t* const r = (BMK_timedFnState_t*)malloc(sizeof(*r));
+ if (r == NULL) return NULL; /* malloc() error */
BMK_resetTimedFnState(r, nbSeconds);
return r;
}
+void BMK_resetTimedFnState(BMK_timedFnState_t* r, unsigned nbSeconds) {
+ r->timeSpent_ns = 0;
+ r->timeBudget_ns = (U64)nbSeconds * TIMELOOP_NANOSEC;
+ r->fastestRun.nanoSecPerRun = (U64)(-1LL);
+ r->fastestRun.sumOfReturn = (size_t)(-1LL);
+ r->nbLoops = 1;
+ r->coolTime = UTIL_getTime();
+}
+
void BMK_freeTimedFnState(BMK_timedFnState_t* state) {
free(state);
}
-/* make option for dstBlocks to be */
-BMK_customTimedReturn_t BMK_benchFunctionTimed(
- BMK_timedFnState_t* cont,
- BMK_benchFn_t benchFn, void* benchPayload,
- BMK_initFn_t initFn, void* initPayload,
- size_t blockCount,
- const void* const* const srcBlockBuffers, const size_t* srcBlockSizes,
- void * const * const dstBlockBuffers, const size_t * dstBlockCapacities, size_t* blockResults)
+
+/* check first if the return structure represents an error or a valid result */
+int BMK_isSuccessful_timedFnOutcome(BMK_timedFnOutcome_t outcome)
+{
+ return (outcome.tag < 2);
+}
+
+/* extract intermediate results from variant type.
+ * note : this function will abort() program execution if result is not valid.
+ * check result validity first, by using BMK_isSuccessful_timedFnOutcome() */
+BMK_runTime_t BMK_extract_timedFnResult(BMK_timedFnOutcome_t outcome)
+{
+ assert(outcome.tag < 2);
+ return outcome.internal_never_use_directly;
+}
+
+/* Tells if nb of seconds set in timedFnState for all runs is spent.
+ * note : this function will return 1 if BMK_benchFunctionTimed() has actually errored. */
+int BMK_isCompleted_timedFnOutcome(BMK_timedFnOutcome_t outcome)
+{
+ return (outcome.tag >= 1);
+}
+
+
+#define MINUSABLETIME (TIMELOOP_NANOSEC / 2) /* 0.5 seconds */
+
+BMK_timedFnOutcome_t BMK_benchFunctionTimed(
+ BMK_timedFnState_t* cont,
+ BMK_benchFn_t benchFn, void* benchPayload,
+ BMK_initFn_t initFn, void* initPayload,
+ size_t blockCount,
+ const void* const* srcBlockBuffers, const size_t* srcBlockSizes,
+ void * const * dstBlockBuffers, const size_t * dstBlockCapacities,
+ size_t* blockResults)
{
- U64 fastest = cont->fastestTime;
int completed = 0;
- BMK_customTimedReturn_t r;
- r.completed = 0;
+ BMK_timedFnOutcome_t r;
+ BMK_runTime_t bestRunTime = cont->fastestRun;
+
+ r.tag = 2; /* error by default */
+
+ while (!completed) {
+ BMK_runOutcome_t runResult;
- while(!r.completed && !completed)
- {
/* Overheat protection */
if (UTIL_clockSpanMicro(cont->coolTime) > ACTIVEPERIOD_MICROSEC) {
DEBUGOUTPUT("\rcooling down ... \r");
UTIL_sleep(COOLPERIOD_SEC);
cont->coolTime = UTIL_getTime();
}
+
/* reinitialize capacity */
- r.result = BMK_benchFunction(benchFn, benchPayload, initFn, initPayload,
- blockCount, srcBlockBuffers, srcBlockSizes, dstBlockBuffers, dstBlockCapacities, blockResults, cont->nbLoops);
- if(r.result.error) { /* completed w/ error */
- r.completed = 1;
+ runResult = BMK_benchFunction(benchFn, benchPayload,
+ initFn, initPayload,
+ blockCount,
+ srcBlockBuffers, srcBlockSizes,
+ dstBlockBuffers, dstBlockCapacities,
+ blockResults,
+ cont->nbLoops);
+
+ if(!BMK_isSuccessful_runOutcome(runResult)) { /* error : move out */
+ r.tag = 2;
return r;
}
- { U64 const loopDuration = r.result.result.nanoSecPerRun * cont->nbLoops;
- r.completed = (cont->timeRemaining <= loopDuration);
- cont->timeRemaining -= loopDuration;
- if (loopDuration > (TIMELOOP_NANOSEC / 100)) {
- fastest = MIN(fastest, r.result.result.nanoSecPerRun);
- if(loopDuration >= MINUSABLETIME) {
- r.result.result.nanoSecPerRun = fastest;
- cont->fastestTime = fastest;
- }
- cont->nbLoops = (U32)(TIMELOOP_NANOSEC / r.result.result.nanoSecPerRun) + 1;
+ { BMK_runTime_t const newRunTime = BMK_extract_runTime(runResult);
+ U64 const loopDuration_ns = newRunTime.nanoSecPerRun * cont->nbLoops;
+
+ cont->timeSpent_ns += loopDuration_ns;
+
+ /* estimate nbLoops for next run to last approximately 1 second */
+ if (loopDuration_ns > (TIMELOOP_NANOSEC / 50)) {
+ U64 const fastestRun_ns = MIN(bestRunTime.nanoSecPerRun, newRunTime.nanoSecPerRun);
+ cont->nbLoops = (U32)(TIMELOOP_NANOSEC / fastestRun_ns) + 1;
} else {
- const unsigned multiplier = 2;
+ /* previous run was too short : blindly increase workload by x multiplier */
+ const unsigned multiplier = 10;
assert(cont->nbLoops < ((unsigned)-1) / multiplier); /* avoid overflow */
cont->nbLoops *= multiplier;
}
- if(loopDuration < MINUSABLETIME) { /* don't report results which have time too low */
+
+ if(loopDuration_ns < MINUSABLETIME) {
+ /* don't report results for which benchmark run time was too small : increased risks of rounding errors */
+ assert(completed == 0);
continue;
+ } else {
+ if(newRunTime.nanoSecPerRun < bestRunTime.nanoSecPerRun) {
+ bestRunTime = newRunTime;
+ }
+ completed = 1;
}
-
}
- completed = 1;
- }
+ } /* while (!completed) */
+
+ r.tag = (cont->timeSpent_ns >= cont->timeBudget_ns); /* report if time budget is spent */
+ r.internal_never_use_directly = bestRunTime;
return r;
}
+
+/* ================================================================= */
+/* Benchmark Zstandard, mem-to-mem scenarios */
+/* ================================================================= */
+
+int BMK_isSuccessful_benchOutcome(BMK_benchOutcome_t outcome)
+{
+ return outcome.tag == 0;
+}
+
+BMK_benchResult_t BMK_extract_benchResult(BMK_benchOutcome_t outcome)
+{
+ assert(outcome.tag == 0);
+ return outcome.internal_never_use_directly;
+}
+
+static BMK_benchOutcome_t BMK_benchOutcome_error()
+{
+ BMK_benchOutcome_t b;
+ memset(&b, 0, sizeof(b));
+ b.tag = 1;
+ return b;
+}
+
+static BMK_benchOutcome_t BMK_benchOutcome_setValidResult(BMK_benchResult_t result)
+{
+ BMK_benchOutcome_t b;
+ b.tag = 0;
+ b.internal_never_use_directly = result;
+ return b;
+}
+
+
/* benchMem with no allocation */
-static BMK_return_t BMK_benchMemAdvancedNoAlloc(
- const void ** const srcPtrs, size_t* const srcSizes,
- void** const cPtrs, size_t* const cCapacities, size_t* const cSizes,
- void** const resPtrs, size_t* const resSizes,
- void** resultBufferPtr, void* compressedBuffer,
- const size_t maxCompressedSize,
- BMK_timedFnState_t* timeStateCompress, BMK_timedFnState_t* timeStateDecompress,
-
- const void* srcBuffer, size_t srcSize,
- const size_t* fileSizes, unsigned nbFiles,
- const int cLevel, const ZSTD_compressionParameters* comprParams,
- const void* dictBuffer, size_t dictBufferSize,
- ZSTD_CCtx* ctx, ZSTD_DCtx* dctx,
- int displayLevel, const char* displayName, const BMK_advancedParams_t* adv)
+static BMK_benchOutcome_t BMK_benchMemAdvancedNoAlloc(
+ const void** srcPtrs, size_t* srcSizes,
+ void** cPtrs, size_t* cCapacities, size_t* cSizes,
+ void** resPtrs, size_t* resSizes,
+ void** resultBufferPtr, void* compressedBuffer,
+ size_t maxCompressedSize,
+ BMK_timedFnState_t* timeStateCompress,
+ BMK_timedFnState_t* timeStateDecompress,
+
+ const void* srcBuffer, size_t srcSize,
+ const size_t* fileSizes, unsigned nbFiles,
+ const int cLevel, const ZSTD_compressionParameters* comprParams,
+ const void* dictBuffer, size_t dictBufferSize,
+ ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
+ int displayLevel, const char* displayName,
+ const BMK_advancedParams_t* adv)
{
size_t const blockSize = ((adv->blockSize>=32 && (adv->mode != BMK_decodeOnly)) ? adv->blockSize : srcSize) + (!srcSize); /* avoid div by 0 */
- BMK_return_t results = { { 0, 0, 0, 0 }, 0 } ;
+ BMK_benchResult_t benchResult;
size_t const loadedCompressedSize = srcSize;
size_t cSize = 0;
double ratio = 0.;
U32 nbBlocks;
- if(!ctx || !dctx)
- EXM_THROW(31, BMK_return_t, "error: passed in null context");
+ assert(cctx != NULL); assert(dctx != NULL);
/* init */
- if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* display last 17 characters */
+ if (strlen(displayName)>17) displayName += strlen(displayName) - 17; /* display last 17 characters */
if (adv->mode == BMK_decodeOnly) { /* benchmark only decompression : source must be already compressed */
const char* srcPtr = (const char*)srcBuffer;
U64 totalDSize64 = 0;
U32 fileNb;
for (fileNb=0; fileNb<nbFiles; fileNb++) {
U64 const fSize64 = ZSTD_findDecompressedSize(srcPtr, fileSizes[fileNb]);
- if (fSize64==0) EXM_THROW(32, BMK_return_t, "Impossible to determine original size ");
+ if (fSize64==0) RETURN_ERROR(32, BMK_benchOutcome_t, "Impossible to determine original size ");
totalDSize64 += fSize64;
srcPtr += fileSizes[fileNb];
}
{ size_t const decodedSize = (size_t)totalDSize64;
+ assert((U64)decodedSize == totalDSize64); /* check overflow */
free(*resultBufferPtr);
*resultBufferPtr = malloc(decodedSize);
if (!(*resultBufferPtr)) {
- EXM_THROW(33, BMK_return_t, "not enough memory");
+ RETURN_ERROR(33, BMK_benchOutcome_t, "not enough memory");
}
- if (totalDSize64 > decodedSize) {
+ if (totalDSize64 > decodedSize) { /* size_t overflow */
free(*resultBufferPtr);
- EXM_THROW(32, BMK_return_t, "original size is too large"); /* size_t overflow */
+ RETURN_ERROR(32, BMK_benchOutcome_t, "original size is too large");
}
cSize = srcSize;
srcSize = decodedSize;
U32 const blockEnd = nbBlocks + nbBlocksforThisFile;
for ( ; nbBlocks<blockEnd; nbBlocks++) {
size_t const thisBlockSize = MIN(remaining, blockSize);
- srcPtrs[nbBlocks] = (const void*)srcPtr;
+ srcPtrs[nbBlocks] = srcPtr;
srcSizes[nbBlocks] = thisBlockSize;
- cPtrs[nbBlocks] = (void*)cPtr;
+ cPtrs[nbBlocks] = cPtr;
cCapacities[nbBlocks] = (adv->mode == BMK_decodeOnly) ? thisBlockSize : ZSTD_compressBound(thisBlockSize);
- resPtrs[nbBlocks] = (void*)resPtr;
+ resPtrs[nbBlocks] = resPtr;
resSizes[nbBlocks] = (adv->mode == BMK_decodeOnly) ? (size_t) ZSTD_findDecompressedSize(srcPtr, thisBlockSize) : thisBlockSize;
srcPtr += thisBlockSize;
cPtr += cCapacities[nbBlocks];
}
}
- /* warmimg up memory */
+ /* warmimg up `compressedBuffer` */
if (adv->mode == BMK_decodeOnly) {
memcpy(compressedBuffer, srcBuffer, loadedCompressedSize);
} else {
}
/* Bench */
- {
- U64 const crcOrig = (adv->mode == BMK_decodeOnly) ? 0 : XXH64(srcBuffer, srcSize, 0);
+ { U64 const crcOrig = (adv->mode == BMK_decodeOnly) ? 0 : XXH64(srcBuffer, srcSize, 0);
# define NB_MARKS 4
- const char* const marks[NB_MARKS] = { " |", " /", " =", "\\" };
+ const char* marks[NB_MARKS] = { " |", " /", " =", " \\" };
U32 markNb = 0;
- DISPLAYLEVEL(2, "\r%79s\r", "");
-
+ int compressionCompleted = (adv->mode == BMK_decodeOnly);
+ int decompressionCompleted = (adv->mode == BMK_compressOnly);
+ BMK_initCCtxArgs cctxprep;
+ BMK_initDCtxArgs dctxprep;
+ cctxprep.cctx = cctx;
+ cctxprep.dictBuffer = dictBuffer;
+ cctxprep.dictBufferSize = dictBufferSize;
+ cctxprep.cLevel = cLevel;
+ cctxprep.comprParams = comprParams;
+ cctxprep.adv = adv;
+ dctxprep.dctx = dctx;
+ dctxprep.dictBuffer = dictBuffer;
+ dctxprep.dictBufferSize = dictBufferSize;
+
+ DISPLAYLEVEL(2, "\r%70s\r", ""); /* blank line */
DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->\r", marks[markNb], displayName, (U32)srcSize);
- {
- BMK_initCCtxArgs cctxprep;
- BMK_initDCtxArgs dctxprep;
- cctxprep.ctx = ctx;
- cctxprep.dictBuffer = dictBuffer;
- cctxprep.dictBufferSize = dictBufferSize;
- cctxprep.cLevel = cLevel;
- cctxprep.comprParams = comprParams;
- cctxprep.adv = adv;
- dctxprep.dctx = dctx;
- dctxprep.dictBuffer = dictBuffer;
- dctxprep.dictBufferSize = dictBufferSize;
- if(adv->loopMode == BMK_timeMode) {
- BMK_customTimedReturn_t intermediateResultCompress;
- BMK_customTimedReturn_t intermediateResultDecompress;
- if(adv->mode == BMK_compressOnly) {
- intermediateResultCompress.completed = 0;
- intermediateResultDecompress.completed = 1;
- } else if (adv->mode == BMK_decodeOnly) {
- intermediateResultCompress.completed = 1;
- intermediateResultDecompress.completed = 0;
- } else { /* both */
- intermediateResultCompress.completed = 0;
- intermediateResultDecompress.completed = 0;
- }
- while(!(intermediateResultCompress.completed && intermediateResultDecompress.completed)) {
- if(!intermediateResultCompress.completed) {
- intermediateResultCompress = BMK_benchFunctionTimed(timeStateCompress, &local_defaultCompress, (void*)ctx, &local_initCCtx, (void*)&cctxprep,
- nbBlocks, srcPtrs, srcSizes, cPtrs, cCapacities, cSizes);
- if(intermediateResultCompress.result.error) {
- results.error = intermediateResultCompress.result.error;
- return results;
- }
- ratio = (double)(srcSize / intermediateResultCompress.result.result.sumOfReturn);
- {
- int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
- results.result.cSpeed = (srcSize * TIMELOOP_NANOSEC / intermediateResultCompress.result.result.nanoSecPerRun);
- cSize = intermediateResultCompress.result.result.sumOfReturn;
- results.result.cSize = cSize;
- ratio = (double)srcSize / results.result.cSize;
- markNb = (markNb+1) % NB_MARKS;
- DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s\r",
- marks[markNb], displayName, (U32)srcSize, (U32)results.result.cSize,
- ratioAccuracy, ratio,
- results.result.cSpeed < (10 MB) ? 2 : 1, (double)results.result.cSpeed / (1 MB));
- }
- }
- if(!intermediateResultDecompress.completed) {
- intermediateResultDecompress = BMK_benchFunctionTimed(timeStateDecompress, &local_defaultDecompress, (void*)(dctx), &local_initDCtx, (void*)&dctxprep,
- nbBlocks, (const void* const*)cPtrs, cSizes, resPtrs, resSizes, NULL);
- if(intermediateResultDecompress.result.error) {
- results.error = intermediateResultDecompress.result.error;
- return results;
- }
+ while (!(compressionCompleted && decompressionCompleted)) {
- {
- int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
- results.result.dSpeed = (srcSize * TIMELOOP_NANOSEC/ intermediateResultDecompress.result.result.nanoSecPerRun);
- markNb = (markNb+1) % NB_MARKS;
- DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s ,%6.1f MB/s \r",
- marks[markNb], displayName, (U32)srcSize, (U32)results.result.cSize,
- ratioAccuracy, ratio,
- results.result.cSpeed < (10 MB) ? 2 : 1, (double)results.result.cSpeed / (1 MB),
- (double)results.result.dSpeed / (1 MB));
- }
- }
+ if (!compressionCompleted) {
+ BMK_runTime_t cResult;
+
+ BMK_timedFnOutcome_t const cOutcome =
+ BMK_benchFunctionTimed(timeStateCompress,
+ &local_defaultCompress, (void*)cctx,
+ &local_initCCtx, (void*)&cctxprep,
+ nbBlocks,
+ srcPtrs, srcSizes,
+ cPtrs, cCapacities,
+ cSizes);
+
+ if (!BMK_isSuccessful_timedFnOutcome(cOutcome)) {
+ return BMK_benchOutcome_error();
}
- } else { //iterMode;
- if(adv->mode != BMK_decodeOnly) {
+ cResult = BMK_extract_timedFnResult(cOutcome);
+ ratio = (double)(srcSize / cResult.sumOfReturn);
+
+ { int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
+ cSize = cResult.sumOfReturn;
+ benchResult.cSpeed = (srcSize * TIMELOOP_NANOSEC / cResult.nanoSecPerRun);
+ benchResult.cSize = cSize;
+ ratio = (double)srcSize / cSize;
+ markNb = (markNb+1) % NB_MARKS;
+ DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s\r",
+ marks[markNb], displayName, (U32)srcSize, (U32)cSize,
+ ratioAccuracy, ratio,
+ benchResult.cSpeed < (10 MB) ? 2 : 1, (double)benchResult.cSpeed / (1 MB));
+ }
+ }
- BMK_customReturn_t compressionResults = BMK_benchFunction(&local_defaultCompress, (void*)ctx, &local_initCCtx, (void*)&cctxprep,
- nbBlocks, srcPtrs, srcSizes, cPtrs, cCapacities, cSizes, adv->nbSeconds);
- if(compressionResults.error) {
- results.error = compressionResults.error;
- return results;
- }
+ if(!decompressionCompleted) {
+ BMK_runTime_t dResult;
- if(compressionResults.result.nanoSecPerRun == 0) {
- results.result.cSpeed = 0;
- } else {
- results.result.cSpeed = srcSize * TIMELOOP_NANOSEC / compressionResults.result.nanoSecPerRun;
- }
+ BMK_timedFnOutcome_t const dOutcome =
+ BMK_benchFunctionTimed(timeStateDecompress,
+ &local_defaultDecompress, (void*)(dctx),
+ &local_initDCtx, (void*)&dctxprep,
+ nbBlocks,
+ (const void* const*)cPtrs, cSizes,
+ resPtrs, resSizes,
+ NULL);
- results.result.cSize = compressionResults.result.sumOfReturn;
- {
- int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
- cSize = compressionResults.result.sumOfReturn;
- results.result.cSize = cSize;
- ratio = (double)srcSize / results.result.cSize;
- markNb = (markNb+1) % NB_MARKS;
- DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s\r",
- marks[markNb], displayName, (U32)srcSize, (U32)results.result.cSize,
- ratioAccuracy, ratio,
- results.result.cSpeed < (10 MB) ? 2 : 1, (double)results.result.cSpeed / (1 MB));
- }
+ if(!BMK_isSuccessful_timedFnOutcome(dOutcome)) {
+ return BMK_benchOutcome_error();
}
- if(adv->mode != BMK_compressOnly) {
- BMK_customReturn_t decompressionResults = BMK_benchFunction(
- &local_defaultDecompress, (void*)(dctx),
- &local_initDCtx, (void*)&dctxprep, nbBlocks,
- (const void* const*)cPtrs, cSizes, resPtrs, resSizes, NULL,
- adv->nbSeconds);
- if(decompressionResults.error) {
- results.error = decompressionResults.error;
- return results;
- }
- if(decompressionResults.result.nanoSecPerRun == 0) {
- results.result.dSpeed = 0;
- } else {
- results.result.dSpeed = srcSize * TIMELOOP_NANOSEC / decompressionResults.result.nanoSecPerRun;
- }
+ dResult = BMK_extract_timedFnResult(dOutcome);
- {
- int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
- markNb = (markNb+1) % NB_MARKS;
- DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s ,%6.1f MB/s \r",
- marks[markNb], displayName, (U32)srcSize, (U32)results.result.cSize,
- ratioAccuracy, ratio,
- results.result.cSpeed < (10 MB) ? 2 : 1, (double)results.result.cSpeed / (1 MB),
- (double)results.result.dSpeed / (1 MB));
- }
+ { int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
+ benchResult.dSpeed = (srcSize * TIMELOOP_NANOSEC / dResult.nanoSecPerRun);
+ markNb = (markNb+1) % NB_MARKS;
+ DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s ,%6.1f MB/s \r",
+ marks[markNb], displayName, (U32)srcSize, (U32)benchResult.cSize,
+ ratioAccuracy, ratio,
+ benchResult.cSpeed < (10 MB) ? 2 : 1, (double)benchResult.cSpeed / (1 MB),
+ (double)benchResult.dSpeed / (1 MB));
}
}
}
/* CRC Checking */
- { void* resultBuffer = *resultBufferPtr;
+ { const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr);
U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);
- /* adv->mode == 0 -> compress + decompress */
if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) {
size_t u;
DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x \n", displayName, (unsigned)crcOrig, (unsigned)crcCheck);
for (u=0; u<srcSize; u++) {
- if (((const BYTE*)srcBuffer)[u] != ((const BYTE*)resultBuffer)[u]) {
+ if (((const BYTE*)srcBuffer)[u] != resultBuffer[u]) {
U32 segNb, bNb, pos;
size_t bacc = 0;
DISPLAY("Decoding error at pos %u ", (U32)u);
for (n=1; n<3; n++) DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]);
DISPLAY(" \n");
DISPLAY("decode: ");
- for (n=-5; n<0; n++) DISPLAY("%02X ", ((const BYTE*)resultBuffer)[u+n]);
- DISPLAY(" :%02X: ", ((const BYTE*)resultBuffer)[u]);
- for (n=1; n<3; n++) DISPLAY("%02X ", ((const BYTE*)resultBuffer)[u+n]);
+ for (n=-5; n<0; n++) DISPLAY("%02X ", resultBuffer[u+n]);
+ DISPLAY(" :%02X: ", resultBuffer[u]);
+ for (n=1; n<3; n++) DISPLAY("%02X ", resultBuffer[u+n]);
DISPLAY(" \n");
}
break;
}
} /* CRC Checking */
- if (displayLevel == 1) { /* hidden display mode -q, used by python speed benchmark */
- double const cSpeed = (double)results.result.cSpeed / (1 MB);
- double const dSpeed = (double)results.result.dSpeed / (1 MB);
- if (adv->additionalParam) {
- DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s (param=%d)\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName, adv->additionalParam);
- } else {
- DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName);
+ if (displayLevel == 1) { /* hidden display mode -q, used by python speed benchmark */
+ double const cSpeed = (double)benchResult.cSpeed / (1 MB);
+ double const dSpeed = (double)benchResult.dSpeed / (1 MB);
+ if (adv->additionalParam) {
+ DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s (param=%d)\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName, adv->additionalParam);
+ } else {
+ DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName);
+ }
}
- }
- DISPLAYLEVEL(2, "%2i#\n", cLevel);
+
+ DISPLAYLEVEL(2, "%2i#\n", cLevel);
} /* Bench */
- results.result.cMem = (1ULL << (comprParams->windowLog)) + ZSTD_sizeof_CCtx(ctx);
- results.error = 0;
- return results;
+
+ benchResult.cMem = (1ULL << (comprParams->windowLog)) + ZSTD_sizeof_CCtx(cctx);
+ return BMK_benchOutcome_setValidResult(benchResult);
}
-BMK_return_t BMK_benchMemAdvanced(const void* srcBuffer, size_t srcSize,
+BMK_benchOutcome_t BMK_benchMemAdvanced(const void* srcBuffer, size_t srcSize,
void* dstBuffer, size_t dstCapacity,
const size_t* fileSizes, unsigned nbFiles,
const int cLevel, const ZSTD_compressionParameters* comprParams,
int displayLevel, const char* displayName, const BMK_advancedParams_t* adv)
{
+ int const dstParamsError = !dstBuffer ^ !dstCapacity; /* must be both NULL or none */
+
size_t const blockSize = ((adv->blockSize>=32 && (adv->mode != BMK_decodeOnly)) ? adv->blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ;
U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles;
BMK_timedFnState_t* timeStateCompress = BMK_createTimedFnState(adv->nbSeconds);
BMK_timedFnState_t* timeStateDecompress = BMK_createTimedFnState(adv->nbSeconds);
- ZSTD_CCtx* ctx = ZSTD_createCCtx();
- ZSTD_DCtx* dctx = ZSTD_createDCtx();
+ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
+ ZSTD_DCtx* const dctx = ZSTD_createDCtx();
const size_t maxCompressedSize = dstCapacity ? dstCapacity : ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024);
void* const internalDstBuffer = dstBuffer ? NULL : malloc(maxCompressedSize);
void* const compressedBuffer = dstBuffer ? dstBuffer : internalDstBuffer;
- BMK_return_t results = { { 0, 0, 0, 0 }, 0 };
-
- int parametersConflict = !dstBuffer ^ !dstCapacity;
+ BMK_benchOutcome_t outcome = BMK_benchOutcome_error(); /* error by default */
void* resultBuffer = srcSize ? malloc(srcSize) : NULL;
int allocationincomplete = !srcPtrs || !srcSizes || !cPtrs ||
!cSizes || !cCapacities || !resPtrs || !resSizes ||
- !timeStateCompress || !timeStateDecompress || !compressedBuffer || !resultBuffer;
-
-
-
- if (!allocationincomplete && !parametersConflict) {
- results = BMK_benchMemAdvancedNoAlloc(srcPtrs, srcSizes, cPtrs, cCapacities, cSizes,
- resPtrs, resSizes, &resultBuffer, compressedBuffer, maxCompressedSize, timeStateCompress, timeStateDecompress,
- srcBuffer, srcSize, fileSizes, nbFiles, cLevel, comprParams,
- dictBuffer, dictBufferSize, ctx, dctx, displayLevel, displayName, adv);
+ !timeStateCompress || !timeStateDecompress ||
+ !cctx || !dctx ||
+ !compressedBuffer || !resultBuffer;
+
+
+ if (!allocationincomplete && !dstParamsError) {
+ outcome = BMK_benchMemAdvancedNoAlloc(srcPtrs, srcSizes,
+ cPtrs, cCapacities, cSizes,
+ resPtrs, resSizes,
+ &resultBuffer,
+ compressedBuffer, maxCompressedSize,
+ timeStateCompress, timeStateDecompress,
+ srcBuffer, srcSize,
+ fileSizes, nbFiles,
+ cLevel, comprParams,
+ dictBuffer, dictBufferSize,
+ cctx, dctx,
+ displayLevel, displayName, adv);
}
/* clean up */
BMK_freeTimedFnState(timeStateCompress);
BMK_freeTimedFnState(timeStateDecompress);
- ZSTD_freeCCtx(ctx);
+ ZSTD_freeCCtx(cctx);
ZSTD_freeDCtx(dctx);
free(internalDstBuffer);
free(resSizes);
if(allocationincomplete) {
- EXM_THROW(31, BMK_return_t, "allocation error : not enough memory");
+ RETURN_ERROR(31, BMK_benchOutcome_t, "allocation error : not enough memory");
}
- if(parametersConflict) {
- EXM_THROW(32, BMK_return_t, "Conflicting input results");
+ if(dstParamsError) {
+ RETURN_ERROR(32, BMK_benchOutcome_t, "Dst parameters not coherent");
}
- return results;
+ return outcome;
}
-BMK_return_t BMK_benchMem(const void* srcBuffer, size_t srcSize,
+BMK_benchOutcome_t BMK_benchMem(const void* srcBuffer, size_t srcSize,
const size_t* fileSizes, unsigned nbFiles,
- const int cLevel, const ZSTD_compressionParameters* comprParams,
+ int cLevel, const ZSTD_compressionParameters* comprParams,
const void* dictBuffer, size_t dictBufferSize,
int displayLevel, const char* displayName) {
- const BMK_advancedParams_t adv = BMK_initAdvancedParams();
+ BMK_advancedParams_t const adv = BMK_initAdvancedParams();
return BMK_benchMemAdvanced(srcBuffer, srcSize,
NULL, 0,
fileSizes, nbFiles,
displayLevel, displayName, &adv);
}
-static size_t BMK_findMaxMem(U64 requiredMem)
-{
- size_t const step = 64 MB;
- BYTE* testmem = NULL;
-
- requiredMem = (((requiredMem >> 26) + 1) << 26);
- requiredMem += step;
- if (requiredMem > maxMemory) requiredMem = maxMemory;
-
- do {
- testmem = (BYTE*)malloc((size_t)requiredMem);
- requiredMem -= step;
- } while (!testmem && requiredMem > 0);
-
- free(testmem);
- return (size_t)(requiredMem);
-}
-
-static BMK_return_t BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
+static BMK_benchOutcome_t BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
const size_t* fileSizes, unsigned nbFiles,
- const int cLevel, const ZSTD_compressionParameters* comprParams,
+ int cLevel, const ZSTD_compressionParameters* comprParams,
const void* dictBuffer, size_t dictBufferSize,
int displayLevel, const char* displayName,
BMK_advancedParams_t const * const adv)
{
- BMK_return_t res;
-
const char* pch = strrchr(displayName, '\\'); /* Windows */
-
- if (!pch) pch = strrchr(displayName, '/'); /* Linux */
+ if (!pch) pch = strrchr(displayName, '/'); /* Linux */
if (pch) displayName = pch+1;
if (adv->realTime) {
SET_REALTIME_PRIORITY;
}
- if (displayLevel == 1 && !adv->additionalParam)
- DISPLAY("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n", ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING, (U32)benchedSize, adv->nbSeconds, (U32)(adv->blockSize>>10));
+ if (displayLevel == 1 && !adv->additionalParam) /* --quiet mode */
+ DISPLAY("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n",
+ ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING,
+ (U32)benchedSize, adv->nbSeconds, (U32)(adv->blockSize>>10));
- res = BMK_benchMemAdvanced(srcBuffer, benchedSize,
- NULL, 0,
- fileSizes, nbFiles,
- cLevel, comprParams,
- dictBuffer, dictBufferSize,
- displayLevel, displayName, adv);
+ return BMK_benchMemAdvanced(srcBuffer, benchedSize,
+ NULL, 0,
+ fileSizes, nbFiles,
+ cLevel, comprParams,
+ dictBuffer, dictBufferSize,
+ displayLevel, displayName, adv);
+}
+
+BMK_benchOutcome_t BMK_syntheticTest(int cLevel, double compressibility,
+ const ZSTD_compressionParameters* compressionParams,
+ int displayLevel, const BMK_advancedParams_t* adv)
+{
+ char name[20] = {0};
+ size_t const benchedSize = 10000000;
+ void* srcBuffer;
+ BMK_benchOutcome_t res;
+
+ if (cLevel > ZSTD_maxCLevel()) {
+ RETURN_ERROR(15, BMK_benchOutcome_t, "Invalid Compression Level");
+ }
+
+ /* Memory allocation */
+ srcBuffer = malloc(benchedSize);
+ if (!srcBuffer) RETURN_ERROR(21, BMK_benchOutcome_t, "not enough memory");
+
+ /* Fill input buffer */
+ RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0);
+
+ /* Bench */
+ snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100));
+ res = BMK_benchCLevel(srcBuffer, benchedSize,
+ &benchedSize /* ? */, 1 /* ? */,
+ cLevel, compressionParams,
+ NULL, 0, /* dictionary */
+ displayLevel, name, adv);
+
+ /* clean up */
+ free(srcBuffer);
return res;
}
+
+static size_t BMK_findMaxMem(U64 requiredMem)
+{
+ size_t const step = 64 MB;
+ BYTE* testmem = NULL;
+
+ requiredMem = (((requiredMem >> 26) + 1) << 26);
+ requiredMem += step;
+ if (requiredMem > maxMemory) requiredMem = maxMemory;
+
+ do {
+ testmem = (BYTE*)malloc((size_t)requiredMem);
+ requiredMem -= step;
+ } while (!testmem && requiredMem > 0);
+
+ free(testmem);
+ return (size_t)(requiredMem);
+}
+
/*! BMK_loadFiles() :
* Loads `buffer` with content of files listed within `fileNamesTable`.
* At most, fills `buffer` entirely. */
return 0;
}
-BMK_return_t BMK_benchFilesAdvanced(const char* const * const fileNamesTable, unsigned const nbFiles,
- const char* const dictFileName, int const cLevel,
- const ZSTD_compressionParameters* const compressionParams,
- int displayLevel, const BMK_advancedParams_t * const adv)
+BMK_benchOutcome_t BMK_benchFilesAdvanced(
+ const char* const * fileNamesTable, unsigned nbFiles,
+ const char* dictFileName, int cLevel,
+ const ZSTD_compressionParameters* compressionParams,
+ int displayLevel, const BMK_advancedParams_t* adv)
{
void* srcBuffer = NULL;
size_t benchedSize;
void* dictBuffer = NULL;
size_t dictBufferSize = 0;
size_t* fileSizes = NULL;
- BMK_return_t res;
+ BMK_benchOutcome_t res = BMK_benchOutcome_error(); /* error by default */
U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
- if(!nbFiles) {
- EXM_THROW(14, BMK_return_t, "No Files to Benchmark");
+ if (!nbFiles) {
+ RETURN_ERROR(14, BMK_benchOutcome_t, "No Files to Benchmark");
}
if (cLevel > ZSTD_maxCLevel()) {
- EXM_THROW(15, BMK_return_t, "Invalid Compression Level");
+ RETURN_ERROR(15, BMK_benchOutcome_t, "Invalid Compression Level");
}
fileSizes = (size_t*)calloc(nbFiles, sizeof(size_t));
- if (!fileSizes) EXM_THROW(12, BMK_return_t, "not enough memory for fileSizes");
+ if (!fileSizes) RETURN_ERROR(12, BMK_benchOutcome_t, "not enough memory for fileSizes");
+
/* Load dictionary */
if (dictFileName != NULL) {
U64 const dictFileSize = UTIL_getFileSize(dictFileName);
if (dictFileSize > 64 MB) {
free(fileSizes);
- EXM_THROW(10, BMK_return_t, "dictionary file %s too large", dictFileName);
+ RETURN_ERROR(10, BMK_benchOutcome_t, "dictionary file %s too large", dictFileName);
}
dictBufferSize = (size_t)dictFileSize;
dictBuffer = malloc(dictBufferSize);
if (dictBuffer==NULL) {
free(fileSizes);
- EXM_THROW(11, BMK_return_t, "not enough memory for dictionary (%u bytes)",
+ RETURN_ERROR(11, BMK_benchOutcome_t, "not enough memory for dictionary (%u bytes)",
(U32)dictBufferSize);
}
- {
- int errorCode = BMK_loadFiles(dictBuffer, dictBufferSize, fileSizes, &dictFileName, 1, displayLevel);
- if(errorCode) {
- res.error = errorCode;
+
+ { int const errorCode = BMK_loadFiles(dictBuffer, dictBufferSize,
+ fileSizes, &dictFileName /*?*/,
+ 1 /*?*/, displayLevel);
+ if (errorCode) {
+ res = BMK_benchOutcome_error();
goto _cleanUp;
- }
- }
+ } }
}
/* Memory allocation & restrictions */
if (!srcBuffer) {
free(dictBuffer);
free(fileSizes);
- EXM_THROW(12, BMK_return_t, "not enough memory");
+ RETURN_ERROR(12, BMK_benchOutcome_t, "not enough memory");
}
/* Load input buffer */
- {
- int errorCode = BMK_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles, displayLevel);
- if(errorCode) {
- res.error = errorCode;
+ { int const errorCode = BMK_loadFiles(srcBuffer, benchedSize,
+ fileSizes, fileNamesTable, nbFiles,
+ displayLevel);
+ if (errorCode) {
+ res = BMK_benchOutcome_error();
goto _cleanUp;
- }
- }
+ } }
+
/* Bench */
- {
- char mfName[20] = {0};
+ { char mfName[20] = {0};
snprintf (mfName, sizeof(mfName), " %u files", nbFiles);
- {
- const char* const displayName = (nbFiles > 1) ? mfName : fileNamesTable[0];
+ { const char* const displayName = (nbFiles > 1) ? mfName : fileNamesTable[0];
res = BMK_benchCLevel(srcBuffer, benchedSize,
- fileSizes, nbFiles,
- cLevel, compressionParams,
- dictBuffer, dictBufferSize,
- displayLevel, displayName,
- adv);
+ fileSizes, nbFiles,
+ cLevel, compressionParams,
+ dictBuffer, dictBufferSize,
+ displayLevel, displayName,
+ adv);
} }
_cleanUp:
}
-BMK_return_t BMK_syntheticTest(int cLevel, double compressibility,
- const ZSTD_compressionParameters* compressionParams,
- int displayLevel, const BMK_advancedParams_t * const adv)
+BMK_benchOutcome_t BMK_benchFiles(
+ const char* const * fileNamesTable, unsigned nbFiles,
+ const char* dictFileName,
+ int cLevel, const ZSTD_compressionParameters* compressionParams,
+ int displayLevel)
{
- char name[20] = {0};
- size_t benchedSize = 10000000;
- void* srcBuffer;
- BMK_return_t res;
-
- if (cLevel > ZSTD_maxCLevel()) {
- EXM_THROW(15, BMK_return_t, "Invalid Compression Level");
- }
-
- /* Memory allocation */
- srcBuffer = malloc(benchedSize);
- if (!srcBuffer) EXM_THROW(21, BMK_return_t, "not enough memory");
-
- /* Fill input buffer */
- RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0);
-
- /* Bench */
- snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100));
- res = BMK_benchCLevel(srcBuffer, benchedSize,
- &benchedSize, 1,
- cLevel, compressionParams,
- NULL, 0,
- displayLevel, name, adv);
-
- /* clean up */
- free(srcBuffer);
-
- return res;
-}
-
-BMK_return_t BMK_benchFiles(const char* const * const fileNamesTable, unsigned const nbFiles,
- const char* const dictFileName,
- int const cLevel, const ZSTD_compressionParameters* const compressionParams,
- int displayLevel) {
- const BMK_advancedParams_t adv = BMK_initAdvancedParams();
+ BMK_advancedParams_t const adv = BMK_initAdvancedParams();
return BMK_benchFilesAdvanced(fileNamesTable, nbFiles, dictFileName, cLevel, compressionParams, displayLevel, &adv);
}
* will either be successful, with .error = 0, providing a valid .result,
* or return an error, with .error != 0, in which case .result is invalid.
*/
-#define ERROR_STRUCT(baseType, typeName) typedef struct { \
- baseType result; \
- int error; \
-} typeName
+#define SUMTYPE_ERROR_RESULT(baseType, variantName) \
+ \
+typedef struct { \
+ baseType internal_never_use_directly; \
+ int tag; \
+} variantName
+
typedef struct {
size_t cSize;
unsigned long long cSpeed; /* bytes / sec */
unsigned long long dSpeed;
- size_t cMem; /* ? what does it reports ? */
-} BMK_result_t;
+ size_t cMem; /* ? what is reported ? */
+} BMK_benchResult_t;
+
+SUMTYPE_ERROR_RESULT(BMK_benchResult_t, BMK_benchOutcome_t);
+
+/* check first if the return structure represents an error or a valid result */
+int BMK_isSuccessful_benchOutcome(BMK_benchOutcome_t errorOrResult);
+
+/* extract result from variant type.
+ * note : this function will abort() program execution if result is not valid
+ * check result validity first, by using BMK_isValid_benchResult()
+ */
+BMK_benchResult_t BMK_extract_benchResult(BMK_benchOutcome_t errorOrResult);
-ERROR_STRUCT(BMK_result_t, BMK_return_t);
/*! BMK_benchFiles() -- called by zstdcli */
/* Loads files from fileNamesTable into memory,
* .result will return compression speed (.cSpeed),
* decompression speed (.dSpeed), and compressed size (.cSize).
*/
-BMK_return_t BMK_benchFiles(const char* const * fileNamesTable, unsigned nbFiles,
+BMK_benchOutcome_t BMK_benchFiles(
+ const char* const * fileNamesTable, unsigned nbFiles,
const char* dictFileName,
int cLevel, const ZSTD_compressionParameters* compressionParams,
int displayLevel);
-typedef enum {
- BMK_timeMode = 0,
- BMK_iterMode = 1
-} BMK_loopMode_t;
typedef enum {
BMK_both = 0,
typedef struct {
BMK_mode_t mode; /* 0: all, 1: compress only 2: decode only */
- BMK_loopMode_t loopMode; /* if loopmode, then nbSeconds = nbLoops */
unsigned nbSeconds; /* default timing is in nbSeconds */
size_t blockSize; /* Maximum allowable size of a block*/
unsigned nbWorkers; /* multithreading */
/*! BMK_benchFilesAdvanced():
* Same as BMK_benchFiles(),
* with more controls, provided through advancedParams_t structure */
-BMK_return_t BMK_benchFilesAdvanced(const char* const * fileNamesTable, unsigned nbFiles,
+BMK_benchOutcome_t BMK_benchFilesAdvanced(
+ const char* const * fileNamesTable, unsigned nbFiles,
const char* dictFileName,
int cLevel, const ZSTD_compressionParameters* compressionParams,
int displayLevel, const BMK_advancedParams_t* adv);
* .result will return the compression speed (.cSpeed),
* decompression speed (.dSpeed), and compressed size (.cSize).
*/
-BMK_return_t BMK_syntheticTest(int cLevel, double compressibility,
+BMK_benchOutcome_t BMK_syntheticTest(
+ int cLevel, double compressibility,
const ZSTD_compressionParameters* compressionParams,
int displayLevel, const BMK_advancedParams_t * const adv);
+
+
+/* === Benchmark Zstandard in a memory-to-memory scenario === */
+
/** BMK_benchMem() -- core benchmarking function, called in paramgrill
* applies ZSTD_compress_generic() and ZSTD_decompress_generic() on data in srcBuffer
* with specific compression parameters provided by other arguments using benchFunction
* provide the same results as benchFiles()
* but for the data stored in srcBuffer
*/
-BMK_return_t BMK_benchMem(const void* srcBuffer, size_t srcSize,
+BMK_benchOutcome_t BMK_benchMem(const void* srcBuffer, size_t srcSize,
const size_t* fileSizes, unsigned nbFiles,
int cLevel, const ZSTD_compressionParameters* comprParams,
const void* dictBuffer, size_t dictBufferSize,
* dstCapacity - capacity of destination buffer, give 0 if dstBuffer = NULL
* adv = see advancedParams_t
*/
-BMK_return_t BMK_benchMemAdvanced(const void* srcBuffer, size_t srcSize,
+BMK_benchOutcome_t BMK_benchMemAdvanced(const void* srcBuffer, size_t srcSize,
void* dstBuffer, size_t dstCapacity,
const size_t* fileSizes, unsigned nbFiles,
int cLevel, const ZSTD_compressionParameters* comprParams,
int displayLevel, const char* displayName,
const BMK_advancedParams_t* adv);
+
+
+/* ==== Benchmarking any function, iterated on a set of blocks ==== */
+
typedef struct {
- size_t sumOfReturn; /* sum of return values */
- unsigned long long nanoSecPerRun; /* time per iteration */
-} BMK_customResult_t;
+ unsigned long long nanoSecPerRun; /* time per iteration */
+ size_t sumOfReturn; /* sum of return values */
+} BMK_runTime_t;
+
+SUMTYPE_ERROR_RESULT(BMK_runTime_t, BMK_runOutcome_t);
-ERROR_STRUCT(BMK_customResult_t, BMK_customReturn_t);
+/* check first if the return structure represents an error or a valid result */
+int BMK_isSuccessful_runOutcome(BMK_runOutcome_t outcome);
+
+/* extract result from variant type.
+ * note : this function will abort() program execution if result is not valid
+ * check result validity first, by using BMK_isSuccessful_runOutcome()
+ */
+BMK_runTime_t BMK_extract_runTime(BMK_runOutcome_t outcome);
+
+
+typedef size_t (*BMK_benchFn_t)(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* customPayload);
+typedef size_t (*BMK_initFn_t)(void* initPayload);
-typedef size_t (*BMK_benchFn_t)(const void*, size_t, void*, size_t, void*);
-typedef size_t (*BMK_initFn_t)(void*);
-/* This function times the execution of 2 argument functions, benchFn and initFn */
+/* BMK_benchFunction() :
+ * This function times the execution of 2 argument functions, benchFn and initFn */
/* benchFn - (*benchFn)(srcBuffers[i], srcSizes[i], dstBuffers[i], dstCapacities[i], benchPayload)
* is run nbLoops times
- * initFn - (*initFn)(initPayload) is run once per benchmark at the beginning. This argument can
- * be NULL, in which case nothing is run.
+ * initFn - (*initFn)(initPayload) is run once per benchmark, at the beginning.
+ * This argument can be NULL, in which case nothing is run.
* blockCount - number of blocks. Size of all array parameters : srcBuffers, srcSizes, dstBuffers, dstCapacities, blockResults
* srcBuffers - an array of buffers to be operated on by benchFn
* srcSizes - an array of the sizes of above buffers
* dstBuffers - an array of buffers to be written into by benchFn
* dstCapacities - an array of the capacities of above buffers
- * blockResults - the return value of benchFn called on each block.
+ * blockResults - store the return value of benchFn for each block. Optional. Use NULL if this result is not requested.
* nbLoops - defines number of times benchFn is run.
- * @return:
- * .error will give a nonzero value if ZSTD_isError() is nonzero for any of the return
- * of the calls to initFn and benchFn, or if benchFunction errors internally
- * .result - if .error = 0, then .result will contain
- * the sum of all return values of benchFn on the first iteration through all of the blocks (.sumOfReturn)
- * and also the time per run of benchFn (.nanoSecPerRun).
- * For the former, this is generally intended to be used on functions which return the # of bytes written into dstBuffer,
- * hence this value will be the total amount of bytes written into dstBuffer.
+ * @return: a variant, which can be an error, or a BMK_runTime_t result.
+ * Use BMK_isSuccessful_runOutcome() to check if function was successful.
+ * If yes, extract the result with BMK_extract_runTime(),
+ * it will contain :
+ * .sumOfReturn : the sum of all return values of benchFn through all of blocks
+ * .nanoSecPerRun : time per run of benchFn + (time for initFn / nbLoops)
+ * .sumOfReturn is generally intended for functions which return a # of bytes written into dstBuffer,
+ * in which case, this value will be the total amount of bytes written into dstBuffer.
*/
-BMK_customReturn_t BMK_benchFunction(BMK_benchFn_t benchFn, void* benchPayload,
+BMK_runOutcome_t BMK_benchFunction(
+ BMK_benchFn_t benchFn, void* benchPayload,
BMK_initFn_t initFn, void* initPayload,
size_t blockCount,
const void *const * srcBuffers, const size_t* srcSizes,
- void *const * dstBuffers, const size_t* dstCapacities, size_t* blockResults,
+ void *const * dstBuffers, const size_t* dstCapacities,
+ size_t* blockResults,
unsigned nbLoops);
-/* state information needed to advance computation for benchFunctionTimed */
-typedef struct BMK_timeState_t BMK_timedFnState_t;
-/* initializes timeState object with desired number of seconds */
+
+/* ==== Benchmarking any function, providing intermediate results ==== */
+
+/* state information needed by benchFunctionTimed */
+typedef struct BMK_timedFnState_s BMK_timedFnState_t;
+
BMK_timedFnState_t* BMK_createTimedFnState(unsigned nbSeconds);
-/* resets existing timeState object */
-void BMK_resetTimedFnState(BMK_timedFnState_t*, unsigned nbSeconds);
-/* deletes timeState object */
+void BMK_resetTimedFnState(BMK_timedFnState_t* timedFnState, unsigned nbSeconds);
void BMK_freeTimedFnState(BMK_timedFnState_t* state);
-typedef struct {
- BMK_customReturn_t result;
- int completed;
-} BMK_customTimedReturn_t;
+/* define timedFnOutcome */
+SUMTYPE_ERROR_RESULT(BMK_runTime_t, BMK_timedFnOutcome_t);
+
+/* check first if the return structure represents an error or a valid result */
+int BMK_isSuccessful_timedFnOutcome(BMK_timedFnOutcome_t outcome);
+
+/* extract intermediate results from variant type.
+ * note : this function will abort() program execution if result is not valid.
+ * check result validity first, by using BMK_isSuccessful_timedFnOutcome() */
+BMK_runTime_t BMK_extract_timedFnResult(BMK_timedFnOutcome_t outcome);
+
+/* Tells if nb of seconds set in timedFnState for all runs is spent.
+ * note : this function will return 1 if BMK_benchFunctionTimed() has actually errored. */
+int BMK_isCompleted_timedFnOutcome(BMK_timedFnOutcome_t outcome);
+
/* BMK_benchFunctionTimed() :
- * Same as BMK_benchFunction(), but runs for nbSeconds seconds rather than a fixed number of loops.
- * Arguments are mostly the same other as BMK_benchFunction()
- * Usage - benchFunctionTimed will return in approximately one second.
- * Keep calling BMK_benchFunctionTimed() until @return.completed == 1,
- * to continue updating intermediate result.
- * Intermediate return values are returned by the function.
+ * Similar to BMK_benchFunction(),
+ * tries to find automatically `nbLoops`, so that each run lasts approximately 1 second.
+ * Note : minimum `nbLoops` is 1, a run may last more than 1 second if benchFn is slow.
+ * Most arguments are the same as BMK_benchFunction()
+ * Usage - initialize a timedFnState, selecting a total nbSeconds allocated for _all_ benchmarks run
+ * call BMK_benchFunctionTimed() repetitively, collecting intermediate results (each run is supposed to last about 1 seconds)
+ * Check if time budget is spent using BMK_isCompleted_timedFnOutcome()
*/
-BMK_customTimedReturn_t BMK_benchFunctionTimed(BMK_timedFnState_t* cont,
- BMK_benchFn_t benchFn, void* benchPayload,
- BMK_initFn_t initFn, void* initPayload,
- size_t blockCount,
- const void *const * srcBlockBuffers, const size_t* srcBlockSizes,
- void *const * dstBlockBuffers, const size_t* dstBlockCapacities, size_t* blockResults);
+BMK_timedFnOutcome_t BMK_benchFunctionTimed(
+ BMK_timedFnState_t* timedFnState,
+ BMK_benchFn_t benchFn, void* benchPayload,
+ BMK_initFn_t initFn, void* initPayload,
+ size_t blockCount,
+ const void *const * srcBlockBuffers, const size_t* srcBlockSizes,
+ void *const * dstBlockBuffers, const size_t* dstBlockCapacities,
+ size_t* blockResults);
#endif /* BENCH_H_121279284357 */