mirror of
				https://github.com/facebook/zstd.git
				synced 2025-11-03 20:33:11 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			1271 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1271 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * This source code is licensed under both the BSD-style license (found in the
 | 
						|
 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
 | 
						|
 * in the COPYING file in the root directory of this source tree).
 | 
						|
 * You may select, at your option, one of the above-listed licenses.
 | 
						|
 */
 | 
						|
 | 
						|
/* **************************************
 | 
						|
 *  Tuning parameters
 | 
						|
 ****************************************/
 | 
						|
#ifndef BMK_TIMETEST_DEFAULT_S /* default minimum time per test */
 | 
						|
#    define BMK_TIMETEST_DEFAULT_S 3
 | 
						|
#endif
 | 
						|
 | 
						|
/* *************************************
 | 
						|
 *  Includes
 | 
						|
 ***************************************/
 | 
						|
/* this must be included first */
 | 
						|
#include "platform.h" /* Large Files support, compiler specifics */
 | 
						|
 | 
						|
/* then following system includes */
 | 
						|
#include <assert.h> /* assert */
 | 
						|
#include <errno.h>
 | 
						|
#include <stdio.h>    /* fprintf, fopen */
 | 
						|
#include <stdlib.h>   /* malloc, free */
 | 
						|
#include <string.h>   /* memset, strerror */
 | 
						|
#include "util.h"     /* UTIL_getFileSize, UTIL_sleep */
 | 
						|
#include "../lib/common/mem.h"
 | 
						|
#include "benchfn.h"
 | 
						|
#include "timefn.h" /* UTIL_time_t */
 | 
						|
#ifndef ZSTD_STATIC_LINKING_ONLY
 | 
						|
#    define ZSTD_STATIC_LINKING_ONLY
 | 
						|
#endif
 | 
						|
#include "../lib/zstd.h"
 | 
						|
#include "datagen.h" /* RDG_genBuffer */
 | 
						|
#include "lorem.h"   /* LOREM_genBuffer */
 | 
						|
#ifndef XXH_INLINE_ALL
 | 
						|
#    define XXH_INLINE_ALL
 | 
						|
#endif
 | 
						|
#include "../lib/common/xxhash.h"
 | 
						|
#include "../lib/zstd_errors.h"
 | 
						|
#include "benchzstd.h"
 | 
						|
 | 
						|
/* *************************************
 | 
						|
 *  Constants
 | 
						|
 ***************************************/
 | 
						|
#ifndef ZSTD_GIT_COMMIT
 | 
						|
#    define ZSTD_GIT_COMMIT_STRING ""
 | 
						|
#else
 | 
						|
#    define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT)
 | 
						|
#endif
 | 
						|
 | 
						|
#define TIMELOOP_MICROSEC (1 * 1000000ULL)             /* 1 second */
 | 
						|
#define TIMELOOP_NANOSEC (1 * 1000000000ULL)           /* 1 second */
 | 
						|
#define ACTIVEPERIOD_MICROSEC (70 * TIMELOOP_MICROSEC) /* 70 seconds */
 | 
						|
#define COOLPERIOD_SEC 10
 | 
						|
 | 
						|
#define KB *(1 << 10)
 | 
						|
#define MB *(1 << 20)
 | 
						|
#define GB *(1U << 30)
 | 
						|
 | 
						|
#define BMK_RUNTEST_DEFAULT_MS 1000
 | 
						|
 | 
						|
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
 | 
						|
 ***************************************/
 | 
						|
#define DISPLAY(...)                  \
 | 
						|
    {                                 \
 | 
						|
        fprintf(stderr, __VA_ARGS__); \
 | 
						|
        fflush(NULL);                 \
 | 
						|
    }
 | 
						|
#define DISPLAYLEVEL(l, ...)  \
 | 
						|
    if (displayLevel >= l) {  \
 | 
						|
        DISPLAY(__VA_ARGS__); \
 | 
						|
    }
 | 
						|
/* 0 : no display;   1: errors;   2 : + result + interaction + warnings;   3 : +
 | 
						|
 * progression;   4 : + information */
 | 
						|
#define OUTPUT(...)                   \
 | 
						|
    {                                 \
 | 
						|
        fprintf(stdout, __VA_ARGS__); \
 | 
						|
        fflush(NULL);                 \
 | 
						|
    }
 | 
						|
#define OUTPUTLEVEL(l, ...)  \
 | 
						|
    if (displayLevel >= l) { \
 | 
						|
        OUTPUT(__VA_ARGS__); \
 | 
						|
    }
 | 
						|
 | 
						|
/* *************************************
 | 
						|
 *  Exceptions
 | 
						|
 ***************************************/
 | 
						|
#ifndef DEBUG
 | 
						|
#    define DEBUG 0
 | 
						|
#endif
 | 
						|
#define DEBUGOUTPUT(...)          \
 | 
						|
    {                             \
 | 
						|
        if (DEBUG)                \
 | 
						|
            DISPLAY(__VA_ARGS__); \
 | 
						|
    }
 | 
						|
 | 
						|
#define RETURN_ERROR_INT(errorNum, ...)                \
 | 
						|
    {                                                  \
 | 
						|
        DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
 | 
						|
        DISPLAYLEVEL(1, "Error %i : ", errorNum);      \
 | 
						|
        DISPLAYLEVEL(1, __VA_ARGS__);                  \
 | 
						|
        DISPLAYLEVEL(1, " \n");                        \
 | 
						|
        return errorNum;                               \
 | 
						|
    }
 | 
						|
 | 
						|
#define CHECK_Z(zf)                                                  \
 | 
						|
    {                                                                \
 | 
						|
        size_t const zerr = zf;                                      \
 | 
						|
        if (ZSTD_isError(zerr)) {                                    \
 | 
						|
            DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__);           \
 | 
						|
            DISPLAY("Error : ");                                     \
 | 
						|
            DISPLAY("%s failed : %s", #zf, ZSTD_getErrorName(zerr)); \
 | 
						|
            DISPLAY(" \n");                                          \
 | 
						|
            exit(1);                                                 \
 | 
						|
        }                                                            \
 | 
						|
    }
 | 
						|
 | 
						|
#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.tag = errorNum;                              \
 | 
						|
        return r;                                      \
 | 
						|
    }
 | 
						|
 | 
						|
static size_t uintSize(unsigned value)
 | 
						|
{
 | 
						|
    size_t size = 1;
 | 
						|
    while (value >= 10) {
 | 
						|
        size++;
 | 
						|
        value /= 10;
 | 
						|
    }
 | 
						|
    return size;
 | 
						|
}
 | 
						|
 | 
						|
/* Note: presume @buffer is large enough */
 | 
						|
static void writeUint_varLen(char* buffer, size_t capacity, unsigned value)
 | 
						|
{
 | 
						|
    int endPos = (int)uintSize(value) - 1;
 | 
						|
    assert(uintSize(value) >= 1);
 | 
						|
    assert(uintSize(value) < capacity); (void)capacity;
 | 
						|
    while (endPos >= 0) {
 | 
						|
        char c = '0' + (char)(value % 10);
 | 
						|
        buffer[endPos--] = c;
 | 
						|
        value /= 10;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* replacement for snprintf(), which is not supported by C89.
 | 
						|
 * sprintf() would be the supported one, but it's labelled unsafe:
 | 
						|
 * modern static analyzer will flag sprintf() as dangerous, making it unusable.
 | 
						|
 * formatString_u() replaces snprintf() for the specific case where there is only one %u argument */
 | 
						|
static int formatString_u(char* buffer, size_t buffer_size, const char* formatString, unsigned int value)
 | 
						|
{
 | 
						|
    size_t const valueSize = uintSize(value);
 | 
						|
    size_t written = 0;
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 0; formatString[i] != '\0' && written < buffer_size - 1; i++) {
 | 
						|
        if (formatString[i] != '%') {
 | 
						|
            buffer[written++] = formatString[i];
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        i++;
 | 
						|
        if (formatString[i] == 'u') {
 | 
						|
            if (written + valueSize >= buffer_size) abort(); /* buffer not large enough */
 | 
						|
            writeUint_varLen(buffer + written, buffer_size - written, value);
 | 
						|
            written += valueSize;
 | 
						|
        } else if (formatString[i] == '%') { /* Check for escaped percent sign */
 | 
						|
            buffer[written++] = '%';
 | 
						|
        } else {
 | 
						|
            abort(); /* unsupported format */
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (written < buffer_size) {
 | 
						|
        buffer[written] = '\0';
 | 
						|
    } else {
 | 
						|
        abort(); /* buffer not large enough */
 | 
						|
    }
 | 
						|
 | 
						|
    return (int)written;
 | 
						|
}
 | 
						|
 | 
						|
/* *************************************
 | 
						|
 *  Benchmark Parameters
 | 
						|
 ***************************************/
 | 
						|
 | 
						|
BMK_advancedParams_t BMK_initAdvancedParams(void)
 | 
						|
{
 | 
						|
    BMK_advancedParams_t const res = {
 | 
						|
        BMK_both,               /* mode */
 | 
						|
        BMK_TIMETEST_DEFAULT_S, /* nbSeconds */
 | 
						|
        0,                      /* chunkSizeMax */
 | 
						|
        0,               /* targetCBlockSize */
 | 
						|
        0,                      /* nbWorkers */
 | 
						|
        0,                      /* realTime */
 | 
						|
        0,                      /* additionalParam */
 | 
						|
        0,                      /* ldmFlag */
 | 
						|
        0,                      /* ldmMinMatch */
 | 
						|
        0,                      /* ldmHashLog */
 | 
						|
        0,                      /* ldmBuckSizeLog */
 | 
						|
        0,                      /* ldmHashRateLog */
 | 
						|
        ZSTD_ps_auto,           /* literalCompressionMode */
 | 
						|
        0                       /* useRowMatchFinder */
 | 
						|
    };
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
/* ********************************************************
 | 
						|
 *  Bench functions
 | 
						|
 **********************************************************/
 | 
						|
#undef MIN
 | 
						|
#undef MAX
 | 
						|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
 | 
						|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
 | 
						|
 | 
						|
static void BMK_initCCtx(
 | 
						|
        ZSTD_CCtx* ctx,
 | 
						|
        const void* dictBuffer,
 | 
						|
        size_t dictBufferSize,
 | 
						|
        int cLevel,
 | 
						|
        const ZSTD_compressionParameters* comprParams,
 | 
						|
        const BMK_advancedParams_t* adv)
 | 
						|
{
 | 
						|
    ZSTD_CCtx_reset(ctx, ZSTD_reset_session_and_parameters);
 | 
						|
    if (adv->nbWorkers == 1) {
 | 
						|
        CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, 0));
 | 
						|
    } else {
 | 
						|
        CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, adv->nbWorkers));
 | 
						|
    }
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, cLevel));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_useRowMatchFinder, adv->useRowMatchFinder));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_enableLongDistanceMatching, adv->ldmFlag));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmMinMatch, adv->ldmMinMatch));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmHashLog, adv->ldmHashLog));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_ldmBucketSizeLog, adv->ldmBucketSizeLog));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_ldmHashRateLog, adv->ldmHashRateLog));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_windowLog, (int)comprParams->windowLog));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_hashLog, (int)comprParams->hashLog));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_chainLog, (int)comprParams->chainLog));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_searchLog, (int)comprParams->searchLog));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_minMatch, (int)comprParams->minMatch));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_targetLength, (int)comprParams->targetLength));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx,
 | 
						|
            ZSTD_c_literalCompressionMode,
 | 
						|
            (int)adv->literalCompressionMode));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_strategy, (int)comprParams->strategy));
 | 
						|
    CHECK_Z(ZSTD_CCtx_setParameter(
 | 
						|
            ctx, ZSTD_c_targetCBlockSize, (int)adv->targetCBlockSize));
 | 
						|
    CHECK_Z(ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize));
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
BMK_initDCtx(ZSTD_DCtx* dctx, const void* dictBuffer, size_t dictBufferSize)
 | 
						|
{
 | 
						|
    CHECK_Z(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
 | 
						|
    CHECK_Z(ZSTD_DCtx_loadDictionary(dctx, dictBuffer, dictBufferSize));
 | 
						|
}
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    ZSTD_CCtx* cctx;
 | 
						|
    const void* dictBuffer;
 | 
						|
    size_t dictBufferSize;
 | 
						|
    int cLevel;
 | 
						|
    const ZSTD_compressionParameters* comprParams;
 | 
						|
    const BMK_advancedParams_t* adv;
 | 
						|
} BMK_initCCtxArgs;
 | 
						|
 | 
						|
static size_t local_initCCtx(void* payload)
 | 
						|
{
 | 
						|
    BMK_initCCtxArgs* ag = (BMK_initCCtxArgs*)payload;
 | 
						|
    BMK_initCCtx(
 | 
						|
            ag->cctx,
 | 
						|
            ag->dictBuffer,
 | 
						|
            ag->dictBufferSize,
 | 
						|
            ag->cLevel,
 | 
						|
            ag->comprParams,
 | 
						|
            ag->adv);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    ZSTD_DCtx* dctx;
 | 
						|
    const void* dictBuffer;
 | 
						|
    size_t dictBufferSize;
 | 
						|
} BMK_initDCtxArgs;
 | 
						|
 | 
						|
static size_t local_initDCtx(void* payload)
 | 
						|
{
 | 
						|
    BMK_initDCtxArgs* ag = (BMK_initDCtxArgs*)payload;
 | 
						|
    BMK_initDCtx(ag->dctx, ag->dictBuffer, ag->dictBufferSize);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* `addArgs` is the context */
 | 
						|
static size_t local_defaultCompress(
 | 
						|
        const void* srcBuffer,
 | 
						|
        size_t srcSize,
 | 
						|
        void* dstBuffer,
 | 
						|
        size_t dstSize,
 | 
						|
        void* addArgs)
 | 
						|
{
 | 
						|
    ZSTD_CCtx* const cctx = (ZSTD_CCtx*)addArgs;
 | 
						|
    return ZSTD_compress2(cctx, dstBuffer, dstSize, srcBuffer, srcSize);
 | 
						|
}
 | 
						|
 | 
						|
/* `addArgs` is the context */
 | 
						|
static size_t local_defaultDecompress(
 | 
						|
        const void* srcBuffer,
 | 
						|
        size_t srcSize,
 | 
						|
        void* dstBuffer,
 | 
						|
        size_t dstCapacity,
 | 
						|
        void* addArgs)
 | 
						|
{
 | 
						|
    size_t moreToFlush    = 1;
 | 
						|
    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 = dstCapacity;
 | 
						|
    out.pos  = 0;
 | 
						|
    while (moreToFlush) {
 | 
						|
        if (out.pos == out.size) {
 | 
						|
            return (size_t)-ZSTD_error_dstSize_tooSmall;
 | 
						|
        }
 | 
						|
        moreToFlush = ZSTD_decompressStream(dctx, &out, &in);
 | 
						|
        if (ZSTD_isError(moreToFlush)) {
 | 
						|
            return moreToFlush;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return out.pos;
 | 
						|
}
 | 
						|
 | 
						|
/* ================================================================= */
 | 
						|
/*      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(void)
 | 
						|
{
 | 
						|
    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_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 chunkSizeMax =
 | 
						|
            ((adv->chunkSizeMax >= 32 && (adv->mode != BMK_decodeOnly))
 | 
						|
                     ? adv->chunkSizeMax
 | 
						|
                     : srcSize)
 | 
						|
            + (!srcSize); /* avoid div by 0 */
 | 
						|
    BMK_benchResult_t benchResult;
 | 
						|
    size_t const loadedCompressedSize = srcSize;
 | 
						|
    size_t cSize                      = 0;
 | 
						|
    double ratio                      = 0.;
 | 
						|
    U32 nbChunks = 0;
 | 
						|
 | 
						|
    assert(cctx != NULL);
 | 
						|
    assert(dctx != NULL);
 | 
						|
 | 
						|
    /* init */
 | 
						|
    memset(&benchResult, 0, sizeof(benchResult));
 | 
						|
    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 == ZSTD_CONTENTSIZE_UNKNOWN) {
 | 
						|
                RETURN_ERROR(
 | 
						|
                        32,
 | 
						|
                        BMK_benchOutcome_t,
 | 
						|
                        "Decompressed size cannot be determined: cannot benchmark");
 | 
						|
            }
 | 
						|
            if (fSize64 == ZSTD_CONTENTSIZE_ERROR) {
 | 
						|
                RETURN_ERROR(
 | 
						|
                        32,
 | 
						|
                        BMK_benchOutcome_t,
 | 
						|
                        "Error while trying to assess decompressed size: data may be invalid");
 | 
						|
            }
 | 
						|
            totalDSize64 += fSize64;
 | 
						|
            srcPtr += fileSizes[fileNb];
 | 
						|
        }
 | 
						|
        {
 | 
						|
            size_t const decodedSize = (size_t)totalDSize64;
 | 
						|
            assert((U64)decodedSize == totalDSize64); /* check overflow */
 | 
						|
            free(*resultBufferPtr);
 | 
						|
            if (totalDSize64 > decodedSize) { /* size_t overflow */
 | 
						|
                RETURN_ERROR(
 | 
						|
                        32,
 | 
						|
                        BMK_benchOutcome_t,
 | 
						|
                        "decompressed size is too large for local system");
 | 
						|
            }
 | 
						|
            *resultBufferPtr = malloc(decodedSize);
 | 
						|
            if (!(*resultBufferPtr)) {
 | 
						|
                RETURN_ERROR(
 | 
						|
                        33,
 | 
						|
                        BMK_benchOutcome_t,
 | 
						|
                        "allocation error: not enough memory");
 | 
						|
            }
 | 
						|
            cSize   = srcSize;
 | 
						|
            srcSize = decodedSize;
 | 
						|
            ratio   = (double)srcSize / (double)cSize;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* Init data chunks  */
 | 
						|
    {
 | 
						|
        const char* srcPtr = (const char*)srcBuffer;
 | 
						|
        char* cPtr         = (char*)compressedBuffer;
 | 
						|
        char* resPtr       = (char*)(*resultBufferPtr);
 | 
						|
        U32 fileNb, chunkID;
 | 
						|
        for (chunkID = 0, fileNb = 0; fileNb < nbFiles; fileNb++) {
 | 
						|
            size_t remaining              = fileSizes[fileNb];
 | 
						|
            U32 const nbChunksforThisFile = (adv->mode == BMK_decodeOnly)
 | 
						|
                    ? 1
 | 
						|
                    : (U32)((remaining + (chunkSizeMax - 1)) / chunkSizeMax);
 | 
						|
            U32 const chunkIdEnd       = chunkID + nbChunksforThisFile;
 | 
						|
            for (; chunkID < chunkIdEnd; chunkID++) {
 | 
						|
                size_t const chunkSize = MIN(remaining, chunkSizeMax);
 | 
						|
                srcPtrs[chunkID]       = srcPtr;
 | 
						|
                srcSizes[chunkID]      = chunkSize;
 | 
						|
                cPtrs[chunkID]         = cPtr;
 | 
						|
                cCapacities[chunkID]   = (adv->mode == BMK_decodeOnly)
 | 
						|
                             ? chunkSize
 | 
						|
                             : ZSTD_compressBound(chunkSize);
 | 
						|
                resPtrs[chunkID]       = resPtr;
 | 
						|
                resSizes[chunkID]      = (adv->mode == BMK_decodeOnly)
 | 
						|
                                ? (size_t)ZSTD_findDecompressedSize(
 | 
						|
                                srcPtr, chunkSize)
 | 
						|
                                : chunkSize;
 | 
						|
                srcPtr += chunkSize;
 | 
						|
                cPtr += cCapacities[chunkID];
 | 
						|
                resPtr += chunkSize;
 | 
						|
                remaining -= chunkSize;
 | 
						|
                if (adv->mode == BMK_decodeOnly) {
 | 
						|
                    cSizes[chunkID]  = chunkSize;
 | 
						|
                    benchResult.cSize = chunkSize;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        nbChunks = chunkID;
 | 
						|
    }
 | 
						|
 | 
						|
    /* warming up `compressedBuffer` */
 | 
						|
    if (adv->mode == BMK_decodeOnly) {
 | 
						|
        memcpy(compressedBuffer, srcBuffer, loadedCompressedSize);
 | 
						|
    } else {
 | 
						|
        RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1);
 | 
						|
    }
 | 
						|
 | 
						|
    if (!UTIL_support_MT_measurements() && adv->nbWorkers > 1) {
 | 
						|
        OUTPUTLEVEL(
 | 
						|
                2,
 | 
						|
                "Warning : time measurements may be incorrect in multithreading mode... \n")
 | 
						|
    }
 | 
						|
 | 
						|
    /* Bench */
 | 
						|
    {
 | 
						|
        U64 const crcOrig = (adv->mode == BMK_decodeOnly)
 | 
						|
                ? 0
 | 
						|
                : XXH64(srcBuffer, srcSize, 0);
 | 
						|
#define NB_MARKS 4
 | 
						|
        const char* marks[NB_MARKS] = { " |", " /", " =", " \\" };
 | 
						|
        U32 markNb                  = 0;
 | 
						|
        int compressionCompleted    = (adv->mode == BMK_decodeOnly);
 | 
						|
        int decompressionCompleted  = (adv->mode == BMK_compressOnly);
 | 
						|
        BMK_benchParams_t cbp, dbp;
 | 
						|
        BMK_initCCtxArgs cctxprep;
 | 
						|
        BMK_initDCtxArgs dctxprep;
 | 
						|
 | 
						|
        cbp.benchFn       = local_defaultCompress; /* ZSTD_compress2 */
 | 
						|
        cbp.benchPayload  = cctx;
 | 
						|
        cbp.initFn        = local_initCCtx; /* BMK_initCCtx */
 | 
						|
        cbp.initPayload   = &cctxprep;
 | 
						|
        cbp.errorFn       = ZSTD_isError;
 | 
						|
        cbp.blockCount    = nbChunks;
 | 
						|
        cbp.srcBuffers    = srcPtrs;
 | 
						|
        cbp.srcSizes      = srcSizes;
 | 
						|
        cbp.dstBuffers    = cPtrs;
 | 
						|
        cbp.dstCapacities = cCapacities;
 | 
						|
        cbp.blockResults  = cSizes;
 | 
						|
 | 
						|
        cctxprep.cctx           = cctx;
 | 
						|
        cctxprep.dictBuffer     = dictBuffer;
 | 
						|
        cctxprep.dictBufferSize = dictBufferSize;
 | 
						|
        cctxprep.cLevel         = cLevel;
 | 
						|
        cctxprep.comprParams    = comprParams;
 | 
						|
        cctxprep.adv            = adv;
 | 
						|
 | 
						|
        dbp.benchFn       = local_defaultDecompress;
 | 
						|
        dbp.benchPayload  = dctx;
 | 
						|
        dbp.initFn        = local_initDCtx;
 | 
						|
        dbp.initPayload   = &dctxprep;
 | 
						|
        dbp.errorFn       = ZSTD_isError;
 | 
						|
        dbp.blockCount    = nbChunks;
 | 
						|
        dbp.srcBuffers    = (const void* const*)cPtrs;
 | 
						|
        dbp.srcSizes      = cSizes;
 | 
						|
        dbp.dstBuffers    = resPtrs;
 | 
						|
        dbp.dstCapacities = resSizes;
 | 
						|
        dbp.blockResults  = NULL;
 | 
						|
 | 
						|
        dctxprep.dctx           = dctx;
 | 
						|
        dctxprep.dictBuffer     = dictBuffer;
 | 
						|
        dctxprep.dictBufferSize = dictBufferSize;
 | 
						|
 | 
						|
        OUTPUTLEVEL(2, "\r%70s\r", ""); /* blank line */
 | 
						|
        assert(srcSize < UINT_MAX);
 | 
						|
        OUTPUTLEVEL(
 | 
						|
                2,
 | 
						|
                "%2s-%-17.17s :%10u -> \r",
 | 
						|
                marks[markNb],
 | 
						|
                displayName,
 | 
						|
                (unsigned)srcSize);
 | 
						|
 | 
						|
        while (!(compressionCompleted && decompressionCompleted)) {
 | 
						|
            if (!compressionCompleted) {
 | 
						|
                BMK_runOutcome_t const cOutcome =
 | 
						|
                        BMK_benchTimedFn(timeStateCompress, cbp);
 | 
						|
 | 
						|
                if (!BMK_isSuccessful_runOutcome(cOutcome)) {
 | 
						|
                    RETURN_ERROR(30, BMK_benchOutcome_t, "compression error");
 | 
						|
                }
 | 
						|
 | 
						|
                {
 | 
						|
                    BMK_runTime_t const cResult = BMK_extract_runTime(cOutcome);
 | 
						|
                    cSize                       = cResult.sumOfReturn;
 | 
						|
                    ratio = (double)srcSize / (double)cSize;
 | 
						|
                    {
 | 
						|
                        BMK_benchResult_t newResult;
 | 
						|
                        newResult.cSpeed =
 | 
						|
                                (U64)((double)srcSize * TIMELOOP_NANOSEC
 | 
						|
                                      / cResult.nanoSecPerRun);
 | 
						|
                        benchResult.cSize = cSize;
 | 
						|
                        if (newResult.cSpeed > benchResult.cSpeed)
 | 
						|
                            benchResult.cSpeed = newResult.cSpeed;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                {
 | 
						|
                    int const ratioDigits = 1 + (ratio < 100.) + (ratio < 10.);
 | 
						|
                    assert(cSize < UINT_MAX);
 | 
						|
                    OUTPUTLEVEL(
 | 
						|
                            2,
 | 
						|
                            "%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s \r",
 | 
						|
                            marks[markNb],
 | 
						|
                            displayName,
 | 
						|
                            (unsigned)srcSize,
 | 
						|
                            (unsigned)cSize,
 | 
						|
                            ratioDigits,
 | 
						|
                            ratio,
 | 
						|
                            benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1,
 | 
						|
                            (double)benchResult.cSpeed / MB_UNIT);
 | 
						|
                }
 | 
						|
                compressionCompleted =
 | 
						|
                        BMK_isCompleted_TimedFn(timeStateCompress);
 | 
						|
            }
 | 
						|
 | 
						|
            if (!decompressionCompleted) {
 | 
						|
                BMK_runOutcome_t const dOutcome =
 | 
						|
                        BMK_benchTimedFn(timeStateDecompress, dbp);
 | 
						|
 | 
						|
                if (!BMK_isSuccessful_runOutcome(dOutcome)) {
 | 
						|
                    RETURN_ERROR(30, BMK_benchOutcome_t, "decompression error");
 | 
						|
                }
 | 
						|
 | 
						|
                {
 | 
						|
                    BMK_runTime_t const dResult = BMK_extract_runTime(dOutcome);
 | 
						|
                    U64 const newDSpeed =
 | 
						|
                            (U64)((double)srcSize * TIMELOOP_NANOSEC
 | 
						|
                                  / dResult.nanoSecPerRun);
 | 
						|
                    if (newDSpeed > benchResult.dSpeed)
 | 
						|
                        benchResult.dSpeed = newDSpeed;
 | 
						|
                }
 | 
						|
 | 
						|
                {
 | 
						|
                    int const ratioDigits = 1 + (ratio < 100.) + (ratio < 10.);
 | 
						|
                    OUTPUTLEVEL(
 | 
						|
                            2,
 | 
						|
                            "%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s, %6.1f MB/s\r",
 | 
						|
                            marks[markNb],
 | 
						|
                            displayName,
 | 
						|
                            (unsigned)srcSize,
 | 
						|
                            (unsigned)cSize,
 | 
						|
                            ratioDigits,
 | 
						|
                            ratio,
 | 
						|
                            benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1,
 | 
						|
                            (double)benchResult.cSpeed / MB_UNIT,
 | 
						|
                            (double)benchResult.dSpeed / MB_UNIT);
 | 
						|
                }
 | 
						|
                decompressionCompleted =
 | 
						|
                        BMK_isCompleted_TimedFn(timeStateDecompress);
 | 
						|
            }
 | 
						|
            markNb = (markNb + 1) % NB_MARKS;
 | 
						|
        } /* while (!(compressionCompleted && decompressionCompleted)) */
 | 
						|
 | 
						|
        /* CRC Checking */
 | 
						|
        {   const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr);
 | 
						|
            U64 const crcCheck       = XXH64(resultBuffer, srcSize, 0);
 | 
						|
            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] != resultBuffer[u]) {
 | 
						|
                        unsigned segNb, bNb, pos;
 | 
						|
                        size_t bacc = 0;
 | 
						|
                        DISPLAY("Decoding error at pos %u ", (unsigned)u);
 | 
						|
                        for (segNb = 0; segNb < nbChunks; segNb++) {
 | 
						|
                            if (bacc + srcSizes[segNb] > u)
 | 
						|
                                break;
 | 
						|
                            bacc += srcSizes[segNb];
 | 
						|
                        }
 | 
						|
                        pos = (U32)(u - bacc);
 | 
						|
                        bNb = pos / (128 KB);
 | 
						|
                        DISPLAY("(sample %u, chunk %u, pos %u) \n",
 | 
						|
                                segNb,
 | 
						|
                                bNb,
 | 
						|
                                pos);
 | 
						|
                        {
 | 
						|
                            size_t const lowest = (u > 5) ? 5 : u;
 | 
						|
                            size_t n;
 | 
						|
                            DISPLAY("origin: ");
 | 
						|
                            for (n = lowest; n > 0; n--)
 | 
						|
                                DISPLAY("%02X ",
 | 
						|
                                        ((const BYTE*)srcBuffer)[u - n]);
 | 
						|
                            DISPLAY(" :%02X:  ", ((const BYTE*)srcBuffer)[u]);
 | 
						|
                            for (n = 1; n < 3; n++)
 | 
						|
                                DISPLAY("%02X ",
 | 
						|
                                        ((const BYTE*)srcBuffer)[u + n]);
 | 
						|
                            DISPLAY(" \n");
 | 
						|
                            DISPLAY("decode: ");
 | 
						|
                            for (n = lowest; 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;
 | 
						|
                    }
 | 
						|
                    if (u == srcSize - 1) { /* should never happen */
 | 
						|
                        DISPLAY("no difference detected\n");
 | 
						|
                    }
 | 
						|
                } /* for (u=0; u<srcSize; u++) */
 | 
						|
            }     /* if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) */
 | 
						|
        }         /* CRC Checking */
 | 
						|
 | 
						|
        if (displayLevel
 | 
						|
            == 1) { /* hidden display mode -q, used by python speed benchmark */
 | 
						|
            double const cSpeed = (double)benchResult.cSpeed / MB_UNIT;
 | 
						|
            double const dSpeed = (double)benchResult.dSpeed / MB_UNIT;
 | 
						|
            if (adv->additionalParam) {
 | 
						|
                OUTPUT("-%-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 {
 | 
						|
                OUTPUT("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s  %s\n",
 | 
						|
                       cLevel,
 | 
						|
                       (int)cSize,
 | 
						|
                       ratio,
 | 
						|
                       cSpeed,
 | 
						|
                       dSpeed,
 | 
						|
                       displayName);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        OUTPUTLEVEL(2, "%2i#\n", cLevel);
 | 
						|
    } /* Bench */
 | 
						|
 | 
						|
    benchResult.cMem =
 | 
						|
            (1ULL << (comprParams->windowLog)) + ZSTD_sizeof_CCtx(cctx);
 | 
						|
    return BMK_benchOutcome_setValidResult(benchResult);
 | 
						|
}
 | 
						|
 | 
						|
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,
 | 
						|
        const void* dictBuffer,
 | 
						|
        size_t dictBufferSize,
 | 
						|
        int displayLevel,
 | 
						|
        const char* displayName,
 | 
						|
        const BMK_advancedParams_t* adv)
 | 
						|
 | 
						|
{
 | 
						|
    int const dstParamsError =
 | 
						|
            !dstBuffer ^ !dstCapacity; /* must be both NULL or none */
 | 
						|
 | 
						|
    size_t const chunkSize =
 | 
						|
            ((adv->chunkSizeMax >= 32 && (adv->mode != BMK_decodeOnly))
 | 
						|
                     ? adv->chunkSizeMax
 | 
						|
                     : srcSize)
 | 
						|
            + (!srcSize) /* avoid div by 0 */;
 | 
						|
    U32 const nbChunksMax =
 | 
						|
            (U32)((srcSize + (chunkSize - 1)) / chunkSize) + nbFiles;
 | 
						|
 | 
						|
    const void** const srcPtrs =
 | 
						|
            (const void**)malloc(nbChunksMax * sizeof(void*));
 | 
						|
    size_t* const srcSizes = (size_t*)malloc(nbChunksMax * sizeof(size_t));
 | 
						|
 | 
						|
    void** const cPtrs        = (void**)malloc(nbChunksMax * sizeof(void*));
 | 
						|
    size_t* const cSizes      = (size_t*)malloc(nbChunksMax * sizeof(size_t));
 | 
						|
    size_t* const cCapacities = (size_t*)malloc(nbChunksMax * sizeof(size_t));
 | 
						|
 | 
						|
    void** const resPtrs   = (void**)malloc(nbChunksMax * sizeof(void*));
 | 
						|
    size_t* const resSizes = (size_t*)malloc(nbChunksMax * sizeof(size_t));
 | 
						|
 | 
						|
    BMK_timedFnState_t* timeStateCompress = BMK_createTimedFnState(
 | 
						|
            adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
 | 
						|
    BMK_timedFnState_t* timeStateDecompress = BMK_createTimedFnState(
 | 
						|
            adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
 | 
						|
 | 
						|
    ZSTD_CCtx* const cctx = ZSTD_createCCtx();
 | 
						|
    ZSTD_DCtx* const dctx = ZSTD_createDCtx();
 | 
						|
 | 
						|
    const size_t maxCompressedSize = dstCapacity
 | 
						|
            ? dstCapacity
 | 
						|
            : ZSTD_compressBound(srcSize) + (nbChunksMax * 1024);
 | 
						|
 | 
						|
    void* const internalDstBuffer =
 | 
						|
            dstBuffer ? NULL : malloc(maxCompressedSize);
 | 
						|
    void* const compressedBuffer = dstBuffer ? dstBuffer : internalDstBuffer;
 | 
						|
 | 
						|
    BMK_benchOutcome_t outcome =
 | 
						|
            BMK_benchOutcome_error(); /* error by default */
 | 
						|
 | 
						|
    void* resultBuffer = srcSize ? malloc(srcSize) : NULL;
 | 
						|
 | 
						|
    int const allocationincomplete = !srcPtrs || !srcSizes || !cPtrs || !cSizes
 | 
						|
            || !cCapacities || !resPtrs || !resSizes || !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(cctx);
 | 
						|
    ZSTD_freeDCtx(dctx);
 | 
						|
 | 
						|
    free(internalDstBuffer);
 | 
						|
    free(resultBuffer);
 | 
						|
 | 
						|
    free((void*)srcPtrs);
 | 
						|
    free(srcSizes);
 | 
						|
    free(cPtrs);
 | 
						|
    free(cSizes);
 | 
						|
    free(cCapacities);
 | 
						|
    free(resPtrs);
 | 
						|
    free(resSizes);
 | 
						|
 | 
						|
    if (allocationincomplete) {
 | 
						|
        RETURN_ERROR(
 | 
						|
                31, BMK_benchOutcome_t, "allocation error : not enough memory");
 | 
						|
    }
 | 
						|
 | 
						|
    if (dstParamsError) {
 | 
						|
        RETURN_ERROR(32, BMK_benchOutcome_t, "Dst parameters not coherent");
 | 
						|
    }
 | 
						|
    return outcome;
 | 
						|
}
 | 
						|
 | 
						|
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,
 | 
						|
        int displayLevel,
 | 
						|
        const char* displayName)
 | 
						|
{
 | 
						|
    BMK_advancedParams_t const adv = BMK_initAdvancedParams();
 | 
						|
    return BMK_benchMemAdvanced(
 | 
						|
            srcBuffer,
 | 
						|
            srcSize,
 | 
						|
            NULL,
 | 
						|
            0,
 | 
						|
            fileSizes,
 | 
						|
            nbFiles,
 | 
						|
            cLevel,
 | 
						|
            comprParams,
 | 
						|
            dictBuffer,
 | 
						|
            dictBufferSize,
 | 
						|
            displayLevel,
 | 
						|
            displayName,
 | 
						|
            &adv);
 | 
						|
}
 | 
						|
 | 
						|
/* @return: 0 on success, !0 if error */
 | 
						|
static int BMK_benchCLevels(
 | 
						|
        const void* srcBuffer,
 | 
						|
        size_t benchedSize,
 | 
						|
        const size_t* fileSizes,
 | 
						|
        unsigned nbFiles,
 | 
						|
        int startCLevel, int endCLevel,
 | 
						|
        const ZSTD_compressionParameters* comprParams,
 | 
						|
        const void* dictBuffer,
 | 
						|
        size_t dictBufferSize,
 | 
						|
        int displayLevel,
 | 
						|
        const char* displayName,
 | 
						|
        BMK_advancedParams_t const* const adv)
 | 
						|
{
 | 
						|
    int level;
 | 
						|
    const char* pch = strrchr(displayName, '\\'); /* Windows */
 | 
						|
    if (!pch)
 | 
						|
        pch = strrchr(displayName, '/'); /* Linux */
 | 
						|
    if (pch)
 | 
						|
        displayName = pch + 1;
 | 
						|
 | 
						|
    if (endCLevel > ZSTD_maxCLevel()) {
 | 
						|
        DISPLAYLEVEL(1, "Invalid Compression Level \n");
 | 
						|
        return 15;
 | 
						|
    }
 | 
						|
    if (endCLevel < startCLevel) {
 | 
						|
        DISPLAYLEVEL(1, "Invalid Compression Level Range \n");
 | 
						|
        return 15;
 | 
						|
    }
 | 
						|
 | 
						|
    if (adv->realTime) {
 | 
						|
        DISPLAYLEVEL(2, "Note : switching to real-time priority \n");
 | 
						|
        SET_REALTIME_PRIORITY;
 | 
						|
    }
 | 
						|
 | 
						|
    if (displayLevel == 1 && !adv->additionalParam) /* --quiet mode */
 | 
						|
        OUTPUT("bench %s %s: input %u bytes, %u seconds, %u KB chunks\n",
 | 
						|
               ZSTD_VERSION_STRING,
 | 
						|
               ZSTD_GIT_COMMIT_STRING,
 | 
						|
               (unsigned)benchedSize,
 | 
						|
               adv->nbSeconds,
 | 
						|
               (unsigned)(adv->chunkSizeMax >> 10));
 | 
						|
 | 
						|
    for (level = startCLevel; level <= endCLevel; level++) {
 | 
						|
        BMK_benchOutcome_t res = BMK_benchMemAdvanced(
 | 
						|
            srcBuffer,
 | 
						|
            benchedSize,
 | 
						|
            NULL,
 | 
						|
            0,
 | 
						|
            fileSizes,
 | 
						|
            nbFiles,
 | 
						|
            level,
 | 
						|
            comprParams,
 | 
						|
            dictBuffer,
 | 
						|
            dictBufferSize,
 | 
						|
            displayLevel,
 | 
						|
            displayName,
 | 
						|
            adv);
 | 
						|
        if (!BMK_isSuccessful_benchOutcome(res)) return 1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int BMK_syntheticTest(
 | 
						|
        double compressibility,
 | 
						|
        int startingCLevel, int endCLevel,
 | 
						|
        const ZSTD_compressionParameters* compressionParams,
 | 
						|
        int displayLevel,
 | 
						|
        const BMK_advancedParams_t* adv)
 | 
						|
{
 | 
						|
    char nameBuff[20]        = { 0 };
 | 
						|
    const char* name         = nameBuff;
 | 
						|
    size_t const benchedSize = adv->chunkSizeMax ? adv->chunkSizeMax : 10000000;
 | 
						|
 | 
						|
    /* Memory allocation */
 | 
						|
    void* const srcBuffer = malloc(benchedSize);
 | 
						|
    if (!srcBuffer) {
 | 
						|
        DISPLAYLEVEL(1, "allocation error : not enough memory \n");
 | 
						|
        return 16;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Fill input buffer */
 | 
						|
    if (compressibility < 0.0) {
 | 
						|
        LOREM_genBuffer(srcBuffer, benchedSize, 0);
 | 
						|
        name = "Lorem ipsum";
 | 
						|
    } else {
 | 
						|
        RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0);
 | 
						|
        formatString_u(
 | 
						|
                nameBuff,
 | 
						|
                sizeof(nameBuff),
 | 
						|
                "Synthetic %u%%",
 | 
						|
                (unsigned)(compressibility * 100));
 | 
						|
    }
 | 
						|
 | 
						|
    /* Bench */
 | 
						|
    {   int res = BMK_benchCLevels(
 | 
						|
                srcBuffer,
 | 
						|
                benchedSize,
 | 
						|
                &benchedSize,
 | 
						|
                1,
 | 
						|
                startingCLevel, endCLevel,
 | 
						|
                compressionParams,
 | 
						|
                NULL,
 | 
						|
                0, /* dictionary */
 | 
						|
                displayLevel,
 | 
						|
                name,
 | 
						|
                adv);
 | 
						|
        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. */
 | 
						|
static int BMK_loadFiles(
 | 
						|
        void* buffer,
 | 
						|
        size_t bufferSize,
 | 
						|
        size_t* fileSizes,
 | 
						|
        const char* const* fileNamesTable,
 | 
						|
        unsigned nbFiles,
 | 
						|
        int displayLevel)
 | 
						|
{
 | 
						|
    size_t pos = 0, totalSize = 0;
 | 
						|
    unsigned n;
 | 
						|
    for (n = 0; n < nbFiles; n++) {
 | 
						|
        const char* const filename = fileNamesTable[n];
 | 
						|
        U64 fileSize = UTIL_getFileSize(
 | 
						|
                filename); /* last file may be shortened */
 | 
						|
        if (UTIL_isDirectory(filename)) {
 | 
						|
            DISPLAYLEVEL(
 | 
						|
                    2, "Ignoring %s directory...       \n", filename);
 | 
						|
            fileSizes[n] = 0;
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
        if (fileSize == UTIL_FILESIZE_UNKNOWN) {
 | 
						|
            DISPLAYLEVEL(
 | 
						|
                    2,
 | 
						|
                    "Cannot evaluate size of %s, ignoring ... \n",
 | 
						|
                    filename);
 | 
						|
            fileSizes[n] = 0;
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
        if (fileSize > bufferSize - pos) {
 | 
						|
            /* buffer too small - limit quantity loaded */
 | 
						|
            fileSize = bufferSize - pos;
 | 
						|
            nbFiles  = n; /* stop after this file */
 | 
						|
        }
 | 
						|
 | 
						|
        {   FILE* const f = fopen(filename, "rb");
 | 
						|
            if (f == NULL) {
 | 
						|
                RETURN_ERROR_INT(
 | 
						|
                        10, "cannot open file %s", filename);
 | 
						|
            }
 | 
						|
            OUTPUTLEVEL(2, "Loading %s...       \r", filename);
 | 
						|
            {   size_t const readSize =
 | 
						|
                        fread(((char*)buffer) + pos, 1, (size_t)fileSize, f);
 | 
						|
                if (readSize != (size_t)fileSize) {
 | 
						|
                    fclose(f);
 | 
						|
                    RETURN_ERROR_INT(
 | 
						|
                            11, "invalid read %s", filename);
 | 
						|
                }
 | 
						|
                pos += readSize;
 | 
						|
            }
 | 
						|
            fileSizes[n] = (size_t)fileSize;
 | 
						|
            totalSize += (size_t)fileSize;
 | 
						|
            fclose(f);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (totalSize == 0)
 | 
						|
        RETURN_ERROR_INT(12, "no data to bench");
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int BMK_benchFilesAdvanced(
 | 
						|
        const char* const* fileNamesTable,
 | 
						|
        unsigned nbFiles,
 | 
						|
        const char* dictFileName,
 | 
						|
        int startCLevel, int endCLevel,
 | 
						|
        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;
 | 
						|
    int res = 1;
 | 
						|
    U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
 | 
						|
 | 
						|
    if (!nbFiles) {
 | 
						|
        DISPLAYLEVEL(1, "No Files to Benchmark");
 | 
						|
        return 13;
 | 
						|
    }
 | 
						|
 | 
						|
    if (endCLevel > ZSTD_maxCLevel()) {
 | 
						|
        DISPLAYLEVEL(1, "Invalid Compression Level");
 | 
						|
        return 14;
 | 
						|
    }
 | 
						|
 | 
						|
    if (totalSizeToLoad == UTIL_FILESIZE_UNKNOWN) {
 | 
						|
        DISPLAYLEVEL(1, "Error loading files");
 | 
						|
        return 15;
 | 
						|
    }
 | 
						|
 | 
						|
    fileSizes = (size_t*)calloc(nbFiles, sizeof(size_t));
 | 
						|
    if (!fileSizes) {
 | 
						|
        DISPLAYLEVEL(1, "not enough memory for fileSizes");
 | 
						|
        return 16;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Load dictionary */
 | 
						|
    if (dictFileName != NULL) {
 | 
						|
        U64 const dictFileSize = UTIL_getFileSize(dictFileName);
 | 
						|
        if (dictFileSize == UTIL_FILESIZE_UNKNOWN) {
 | 
						|
            DISPLAYLEVEL(
 | 
						|
                    1,
 | 
						|
                    "error loading %s : %s \n",
 | 
						|
                    dictFileName,
 | 
						|
                    strerror(errno));
 | 
						|
            free(fileSizes);
 | 
						|
            DISPLAYLEVEL(1, "benchmark aborted");
 | 
						|
            return 17;
 | 
						|
        }
 | 
						|
        if (dictFileSize > 64 MB) {
 | 
						|
            free(fileSizes);
 | 
						|
            DISPLAYLEVEL(1, "dictionary file %s too large", dictFileName);
 | 
						|
            return 18;
 | 
						|
        }
 | 
						|
        dictBufferSize = (size_t)dictFileSize;
 | 
						|
        dictBuffer     = malloc(dictBufferSize);
 | 
						|
        if (dictBuffer == NULL) {
 | 
						|
            free(fileSizes);
 | 
						|
            DISPLAYLEVEL(
 | 
						|
                    1,
 | 
						|
                    "not enough memory for dictionary (%u bytes)",
 | 
						|
                    (unsigned)dictBufferSize);
 | 
						|
            return 19;
 | 
						|
        }
 | 
						|
 | 
						|
        {
 | 
						|
            int const errorCode = BMK_loadFiles(
 | 
						|
                    dictBuffer,
 | 
						|
                    dictBufferSize,
 | 
						|
                    fileSizes,
 | 
						|
                    &dictFileName /*?*/,
 | 
						|
                    1 /*?*/,
 | 
						|
                    displayLevel);
 | 
						|
            if (errorCode) {
 | 
						|
                goto _cleanUp;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* Memory allocation & restrictions */
 | 
						|
    benchedSize = BMK_findMaxMem(totalSizeToLoad * 3) / 3;
 | 
						|
    if ((U64)benchedSize > totalSizeToLoad)
 | 
						|
        benchedSize = (size_t)totalSizeToLoad;
 | 
						|
    if (benchedSize < totalSizeToLoad)
 | 
						|
        DISPLAY("Not enough memory; testing %u MB only...\n",
 | 
						|
                (unsigned)(benchedSize >> 20));
 | 
						|
 | 
						|
    srcBuffer = benchedSize ? malloc(benchedSize) : NULL;
 | 
						|
    if (!srcBuffer) {
 | 
						|
        free(dictBuffer);
 | 
						|
        free(fileSizes);
 | 
						|
        DISPLAYLEVEL(1, "not enough memory for srcBuffer");
 | 
						|
        return 20;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Load input buffer */
 | 
						|
    {
 | 
						|
        int const errorCode = BMK_loadFiles(
 | 
						|
                srcBuffer,
 | 
						|
                benchedSize,
 | 
						|
                fileSizes,
 | 
						|
                fileNamesTable,
 | 
						|
                nbFiles,
 | 
						|
                displayLevel);
 | 
						|
        if (errorCode) {
 | 
						|
            goto _cleanUp;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* Bench */
 | 
						|
    {
 | 
						|
        char mfName[20] = { 0 };
 | 
						|
        formatString_u(mfName, sizeof(mfName), " %u files", nbFiles);
 | 
						|
        {   const char* const displayName =
 | 
						|
                    (nbFiles > 1) ? mfName : fileNamesTable[0];
 | 
						|
            res = BMK_benchCLevels(
 | 
						|
                    srcBuffer,
 | 
						|
                    benchedSize,
 | 
						|
                    fileSizes,
 | 
						|
                    nbFiles,
 | 
						|
                    startCLevel, endCLevel,
 | 
						|
                    compressionParams,
 | 
						|
                    dictBuffer,
 | 
						|
                    dictBufferSize,
 | 
						|
                    displayLevel,
 | 
						|
                    displayName,
 | 
						|
                    adv);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
_cleanUp:
 | 
						|
    free(srcBuffer);
 | 
						|
    free(dictBuffer);
 | 
						|
    free(fileSizes);
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
int BMK_benchFiles(
 | 
						|
        const char* const* fileNamesTable,
 | 
						|
        unsigned nbFiles,
 | 
						|
        const char* dictFileName,
 | 
						|
        int cLevel,
 | 
						|
        const ZSTD_compressionParameters* compressionParams,
 | 
						|
        int displayLevel)
 | 
						|
{
 | 
						|
    BMK_advancedParams_t const adv = BMK_initAdvancedParams();
 | 
						|
    return BMK_benchFilesAdvanced(
 | 
						|
            fileNamesTable,
 | 
						|
            nbFiles,
 | 
						|
            dictFileName,
 | 
						|
            cLevel, cLevel,
 | 
						|
            compressionParams,
 | 
						|
            displayLevel,
 | 
						|
            &adv);
 | 
						|
}
 |