From 4086b2871b8ce6c18b70906a9b03dc4f131f2a4b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 30 Aug 2018 11:02:08 -0700 Subject: [PATCH] largeNbDicts compatible with multiple source files splitting is disabled by default, but can be re-enabled using usual command -B# update commands to look like zstd ones --- contrib/largeNbDicts/Makefile | 2 +- contrib/largeNbDicts/largeNbDicts.c | 555 +++++++++++++++++++--------- programs/bench.c | 12 +- programs/util.h | 5 +- 4 files changed, 396 insertions(+), 178 deletions(-) diff --git a/contrib/largeNbDicts/Makefile b/contrib/largeNbDicts/Makefile index 0f8dbb3a..cf529399 100644 --- a/contrib/largeNbDicts/Makefile +++ b/contrib/largeNbDicts/Makefile @@ -16,7 +16,7 @@ CPPFLAGS+= -I$(LIBDIR) -I$(LIBDIR)/common -I$(LIBDIR)/dictBuilder -I$(PROGDIR) CFLAGS ?= -O3 DEBUGFLAGS= -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ - -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \ + -Wstrict-aliasing=1 -Wswitch-enum \ -Wstrict-prototypes -Wundef -Wpointer-arith -Wformat-security \ -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \ -Wredundant-decls diff --git a/contrib/largeNbDicts/largeNbDicts.c b/contrib/largeNbDicts/largeNbDicts.c index 19336249..5b982bd4 100644 --- a/contrib/largeNbDicts/largeNbDicts.c +++ b/contrib/largeNbDicts/largeNbDicts.c @@ -35,12 +35,22 @@ #define KB *(1<<10) #define MB *(1<<20) -#define BLOCKSIZE_DEFAULT (4 KB) +#define BLOCKSIZE_DEFAULT 0 /* no slicing into blocks */ #define DICTSIZE (4 KB) #define CLEVEL_DEFAULT 3 +#define BENCH_TIME_DEFAULT_S 6 +#define RUN_TIME_DEFAULT_MS 1000 +#define BENCH_TIME_DEFAULT_MS (BENCH_TIME_DEFAULT_S * RUN_TIME_DEFAULT_MS) + #define DISPLAY_LEVEL_DEFAULT 3 +#define BENCH_SIZE_MAX (1200 MB) + + +/*--- Macros ---*/ +#define CONTROL(c) assert(c) + /*--- Display Macros ---*/ @@ -59,12 +69,17 @@ typedef struct { static const buffer_t kBuffNull = { NULL, 0, 0 }; - -static buffer_t fillBuffer_fromHandle(buffer_t buff, FILE* f) +/* @return : kBuffNull if any error */ +static buffer_t createBuffer(size_t capacity) { - size_t const readSize = fread(buff.ptr, 1, buff.capacity, f); - buff.size = readSize; - return buff; + void* const ptr = malloc(capacity); + if (ptr==NULL) return kBuffNull; + + buffer_t buffer; + buffer.ptr = ptr; + buffer.capacity = capacity; + buffer.size = 0; + return buffer; } static void freeBuffer(buffer_t buff) @@ -72,20 +87,24 @@ static void freeBuffer(buffer_t buff) free(buff.ptr); } + +static void fillBuffer_fromHandle(buffer_t* buff, FILE* f) +{ + size_t const readSize = fread(buff->ptr, 1, buff->capacity, f); + buff->size = readSize; +} + /* @return : kBuffNull if any error */ static buffer_t createBuffer_fromHandle(FILE* f, size_t bufferSize) { - void* const buffer = malloc(bufferSize); - if (buffer==NULL) return kBuffNull; - - { buffer_t buff = { buffer, 0, bufferSize }; - buff = fillBuffer_fromHandle(buff, f); - if (buff.size != buff.capacity) { - freeBuffer(buff); - return kBuffNull; - } - return buff; + buffer_t buff = createBuffer(bufferSize); + if (buff.ptr == NULL) return kBuffNull; + fillBuffer_fromHandle(&buff, f); + if (buff.size != buff.capacity) { + freeBuffer(buff); + return kBuffNull; } + return buff; } /* @return : kBuffNull if any error */ @@ -107,78 +126,14 @@ static buffer_t createBuffer_fromFile(const char* fileName) } } - -/*--- buffer_collection_t ---*/ - -typedef struct { - void** buffers; - size_t* capacities; - size_t nbBuffers; -} buffer_collection_t; - -static const buffer_collection_t kNullCollection = { NULL, NULL, 0 }; - -static void freeCollection(buffer_collection_t collection) +static buffer_t +createDictionaryBuffer(const char* dictionaryName, + const void* srcBuffer, + const size_t* srcBlockSizes, unsigned nbBlocks) { - free(collection.buffers); - free(collection.capacities); -} - -/* returns .buffers=NULL if operation fails */ -buffer_collection_t splitBuffer(buffer_t srcBuffer, size_t blockSize) -{ - size_t const nbBlocks = (srcBuffer.size + (blockSize-1)) / blockSize; - - void** const buffers = malloc(nbBlocks * sizeof(void*)); - size_t* const capacities = malloc(nbBlocks * sizeof(size_t*)); - if ((buffers==NULL) || capacities==NULL) { - free(buffers); - free(capacities); - return kNullCollection; - } - - char* newBlockPtr = (char*)srcBuffer.ptr; - char* const srcEnd = newBlockPtr + srcBuffer.size; - assert(nbBlocks >= 1); - for (size_t blockNb = 0; blockNb < nbBlocks-1; blockNb++) { - buffers[blockNb] = newBlockPtr; - capacities[blockNb] = blockSize; - newBlockPtr += blockSize; - } - - /* last block */ - assert(newBlockPtr <= srcEnd); - size_t const lastBlockSize = (srcEnd - newBlockPtr); - buffers[nbBlocks-1] = newBlockPtr; - capacities[nbBlocks-1] = lastBlockSize; - - buffer_collection_t result; - result.buffers = buffers; - result.capacities = capacities; - result.nbBuffers = nbBlocks; - return result; -} - -/* shrinkSizes() : - * update sizes in buffer collection */ -void shrinkSizes(buffer_collection_t collection, - const size_t* sizes) /* presumed same size as collection */ -{ - size_t const nbBlocks = collection.nbBuffers; - for (size_t blockNb = 0; blockNb < nbBlocks; blockNb++) { - assert(sizes[blockNb] <= collection.capacities[blockNb]); - collection.capacities[blockNb] = sizes[blockNb]; - } -} - -/*--- dictionary creation ---*/ - -buffer_t createDictionary(const char* dictionary, - const void* srcBuffer, size_t* srcBlockSizes, unsigned nbBlocks) -{ - if (dictionary) { - DISPLAYLEVEL(3, "loading dictionary %s \n", dictionary); - return createBuffer_fromFile(dictionary); + if (dictionaryName) { + DISPLAYLEVEL(3, "loading dictionary %s \n", dictionaryName); + return createBuffer_fromFile(dictionaryName); } else { DISPLAYLEVEL(3, "creating dictionary, of target size %u bytes \n", DICTSIZE); void* const dictBuffer = malloc(DICTSIZE); @@ -199,6 +154,229 @@ buffer_t createDictionary(const char* dictionary, } +/*! BMK_loadFiles() : + * Loads `buffer`, with content from files listed within `fileNamesTable`. + * Fills `buffer` entirely. + * @return : 0 on success, !=0 on error */ +static int loadFiles(void* buffer, size_t bufferSize, + size_t* fileSizes, + const char* const * fileNamesTable, unsigned nbFiles) +{ + size_t pos = 0, totalSize = 0; + + for (unsigned n=0; n 0); + size_t* const fileSizes = (size_t*)calloc(nbFiles, sizeof(*fileSizes)); + assert(fileSizes != NULL); + + /* Load input buffer */ + int const errorCode = loadFiles(srcBuffer, loadedSize, + fileSizes, + fileNamesTable, nbFiles); + assert(errorCode == 0); + + void** sliceTable = (void**)malloc(nbFiles * sizeof(*sliceTable)); + assert(sliceTable != NULL); + + char* const ptr = (char*)srcBuffer; + size_t pos = 0; + unsigned fileNb = 0; + for ( ; (pos < loadedSize) && (fileNb < nbFiles); fileNb++) { + sliceTable[fileNb] = ptr + pos; + pos += fileSizes[fileNb]; + } + assert(pos == loadedSize); + assert(fileNb == nbFiles); + + + buffer_t buffer; + buffer.ptr = srcBuffer; + buffer.capacity = loadedSize; + buffer.size = loadedSize; + + slice_collection_t slices; + slices.slicePtrs = sliceTable; + slices.capacities = fileSizes; + slices.nbSlices = nbFiles; + + buffer_collection_t bc; + bc.buffer = buffer; + bc.slices = slices; + return bc; +} + + + + /*--- ddict_collection_t ---*/ typedef struct { @@ -260,12 +438,12 @@ void shuffleDictionaries(ddict_collection_t dicts) * or 0 if error. */ static size_t compressBlocks(size_t* cSizes, /* optional (can be NULL). If present, must contain at least nbBlocks fields */ - buffer_collection_t dstBlockBuffers, - buffer_collection_t srcBlockBuffers, + slice_collection_t dstBlockBuffers, + slice_collection_t srcBlockBuffers, ZSTD_CDict* cdict, int cLevel) { - size_t const nbBlocks = srcBlockBuffers.nbBuffers; - assert(dstBlockBuffers.nbBuffers == srcBlockBuffers.nbBuffers); + size_t const nbBlocks = srcBlockBuffers.nbSlices; + assert(dstBlockBuffers.nbSlices == srcBlockBuffers.nbSlices); ZSTD_CCtx* const cctx = ZSTD_createCCtx(); assert(cctx != NULL); @@ -275,16 +453,16 @@ static size_t compressBlocks(size_t* cSizes, /* optional (can be NULL). If pre size_t cBlockSize; if (cdict == NULL) { cBlockSize = ZSTD_compressCCtx(cctx, - dstBlockBuffers.buffers[blockNb], dstBlockBuffers.capacities[blockNb], - srcBlockBuffers.buffers[blockNb], srcBlockBuffers.capacities[blockNb], + dstBlockBuffers.slicePtrs[blockNb], dstBlockBuffers.capacities[blockNb], + srcBlockBuffers.slicePtrs[blockNb], srcBlockBuffers.capacities[blockNb], cLevel); } else { cBlockSize = ZSTD_compress_usingCDict(cctx, - dstBlockBuffers.buffers[blockNb], dstBlockBuffers.capacities[blockNb], - srcBlockBuffers.buffers[blockNb], srcBlockBuffers.capacities[blockNb], + dstBlockBuffers.slicePtrs[blockNb], dstBlockBuffers.capacities[blockNb], + srcBlockBuffers.slicePtrs[blockNb], srcBlockBuffers.capacities[blockNb], cdict); } - assert(!ZSTD_isError(cBlockSize)); + CONTROL(!ZSTD_isError(cBlockSize)); if (cSizes) cSizes[blockNb] = cBlockSize; totalCSize += cBlockSize; } @@ -337,31 +515,32 @@ size_t decompress(const void* src, size_t srcSize, void* dst, size_t dstCapacity } -#define BENCH_TIME_DEFAULT_MS 6000 -#define RUN_TIME_DEFAULT_MS 1000 - -static int benchMem(buffer_collection_t dstBlocks, - buffer_collection_t srcBlocks, - ddict_collection_t dictionaries) +static int benchMem(slice_collection_t dstBlocks, + slice_collection_t srcBlocks, + ddict_collection_t dictionaries, + int nbRounds) { - assert(dstBlocks.nbBuffers == srcBlocks.nbBuffers); + assert(dstBlocks.nbSlices == srcBlocks.nbSlices); + + unsigned const ms_per_round = RUN_TIME_DEFAULT_MS; + unsigned const total_time_ms = nbRounds * ms_per_round; double bestSpeed = 0.; BMK_timedFnState_t* const benchState = - BMK_createTimedFnState(BENCH_TIME_DEFAULT_MS, RUN_TIME_DEFAULT_MS); + BMK_createTimedFnState(total_time_ms, ms_per_round); decompressInstructions di = createDecompressInstructions(dictionaries); for (;;) { BMK_runOutcome_t const outcome = BMK_benchTimedFn(benchState, decompress, &di, NULL, NULL, - dstBlocks.nbBuffers, - (const void* const *)srcBlocks.buffers, srcBlocks.capacities, - dstBlocks.buffers, dstBlocks.capacities, + dstBlocks.nbSlices, + (const void* const *)srcBlocks.slicePtrs, srcBlocks.capacities, + dstBlocks.slicePtrs, dstBlocks.capacities, NULL); + CONTROL(BMK_isSuccessful_runOutcome(outcome)); - assert(BMK_isSuccessful_runOutcome(outcome)); BMK_runTime_t const result = BMK_extract_runTime(outcome); U64 const dTime_ns = result.nanoSecPerRun; double const dTime_sec = (double)dTime_ns / 1000000000; @@ -381,65 +560,87 @@ static int benchMem(buffer_collection_t dstBlocks, } -/* bench() : - * fileName : file to load for benchmarking purpose - * dictionary : optional (can be NULL), file to load as dictionary, +/*! bench() : + * fileName : file to load for benchmarking purpose + * dictionary : optional (can be NULL), file to load as dictionary, * if none provided : will be calculated on the fly by the program. * @return : 0 is success, 1+ otherwise */ -int bench(const char* fileName, const char* dictionary, - size_t blockSize, int clevel, unsigned nbDictMax) +int bench(const char** fileNameTable, unsigned nbFiles, + const char* dictionary, + size_t blockSize, int clevel, unsigned nbDictMax, int nbRounds) { int result = 0; - DISPLAYLEVEL(3, "loading %s... \n", fileName); - buffer_t const srcBuffer = createBuffer_fromFile(fileName); - assert(srcBuffer.ptr != NULL); + DISPLAYLEVEL(3, "loading %u files... \n", nbFiles); + buffer_collection_t const srcs = createBufferCollection_fromFiles(fileNameTable, nbFiles); + CONTROL(srcs.buffer.ptr != NULL); + buffer_t srcBuffer = srcs.buffer; size_t const srcSize = srcBuffer.size; DISPLAYLEVEL(3, "created src buffer of size %.1f MB \n", (double)srcSize / (1 MB)); - buffer_collection_t const srcBlockBuffers = splitBuffer(srcBuffer, blockSize); - assert(srcBlockBuffers.buffers != NULL); - unsigned const nbBlocks = (unsigned)srcBlockBuffers.nbBuffers; - DISPLAYLEVEL(3, "split input into %u blocks of max size %u bytes \n", - nbBlocks, (unsigned)blockSize); + slice_collection_t const srcSlices = splitSlices(srcs.slices, blockSize); + unsigned const nbBlocks = (unsigned)(srcSlices.nbSlices); + DISPLAYLEVEL(3, "split input into %u blocks ", nbBlocks); + if (blockSize) + DISPLAYLEVEL(3, "of max size %u bytes ", (unsigned)blockSize); + DISPLAYLEVEL(3, "\n"); - size_t const dstBlockSize = ZSTD_compressBound(blockSize); - size_t const dstBufferCapacity = nbBlocks * dstBlockSize; - void* const dstPtr = malloc(dstBufferCapacity); - assert(dstPtr != NULL); - buffer_t dstBuffer; - dstBuffer.ptr = dstPtr; - dstBuffer.capacity = dstBufferCapacity; - dstBuffer.size = dstBufferCapacity; - buffer_collection_t const dstBlockBuffers = splitBuffer(dstBuffer, dstBlockSize); - assert(dstBlockBuffers.buffers != NULL); + size_t* const dstCapacities = malloc(nbBlocks * sizeof(*dstCapacities)); + CONTROL(dstCapacities != NULL); + size_t dstBufferCapacity = 0; + for (size_t bnb=0; bnb bufferSize-pos) fileSize = bufferSize-pos, nbFiles=n; /* buffer too small - stop after this file */ - { size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f); - if (readSize != (size_t)fileSize) EXM_THROW_INT(11, "could not read %s", fileNamesTable[n]); - pos += readSize; } + { size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f); + if (readSize != (size_t)fileSize) EXM_THROW_INT(11, "could not read %s", fileNamesTable[n]); + pos += readSize; + } fileSizes[n] = (size_t)fileSize; totalSize += (size_t)fileSize; fclose(f); diff --git a/programs/util.h b/programs/util.h index 4392a5bd..76000d99 100644 --- a/programs/util.h +++ b/programs/util.h @@ -526,7 +526,10 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ * After finishing usage of the list the structures should be freed with UTIL_freeFileList(params: return value, allocatedBuffer) * In case of error UTIL_createFileList returns NULL and UTIL_freeFileList should not be called. */ -UTIL_STATIC const char** UTIL_createFileList(const char **inputNames, unsigned inputNamesNb, char** allocatedBuffer, unsigned* allocatedNamesNb, int followLinks) +UTIL_STATIC const char** +UTIL_createFileList(const char **inputNames, unsigned inputNamesNb, + char** allocatedBuffer, unsigned* allocatedNamesNb, + int followLinks) { size_t pos; unsigned i, nbFiles;