#define KB *(1<<10)
#define MB *(1<<20)
-#define BLOCKSIZE (4 KB)
+#define BLOCKSIZE_DEFAULT (4 KB)
#define DICTSIZE (4 KB)
-#define COMP_LEVEL 3
+#define CLEVEL_DEFAULT 3
#define DISPLAY_LEVEL_DEFAULT 3
typedef struct {
ZSTD_DCtx* dctx;
- size_t nbBlocks;
- size_t blockNb;
+ size_t nbDicts;
+ size_t dictNb;
ddict_collection_t dictionaries;
} decompressInstructions;
decompressInstructions di;
di.dctx = ZSTD_createDCtx();
assert(di.dctx != NULL);
- di.nbBlocks = dictionaries.nbDDict;
- di.blockNb = 0;
+ di.nbDicts = dictionaries.nbDDict;
+ di.dictNb = 0;
di.dictionaries = dictionaries;
return di;
}
size_t const result = ZSTD_decompress_usingDDict(di->dctx,
dst, dstCapacity,
src, srcSize,
- di->dictionaries.ddicts[di->blockNb]);
+ di->dictionaries.ddicts[di->dictNb]);
- di->blockNb = di->blockNb + 1;
- if (di->blockNb >= di->nbBlocks) di->blockNb = 0;
+ di->dictNb = di->dictNb + 1;
+ if (di->dictNb >= di->nbDicts) di->dictNb = 0;
return result;
}
ddict_collection_t dictionaries)
{
assert(dstBlocks.nbBuffers == srcBlocks.nbBuffers);
- assert(dstBlocks.nbBuffers == dictionaries.nbDDict);
double bestSpeed = 0.;
double const dSpeed_MBps = (double)srcSize / dTime_sec / (1 MB);
if (dSpeed_MBps > bestSpeed) bestSpeed = dSpeed_MBps;
DISPLAY("Decompression Speed : %.1f MB/s \r", bestSpeed);
+ fflush(stdout);
if (BMK_isCompleted_TimedFn(benchState)) break;
}
DISPLAY("\n");
* 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)
+int bench(const char* fileName, const char* dictionary,
+ size_t blockSize, int clevel, unsigned nbDictMax)
{
int result = 0;
DISPLAYLEVEL(3, "created src buffer of size %.1f MB \n",
(double)srcSize / (1 MB));
- buffer_collection_t const srcBlockBuffers = splitBuffer(srcBuffer, BLOCKSIZE);
+ 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, BLOCKSIZE);
+ nbBlocks, (unsigned)blockSize);
- size_t const dstBlockSize = ZSTD_compressBound(BLOCKSIZE);
+ size_t const dstBlockSize = ZSTD_compressBound(blockSize);
size_t const dstBufferCapacity = nbBlocks * dstBlockSize;
void* const dstPtr = malloc(dstBufferCapacity);
assert(dstPtr != NULL);
srcBlockBuffers.capacities, nbBlocks);
assert(dictBuffer.ptr != NULL);
- ZSTD_CDict* const cdict = ZSTD_createCDict(dictBuffer.ptr, dictBuffer.size, COMP_LEVEL);
+ ZSTD_CDict* const cdict = ZSTD_createCDict(dictBuffer.ptr, dictBuffer.size, clevel);
assert(cdict != NULL);
- size_t const cTotalSizeNoDict = compressBlocks(NULL, dstBlockBuffers, srcBlockBuffers, NULL, COMP_LEVEL);
+ size_t const cTotalSizeNoDict = compressBlocks(NULL, dstBlockBuffers, srcBlockBuffers, NULL, clevel);
assert(cTotalSizeNoDict != 0);
DISPLAYLEVEL(3, "compressing at level %u without dictionary : Ratio=%.2f (%u bytes) \n",
- COMP_LEVEL,
+ clevel,
(double)srcSize / cTotalSizeNoDict, (unsigned)cTotalSizeNoDict);
size_t* const cSizes = malloc(nbBlocks * sizeof(size_t));
assert(cSizes != NULL);
- size_t const cTotalSize = compressBlocks(cSizes, dstBlockBuffers, srcBlockBuffers, cdict, COMP_LEVEL);
+ size_t const cTotalSize = compressBlocks(cSizes, dstBlockBuffers, srcBlockBuffers, cdict, clevel);
assert(cTotalSize != 0);
DISPLAYLEVEL(3, "compressed using a %u bytes dictionary : Ratio=%.2f (%u bytes) \n",
(unsigned)dictBuffer.size,
(double)srcSize / cTotalSize, (unsigned)cTotalSize);
size_t const dictMem = ZSTD_estimateDDictSize(dictBuffer.size, ZSTD_dlm_byCopy);
- size_t const allDictMem = dictMem * nbBlocks;
+ unsigned const nbDicts = nbDictMax ? nbDictMax : nbBlocks;
+ size_t const allDictMem = dictMem * nbDicts;
DISPLAYLEVEL(3, "generating %u dictionaries, using %.1f MB of memory \n",
- nbBlocks, (double)allDictMem / (1 MB));
+ nbDicts, (double)allDictMem / (1 MB));
- ddict_collection_t const dictionaries = createDDictCollection(dictBuffer.ptr, dictBuffer.size, nbBlocks);
+ ddict_collection_t const dictionaries = createDDictCollection(dictBuffer.ptr, dictBuffer.size, nbDicts);
assert(dictionaries.ddicts != NULL);
shuffleDictionaries(dictionaries);
resultBuffer.capacity = srcSize;
resultBuffer.size = srcSize;
- buffer_collection_t const resultBlockBuffers = splitBuffer(resultBuffer, BLOCKSIZE);
+ buffer_collection_t const resultBlockBuffers = splitBuffer(resultBuffer, blockSize);
assert(resultBlockBuffers.buffers != NULL);
shrinkSizes(dstBlockBuffers, cSizes);
/* --- Command Line --- */
+/*! readU32FromChar() :
+ * @return : unsigned integer value read from input in `char` format.
+ * allows and interprets K, KB, KiB, M, MB and MiB suffix.
+ * Will also modify `*stringPtr`, advancing it to position where it stopped reading.
+ * Note : function will exit() program if digit sequence overflows */
+static unsigned readU32FromChar(const char** stringPtr)
+{
+ unsigned result = 0;
+ while ((**stringPtr >='0') && (**stringPtr <='9')) {
+ unsigned const max = (((unsigned)(-1)) / 10) - 1;
+ assert(result <= max); /* check overflow */
+ result *= 10, result += **stringPtr - '0', (*stringPtr)++ ;
+ }
+ if ((**stringPtr=='K') || (**stringPtr=='M')) {
+ unsigned const maxK = ((unsigned)(-1)) >> 10;
+ assert(result <= maxK); /* check overflow */
+ result <<= 10;
+ if (**stringPtr=='M') {
+ assert(result <= maxK); /* check overflow */
+ result <<= 10;
+ }
+ (*stringPtr)++; /* skip `K` or `M` */
+ if (**stringPtr=='i') (*stringPtr)++;
+ if (**stringPtr=='B') (*stringPtr)++;
+ }
+ return result;
+}
+
+/** longCommandWArg() :
+ * check if *stringPtr is the same as longCommand.
+ * If yes, @return 1 and advances *stringPtr to the position which immediately follows longCommand.
+ * @return 0 and doesn't modify *stringPtr otherwise.
+ */
+static unsigned longCommandWArg(const char** stringPtr, const char* longCommand)
+{
+ size_t const comSize = strlen(longCommand);
+ int const result = !strncmp(*stringPtr, longCommand, comSize);
+ if (result) *stringPtr += comSize;
+ return result;
+}
+
+
int bad_usage(const char* exeName)
{
DISPLAY (" bad usage : \n");
- DISPLAY (" %s filename [-D dictionary] \n", exeName);
+ DISPLAY (" %s filename [Options] \n", exeName);
+ DISPLAY ("Options : \n");
+ DISPLAY ("--clevel=# : use compression level # (default: %u) \n", CLEVEL_DEFAULT);
+ DISPLAY ("--blockSize=# : cut input into blocks of size # (default: %u) \n", BLOCKSIZE_DEFAULT);
+ DISPLAY ("--dictionary=# : use # as a dictionary (default: create one) \n");
+ DISPLAY ("--nbDicts=# : set nb of dictionaries to # (default: one per block) \n");
return 1;
}
int main (int argc, const char** argv)
{
const char* const exeName = argv[0];
+ int cLevel = CLEVEL_DEFAULT;
+ size_t blockSize = BLOCKSIZE_DEFAULT;
+ size_t nbDicts = 0;
if (argc < 2) return bad_usage(exeName);
const char* const fileName = argv[1];
const char* dictionary = NULL;
- if (argc > 2) {
- if (argc != 4) return bad_usage(exeName);
- if (strcmp(argv[2], "-D")) return bad_usage(exeName);
- dictionary = argv[3];
+ for (int argNb = 2; argNb < argc ; argNb++) {
+ const char* argument = argv[argNb];
+ if (longCommandWArg(&argument, "--clevel=")) { cLevel = readU32FromChar(&argument); continue; }
+ if (longCommandWArg(&argument, "--blockSize=")) { blockSize = readU32FromChar(&argument); continue; }
+ if (longCommandWArg(&argument, "--dictionary=")) { dictionary = argument; continue; }
+ if (longCommandWArg(&argument, "--nbDicts=")) { nbDicts = readU32FromChar(&argument); continue; }
+ return bad_usage(exeName);
}
- return bench(fileName, dictionary);
+ return bench(fileName, dictionary, blockSize, cLevel, nbDicts);
}