1*01826a49SYabin Cui /*
2*01826a49SYabin Cui * Copyright (c) Meta Platforms, Inc. and affiliates.
3*01826a49SYabin Cui * All rights reserved.
4*01826a49SYabin Cui *
5*01826a49SYabin Cui * This source code is licensed under both the BSD-style license (found in the
6*01826a49SYabin Cui * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*01826a49SYabin Cui * in the COPYING file in the root directory of this source tree).
8*01826a49SYabin Cui * You may select, at your option, one of the above-listed licenses.
9*01826a49SYabin Cui */
10*01826a49SYabin Cui
11*01826a49SYabin Cui /* largeNbDicts
12*01826a49SYabin Cui * This is a benchmark test tool
13*01826a49SYabin Cui * dedicated to the specific case of dictionary decompression
14*01826a49SYabin Cui * using a very large nb of dictionaries
15*01826a49SYabin Cui * thus suffering latency from lots of cache misses.
16*01826a49SYabin Cui * It's created in a bid to investigate performance and find optimizations. */
17*01826a49SYabin Cui
18*01826a49SYabin Cui
19*01826a49SYabin Cui /*--- Dependencies ---*/
20*01826a49SYabin Cui
21*01826a49SYabin Cui #include <stddef.h> /* size_t */
22*01826a49SYabin Cui #include <stdlib.h> /* malloc, free, abort, qsort*/
23*01826a49SYabin Cui #include <stdio.h> /* fprintf */
24*01826a49SYabin Cui #include <limits.h> /* UINT_MAX */
25*01826a49SYabin Cui #include <assert.h> /* assert */
26*01826a49SYabin Cui
27*01826a49SYabin Cui #include "util.h"
28*01826a49SYabin Cui #include "benchfn.h"
29*01826a49SYabin Cui #define ZSTD_STATIC_LINKING_ONLY
30*01826a49SYabin Cui #include "zstd.h"
31*01826a49SYabin Cui #include "zdict.h"
32*01826a49SYabin Cui
33*01826a49SYabin Cui
34*01826a49SYabin Cui /*--- Constants --- */
35*01826a49SYabin Cui
36*01826a49SYabin Cui #define KB *(1<<10)
37*01826a49SYabin Cui #define MB *(1<<20)
38*01826a49SYabin Cui
39*01826a49SYabin Cui #define BLOCKSIZE_DEFAULT 0 /* no slicing into blocks */
40*01826a49SYabin Cui #define DICTSIZE (4 KB)
41*01826a49SYabin Cui #define CLEVEL_DEFAULT 3
42*01826a49SYabin Cui #define DICT_LOAD_METHOD ZSTD_dlm_byCopy
43*01826a49SYabin Cui
44*01826a49SYabin Cui #define BENCH_TIME_DEFAULT_S 6
45*01826a49SYabin Cui #define RUN_TIME_DEFAULT_MS 1000
46*01826a49SYabin Cui #define BENCH_TIME_DEFAULT_MS (BENCH_TIME_DEFAULT_S * RUN_TIME_DEFAULT_MS)
47*01826a49SYabin Cui
48*01826a49SYabin Cui #define DISPLAY_LEVEL_DEFAULT 3
49*01826a49SYabin Cui
50*01826a49SYabin Cui #define BENCH_SIZE_MAX (1200 MB)
51*01826a49SYabin Cui
52*01826a49SYabin Cui
53*01826a49SYabin Cui /*--- Macros ---*/
54*01826a49SYabin Cui
55*01826a49SYabin Cui #define CONTROL(c) { if (!(c)) abort(); }
56*01826a49SYabin Cui #undef MIN
57*01826a49SYabin Cui #define MIN(a,b) ((a) < (b) ? (a) : (b))
58*01826a49SYabin Cui
59*01826a49SYabin Cui
60*01826a49SYabin Cui /*--- Display Macros ---*/
61*01826a49SYabin Cui
62*01826a49SYabin Cui #define DISPLAY(...) fprintf(stdout, __VA_ARGS__)
63*01826a49SYabin Cui #define DISPLAYLEVEL(l, ...) { if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } }
64*01826a49SYabin Cui static int g_displayLevel = DISPLAY_LEVEL_DEFAULT; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */
65*01826a49SYabin Cui
66*01826a49SYabin Cui
67*01826a49SYabin Cui /*--- buffer_t ---*/
68*01826a49SYabin Cui
69*01826a49SYabin Cui typedef struct {
70*01826a49SYabin Cui void* ptr;
71*01826a49SYabin Cui size_t size;
72*01826a49SYabin Cui size_t capacity;
73*01826a49SYabin Cui } buffer_t;
74*01826a49SYabin Cui
75*01826a49SYabin Cui static const buffer_t kBuffNull = { NULL, 0, 0 };
76*01826a49SYabin Cui
77*01826a49SYabin Cui /* @return : kBuffNull if any error */
createBuffer(size_t capacity)78*01826a49SYabin Cui static buffer_t createBuffer(size_t capacity)
79*01826a49SYabin Cui {
80*01826a49SYabin Cui assert(capacity > 0);
81*01826a49SYabin Cui void* const ptr = malloc(capacity);
82*01826a49SYabin Cui if (ptr==NULL) return kBuffNull;
83*01826a49SYabin Cui
84*01826a49SYabin Cui buffer_t buffer;
85*01826a49SYabin Cui buffer.ptr = ptr;
86*01826a49SYabin Cui buffer.capacity = capacity;
87*01826a49SYabin Cui buffer.size = 0;
88*01826a49SYabin Cui return buffer;
89*01826a49SYabin Cui }
90*01826a49SYabin Cui
freeBuffer(buffer_t buff)91*01826a49SYabin Cui static void freeBuffer(buffer_t buff)
92*01826a49SYabin Cui {
93*01826a49SYabin Cui free(buff.ptr);
94*01826a49SYabin Cui }
95*01826a49SYabin Cui
96*01826a49SYabin Cui
fillBuffer_fromHandle(buffer_t * buff,FILE * f)97*01826a49SYabin Cui static void fillBuffer_fromHandle(buffer_t* buff, FILE* f)
98*01826a49SYabin Cui {
99*01826a49SYabin Cui size_t const readSize = fread(buff->ptr, 1, buff->capacity, f);
100*01826a49SYabin Cui buff->size = readSize;
101*01826a49SYabin Cui }
102*01826a49SYabin Cui
103*01826a49SYabin Cui
104*01826a49SYabin Cui /* @return : kBuffNull if any error */
createBuffer_fromFile(const char * fileName)105*01826a49SYabin Cui static buffer_t createBuffer_fromFile(const char* fileName)
106*01826a49SYabin Cui {
107*01826a49SYabin Cui U64 const fileSize = UTIL_getFileSize(fileName);
108*01826a49SYabin Cui size_t const bufferSize = (size_t) fileSize;
109*01826a49SYabin Cui
110*01826a49SYabin Cui if (fileSize == UTIL_FILESIZE_UNKNOWN) return kBuffNull;
111*01826a49SYabin Cui assert((U64)bufferSize == fileSize); /* check overflow */
112*01826a49SYabin Cui
113*01826a49SYabin Cui { FILE* const f = fopen(fileName, "rb");
114*01826a49SYabin Cui if (f == NULL) return kBuffNull;
115*01826a49SYabin Cui
116*01826a49SYabin Cui buffer_t buff = createBuffer(bufferSize);
117*01826a49SYabin Cui CONTROL(buff.ptr != NULL);
118*01826a49SYabin Cui
119*01826a49SYabin Cui fillBuffer_fromHandle(&buff, f);
120*01826a49SYabin Cui CONTROL(buff.size == buff.capacity);
121*01826a49SYabin Cui
122*01826a49SYabin Cui fclose(f); /* do nothing specific if fclose() fails */
123*01826a49SYabin Cui return buff;
124*01826a49SYabin Cui }
125*01826a49SYabin Cui }
126*01826a49SYabin Cui
127*01826a49SYabin Cui
128*01826a49SYabin Cui /* @return : kBuffNull if any error */
129*01826a49SYabin Cui static buffer_t
createDictionaryBuffer(const char * dictionaryName,const void * srcBuffer,const size_t * srcBlockSizes,size_t nbBlocks,size_t requestedDictSize)130*01826a49SYabin Cui createDictionaryBuffer(const char* dictionaryName,
131*01826a49SYabin Cui const void* srcBuffer,
132*01826a49SYabin Cui const size_t* srcBlockSizes, size_t nbBlocks,
133*01826a49SYabin Cui size_t requestedDictSize)
134*01826a49SYabin Cui {
135*01826a49SYabin Cui if (dictionaryName) {
136*01826a49SYabin Cui DISPLAYLEVEL(3, "loading dictionary %s \n", dictionaryName);
137*01826a49SYabin Cui return createBuffer_fromFile(dictionaryName); /* note : result might be kBuffNull */
138*01826a49SYabin Cui
139*01826a49SYabin Cui } else {
140*01826a49SYabin Cui
141*01826a49SYabin Cui DISPLAYLEVEL(3, "creating dictionary, of target size %u bytes \n",
142*01826a49SYabin Cui (unsigned)requestedDictSize);
143*01826a49SYabin Cui void* const dictBuffer = malloc(requestedDictSize);
144*01826a49SYabin Cui CONTROL(dictBuffer != NULL);
145*01826a49SYabin Cui
146*01826a49SYabin Cui assert(nbBlocks <= UINT_MAX);
147*01826a49SYabin Cui size_t const dictSize = ZDICT_trainFromBuffer(dictBuffer, requestedDictSize,
148*01826a49SYabin Cui srcBuffer,
149*01826a49SYabin Cui srcBlockSizes, (unsigned)nbBlocks);
150*01826a49SYabin Cui CONTROL(!ZSTD_isError(dictSize));
151*01826a49SYabin Cui
152*01826a49SYabin Cui buffer_t result;
153*01826a49SYabin Cui result.ptr = dictBuffer;
154*01826a49SYabin Cui result.capacity = requestedDictSize;
155*01826a49SYabin Cui result.size = dictSize;
156*01826a49SYabin Cui return result;
157*01826a49SYabin Cui }
158*01826a49SYabin Cui }
159*01826a49SYabin Cui
160*01826a49SYabin Cui /*! BMK_loadFiles() :
161*01826a49SYabin Cui * Loads `buffer`, with content from files listed within `fileNamesTable`.
162*01826a49SYabin Cui * Fills `buffer` entirely.
163*01826a49SYabin Cui * @return : 0 on success, !=0 on error */
loadFiles(void * buffer,size_t bufferSize,size_t * fileSizes,const char * const * fileNamesTable,unsigned nbFiles)164*01826a49SYabin Cui static int loadFiles(void* buffer, size_t bufferSize,
165*01826a49SYabin Cui size_t* fileSizes,
166*01826a49SYabin Cui const char* const * fileNamesTable, unsigned nbFiles)
167*01826a49SYabin Cui {
168*01826a49SYabin Cui size_t pos = 0, totalSize = 0;
169*01826a49SYabin Cui
170*01826a49SYabin Cui for (unsigned n=0; n<nbFiles; n++) {
171*01826a49SYabin Cui U64 fileSize = UTIL_getFileSize(fileNamesTable[n]);
172*01826a49SYabin Cui if (UTIL_isDirectory(fileNamesTable[n])) {
173*01826a49SYabin Cui fileSizes[n] = 0;
174*01826a49SYabin Cui continue;
175*01826a49SYabin Cui }
176*01826a49SYabin Cui if (fileSize == UTIL_FILESIZE_UNKNOWN) {
177*01826a49SYabin Cui fileSizes[n] = 0;
178*01826a49SYabin Cui continue;
179*01826a49SYabin Cui }
180*01826a49SYabin Cui
181*01826a49SYabin Cui FILE* const f = fopen(fileNamesTable[n], "rb");
182*01826a49SYabin Cui assert(f!=NULL);
183*01826a49SYabin Cui
184*01826a49SYabin Cui assert(pos <= bufferSize);
185*01826a49SYabin Cui assert(fileSize <= bufferSize - pos);
186*01826a49SYabin Cui
187*01826a49SYabin Cui { size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f);
188*01826a49SYabin Cui assert(readSize == fileSize);
189*01826a49SYabin Cui pos += readSize;
190*01826a49SYabin Cui }
191*01826a49SYabin Cui fileSizes[n] = (size_t)fileSize;
192*01826a49SYabin Cui totalSize += (size_t)fileSize;
193*01826a49SYabin Cui fclose(f);
194*01826a49SYabin Cui }
195*01826a49SYabin Cui
196*01826a49SYabin Cui assert(totalSize == bufferSize);
197*01826a49SYabin Cui return 0;
198*01826a49SYabin Cui }
199*01826a49SYabin Cui
200*01826a49SYabin Cui
201*01826a49SYabin Cui
202*01826a49SYabin Cui /*--- slice_collection_t ---*/
203*01826a49SYabin Cui
204*01826a49SYabin Cui typedef struct {
205*01826a49SYabin Cui void** slicePtrs;
206*01826a49SYabin Cui size_t* capacities;
207*01826a49SYabin Cui size_t nbSlices;
208*01826a49SYabin Cui } slice_collection_t;
209*01826a49SYabin Cui
210*01826a49SYabin Cui static const slice_collection_t kNullCollection = { NULL, NULL, 0 };
211*01826a49SYabin Cui
freeSliceCollection(slice_collection_t collection)212*01826a49SYabin Cui static void freeSliceCollection(slice_collection_t collection)
213*01826a49SYabin Cui {
214*01826a49SYabin Cui free(collection.slicePtrs);
215*01826a49SYabin Cui free(collection.capacities);
216*01826a49SYabin Cui }
217*01826a49SYabin Cui
218*01826a49SYabin Cui /* shrinkSizes() :
219*01826a49SYabin Cui * downsizes sizes of slices within collection, according to `newSizes`.
220*01826a49SYabin Cui * every `newSizes` entry must be <= than its corresponding collection size */
shrinkSizes(slice_collection_t collection,const size_t * newSizes)221*01826a49SYabin Cui void shrinkSizes(slice_collection_t collection,
222*01826a49SYabin Cui const size_t* newSizes) /* presumed same size as collection */
223*01826a49SYabin Cui {
224*01826a49SYabin Cui size_t const nbSlices = collection.nbSlices;
225*01826a49SYabin Cui for (size_t blockNb = 0; blockNb < nbSlices; blockNb++) {
226*01826a49SYabin Cui assert(newSizes[blockNb] <= collection.capacities[blockNb]);
227*01826a49SYabin Cui collection.capacities[blockNb] = newSizes[blockNb];
228*01826a49SYabin Cui }
229*01826a49SYabin Cui }
230*01826a49SYabin Cui
231*01826a49SYabin Cui
232*01826a49SYabin Cui /* splitSlices() :
233*01826a49SYabin Cui * nbSlices : if == 0, nbSlices is automatically determined from srcSlices and blockSize.
234*01826a49SYabin Cui * otherwise, creates exactly nbSlices slices,
235*01826a49SYabin Cui * by either truncating input (when smaller)
236*01826a49SYabin Cui * or repeating input from beginning */
237*01826a49SYabin Cui static slice_collection_t
splitSlices(slice_collection_t srcSlices,size_t blockSize,size_t nbSlices)238*01826a49SYabin Cui splitSlices(slice_collection_t srcSlices, size_t blockSize, size_t nbSlices)
239*01826a49SYabin Cui {
240*01826a49SYabin Cui if (blockSize==0) blockSize = (size_t)(-1); /* means "do not cut" */
241*01826a49SYabin Cui size_t nbSrcBlocks = 0;
242*01826a49SYabin Cui for (size_t ssnb=0; ssnb < srcSlices.nbSlices; ssnb++) {
243*01826a49SYabin Cui size_t pos = 0;
244*01826a49SYabin Cui while (pos <= srcSlices.capacities[ssnb]) {
245*01826a49SYabin Cui nbSrcBlocks++;
246*01826a49SYabin Cui pos += blockSize;
247*01826a49SYabin Cui }
248*01826a49SYabin Cui }
249*01826a49SYabin Cui
250*01826a49SYabin Cui if (nbSlices == 0) nbSlices = nbSrcBlocks;
251*01826a49SYabin Cui
252*01826a49SYabin Cui void** const sliceTable = (void**)malloc(nbSlices * sizeof(*sliceTable));
253*01826a49SYabin Cui size_t* const capacities = (size_t*)malloc(nbSlices * sizeof(*capacities));
254*01826a49SYabin Cui if (sliceTable == NULL || capacities == NULL) {
255*01826a49SYabin Cui free(sliceTable);
256*01826a49SYabin Cui free(capacities);
257*01826a49SYabin Cui return kNullCollection;
258*01826a49SYabin Cui }
259*01826a49SYabin Cui
260*01826a49SYabin Cui size_t ssnb = 0;
261*01826a49SYabin Cui for (size_t sliceNb=0; sliceNb < nbSlices; ) {
262*01826a49SYabin Cui ssnb = (ssnb + 1) % srcSlices.nbSlices;
263*01826a49SYabin Cui size_t pos = 0;
264*01826a49SYabin Cui char* const ptr = (char*)srcSlices.slicePtrs[ssnb];
265*01826a49SYabin Cui while (pos < srcSlices.capacities[ssnb] && sliceNb < nbSlices) {
266*01826a49SYabin Cui size_t const size = MIN(blockSize, srcSlices.capacities[ssnb] - pos);
267*01826a49SYabin Cui sliceTable[sliceNb] = ptr + pos;
268*01826a49SYabin Cui capacities[sliceNb] = size;
269*01826a49SYabin Cui sliceNb++;
270*01826a49SYabin Cui pos += blockSize;
271*01826a49SYabin Cui }
272*01826a49SYabin Cui }
273*01826a49SYabin Cui
274*01826a49SYabin Cui slice_collection_t result;
275*01826a49SYabin Cui result.nbSlices = nbSlices;
276*01826a49SYabin Cui result.slicePtrs = sliceTable;
277*01826a49SYabin Cui result.capacities = capacities;
278*01826a49SYabin Cui return result;
279*01826a49SYabin Cui }
280*01826a49SYabin Cui
281*01826a49SYabin Cui
sliceCollection_totalCapacity(slice_collection_t sc)282*01826a49SYabin Cui static size_t sliceCollection_totalCapacity(slice_collection_t sc)
283*01826a49SYabin Cui {
284*01826a49SYabin Cui size_t totalSize = 0;
285*01826a49SYabin Cui for (size_t n=0; n<sc.nbSlices; n++)
286*01826a49SYabin Cui totalSize += sc.capacities[n];
287*01826a49SYabin Cui return totalSize;
288*01826a49SYabin Cui }
289*01826a49SYabin Cui
290*01826a49SYabin Cui
291*01826a49SYabin Cui /* --- buffer collection --- */
292*01826a49SYabin Cui
293*01826a49SYabin Cui typedef struct {
294*01826a49SYabin Cui buffer_t buffer;
295*01826a49SYabin Cui slice_collection_t slices;
296*01826a49SYabin Cui } buffer_collection_t;
297*01826a49SYabin Cui
298*01826a49SYabin Cui
freeBufferCollection(buffer_collection_t bc)299*01826a49SYabin Cui static void freeBufferCollection(buffer_collection_t bc)
300*01826a49SYabin Cui {
301*01826a49SYabin Cui freeBuffer(bc.buffer);
302*01826a49SYabin Cui freeSliceCollection(bc.slices);
303*01826a49SYabin Cui }
304*01826a49SYabin Cui
305*01826a49SYabin Cui
306*01826a49SYabin Cui static buffer_collection_t
createBufferCollection_fromSliceCollectionSizes(slice_collection_t sc)307*01826a49SYabin Cui createBufferCollection_fromSliceCollectionSizes(slice_collection_t sc)
308*01826a49SYabin Cui {
309*01826a49SYabin Cui size_t const bufferSize = sliceCollection_totalCapacity(sc);
310*01826a49SYabin Cui
311*01826a49SYabin Cui buffer_t buffer = createBuffer(bufferSize);
312*01826a49SYabin Cui CONTROL(buffer.ptr != NULL);
313*01826a49SYabin Cui
314*01826a49SYabin Cui size_t const nbSlices = sc.nbSlices;
315*01826a49SYabin Cui void** const slices = (void**)malloc(nbSlices * sizeof(*slices));
316*01826a49SYabin Cui CONTROL(slices != NULL);
317*01826a49SYabin Cui
318*01826a49SYabin Cui size_t* const capacities = (size_t*)malloc(nbSlices * sizeof(*capacities));
319*01826a49SYabin Cui CONTROL(capacities != NULL);
320*01826a49SYabin Cui
321*01826a49SYabin Cui char* const ptr = (char*)buffer.ptr;
322*01826a49SYabin Cui size_t pos = 0;
323*01826a49SYabin Cui for (size_t n=0; n < nbSlices; n++) {
324*01826a49SYabin Cui capacities[n] = sc.capacities[n];
325*01826a49SYabin Cui slices[n] = ptr + pos;
326*01826a49SYabin Cui pos += capacities[n];
327*01826a49SYabin Cui }
328*01826a49SYabin Cui
329*01826a49SYabin Cui buffer_collection_t result;
330*01826a49SYabin Cui result.buffer = buffer;
331*01826a49SYabin Cui result.slices.nbSlices = nbSlices;
332*01826a49SYabin Cui result.slices.capacities = capacities;
333*01826a49SYabin Cui result.slices.slicePtrs = slices;
334*01826a49SYabin Cui return result;
335*01826a49SYabin Cui }
336*01826a49SYabin Cui
337*01826a49SYabin Cui static buffer_collection_t
createBufferCollection_fromSliceCollection(slice_collection_t sc)338*01826a49SYabin Cui createBufferCollection_fromSliceCollection(slice_collection_t sc)
339*01826a49SYabin Cui {
340*01826a49SYabin Cui size_t const bufferSize = sliceCollection_totalCapacity(sc);
341*01826a49SYabin Cui
342*01826a49SYabin Cui buffer_t buffer = createBuffer(bufferSize);
343*01826a49SYabin Cui CONTROL(buffer.ptr != NULL);
344*01826a49SYabin Cui
345*01826a49SYabin Cui size_t const nbSlices = sc.nbSlices;
346*01826a49SYabin Cui void** const slices = (void**)malloc(nbSlices * sizeof(*slices));
347*01826a49SYabin Cui CONTROL(slices != NULL);
348*01826a49SYabin Cui
349*01826a49SYabin Cui size_t* const capacities = (size_t*)malloc(nbSlices * sizeof(*capacities));
350*01826a49SYabin Cui CONTROL(capacities != NULL);
351*01826a49SYabin Cui
352*01826a49SYabin Cui char* const ptr = (char*)buffer.ptr;
353*01826a49SYabin Cui size_t pos = 0;
354*01826a49SYabin Cui for (size_t n=0; n < nbSlices; n++) {
355*01826a49SYabin Cui capacities[n] = sc.capacities[n];
356*01826a49SYabin Cui slices[n] = ptr + pos;
357*01826a49SYabin Cui pos += capacities[n];
358*01826a49SYabin Cui }
359*01826a49SYabin Cui
360*01826a49SYabin Cui for (size_t i = 0; i < nbSlices; i++) {
361*01826a49SYabin Cui memcpy(slices[i], sc.slicePtrs[i], sc.capacities[i]);
362*01826a49SYabin Cui capacities[i] = sc.capacities[i];
363*01826a49SYabin Cui }
364*01826a49SYabin Cui
365*01826a49SYabin Cui buffer_collection_t result;
366*01826a49SYabin Cui result.buffer = buffer;
367*01826a49SYabin Cui result.slices.nbSlices = nbSlices;
368*01826a49SYabin Cui result.slices.capacities = capacities;
369*01826a49SYabin Cui result.slices.slicePtrs = slices;
370*01826a49SYabin Cui
371*01826a49SYabin Cui return result;
372*01826a49SYabin Cui }
373*01826a49SYabin Cui
374*01826a49SYabin Cui /* @return : kBuffNull if any error */
375*01826a49SYabin Cui static buffer_collection_t
createBufferCollection_fromFiles(const char * const * fileNamesTable,unsigned nbFiles)376*01826a49SYabin Cui createBufferCollection_fromFiles(const char* const * fileNamesTable, unsigned nbFiles)
377*01826a49SYabin Cui {
378*01826a49SYabin Cui U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
379*01826a49SYabin Cui assert(totalSizeToLoad != UTIL_FILESIZE_UNKNOWN);
380*01826a49SYabin Cui assert(totalSizeToLoad <= BENCH_SIZE_MAX);
381*01826a49SYabin Cui size_t const loadedSize = (size_t)totalSizeToLoad;
382*01826a49SYabin Cui assert(loadedSize > 0);
383*01826a49SYabin Cui void* const srcBuffer = malloc(loadedSize);
384*01826a49SYabin Cui assert(srcBuffer != NULL);
385*01826a49SYabin Cui
386*01826a49SYabin Cui assert(nbFiles > 0);
387*01826a49SYabin Cui size_t* const fileSizes = (size_t*)calloc(nbFiles, sizeof(*fileSizes));
388*01826a49SYabin Cui assert(fileSizes != NULL);
389*01826a49SYabin Cui
390*01826a49SYabin Cui /* Load input buffer */
391*01826a49SYabin Cui int const errorCode = loadFiles(srcBuffer, loadedSize,
392*01826a49SYabin Cui fileSizes,
393*01826a49SYabin Cui fileNamesTable, nbFiles);
394*01826a49SYabin Cui assert(errorCode == 0);
395*01826a49SYabin Cui
396*01826a49SYabin Cui void** sliceTable = (void**)malloc(nbFiles * sizeof(*sliceTable));
397*01826a49SYabin Cui assert(sliceTable != NULL);
398*01826a49SYabin Cui
399*01826a49SYabin Cui char* const ptr = (char*)srcBuffer;
400*01826a49SYabin Cui size_t pos = 0;
401*01826a49SYabin Cui unsigned fileNb = 0;
402*01826a49SYabin Cui for ( ; (pos < loadedSize) && (fileNb < nbFiles); fileNb++) {
403*01826a49SYabin Cui sliceTable[fileNb] = ptr + pos;
404*01826a49SYabin Cui pos += fileSizes[fileNb];
405*01826a49SYabin Cui }
406*01826a49SYabin Cui assert(pos == loadedSize);
407*01826a49SYabin Cui assert(fileNb == nbFiles);
408*01826a49SYabin Cui
409*01826a49SYabin Cui
410*01826a49SYabin Cui buffer_t buffer;
411*01826a49SYabin Cui buffer.ptr = srcBuffer;
412*01826a49SYabin Cui buffer.capacity = loadedSize;
413*01826a49SYabin Cui buffer.size = loadedSize;
414*01826a49SYabin Cui
415*01826a49SYabin Cui slice_collection_t slices;
416*01826a49SYabin Cui slices.slicePtrs = sliceTable;
417*01826a49SYabin Cui slices.capacities = fileSizes;
418*01826a49SYabin Cui slices.nbSlices = nbFiles;
419*01826a49SYabin Cui
420*01826a49SYabin Cui buffer_collection_t bc;
421*01826a49SYabin Cui bc.buffer = buffer;
422*01826a49SYabin Cui bc.slices = slices;
423*01826a49SYabin Cui return bc;
424*01826a49SYabin Cui }
425*01826a49SYabin Cui
426*01826a49SYabin Cui
427*01826a49SYabin Cui
428*01826a49SYabin Cui
429*01826a49SYabin Cui /*--- ddict_collection_t ---*/
430*01826a49SYabin Cui
431*01826a49SYabin Cui typedef struct {
432*01826a49SYabin Cui ZSTD_DDict** ddicts;
433*01826a49SYabin Cui size_t nbDDict;
434*01826a49SYabin Cui } ddict_collection_t;
435*01826a49SYabin Cui
436*01826a49SYabin Cui typedef struct {
437*01826a49SYabin Cui ZSTD_CDict** cdicts;
438*01826a49SYabin Cui size_t nbCDict;
439*01826a49SYabin Cui } cdict_collection_t;
440*01826a49SYabin Cui
441*01826a49SYabin Cui static const cdict_collection_t kNullCDictCollection = { NULL, 0 };
442*01826a49SYabin Cui
freeCDictCollection(cdict_collection_t cdictc)443*01826a49SYabin Cui static void freeCDictCollection(cdict_collection_t cdictc)
444*01826a49SYabin Cui {
445*01826a49SYabin Cui for (size_t dictNb=0; dictNb < cdictc.nbCDict; dictNb++) {
446*01826a49SYabin Cui ZSTD_freeCDict(cdictc.cdicts[dictNb]);
447*01826a49SYabin Cui }
448*01826a49SYabin Cui free(cdictc.cdicts);
449*01826a49SYabin Cui }
450*01826a49SYabin Cui
451*01826a49SYabin Cui /* returns .buffers=NULL if operation fails */
createCDictCollection(const void * dictBuffer,size_t dictSize,size_t nbCDict,ZSTD_dictContentType_e dictContentType,ZSTD_CCtx_params * cctxParams)452*01826a49SYabin Cui static cdict_collection_t createCDictCollection(const void* dictBuffer, size_t dictSize, size_t nbCDict, ZSTD_dictContentType_e dictContentType, ZSTD_CCtx_params* cctxParams)
453*01826a49SYabin Cui {
454*01826a49SYabin Cui ZSTD_CDict** const cdicts = malloc(nbCDict * sizeof(ZSTD_CDict*));
455*01826a49SYabin Cui if (cdicts==NULL) return kNullCDictCollection;
456*01826a49SYabin Cui for (size_t dictNb=0; dictNb < nbCDict; dictNb++) {
457*01826a49SYabin Cui cdicts[dictNb] = ZSTD_createCDict_advanced2(dictBuffer, dictSize, DICT_LOAD_METHOD, dictContentType, cctxParams, ZSTD_defaultCMem);
458*01826a49SYabin Cui CONTROL(cdicts[dictNb] != NULL);
459*01826a49SYabin Cui }
460*01826a49SYabin Cui cdict_collection_t cdictc;
461*01826a49SYabin Cui cdictc.cdicts = cdicts;
462*01826a49SYabin Cui cdictc.nbCDict = nbCDict;
463*01826a49SYabin Cui return cdictc;
464*01826a49SYabin Cui }
465*01826a49SYabin Cui
466*01826a49SYabin Cui static const ddict_collection_t kNullDDictCollection = { NULL, 0 };
467*01826a49SYabin Cui
freeDDictCollection(ddict_collection_t ddictc)468*01826a49SYabin Cui static void freeDDictCollection(ddict_collection_t ddictc)
469*01826a49SYabin Cui {
470*01826a49SYabin Cui for (size_t dictNb=0; dictNb < ddictc.nbDDict; dictNb++) {
471*01826a49SYabin Cui ZSTD_freeDDict(ddictc.ddicts[dictNb]);
472*01826a49SYabin Cui }
473*01826a49SYabin Cui free(ddictc.ddicts);
474*01826a49SYabin Cui }
475*01826a49SYabin Cui
476*01826a49SYabin Cui /* returns .buffers=NULL if operation fails */
createDDictCollection(const void * dictBuffer,size_t dictSize,size_t nbDDict)477*01826a49SYabin Cui static ddict_collection_t createDDictCollection(const void* dictBuffer, size_t dictSize, size_t nbDDict)
478*01826a49SYabin Cui {
479*01826a49SYabin Cui ZSTD_DDict** const ddicts = malloc(nbDDict * sizeof(ZSTD_DDict*));
480*01826a49SYabin Cui assert(ddicts != NULL);
481*01826a49SYabin Cui if (ddicts==NULL) return kNullDDictCollection;
482*01826a49SYabin Cui for (size_t dictNb=0; dictNb < nbDDict; dictNb++) {
483*01826a49SYabin Cui ddicts[dictNb] = ZSTD_createDDict(dictBuffer, dictSize);
484*01826a49SYabin Cui assert(ddicts[dictNb] != NULL);
485*01826a49SYabin Cui }
486*01826a49SYabin Cui ddict_collection_t ddictc;
487*01826a49SYabin Cui ddictc.ddicts = ddicts;
488*01826a49SYabin Cui ddictc.nbDDict = nbDDict;
489*01826a49SYabin Cui return ddictc;
490*01826a49SYabin Cui }
491*01826a49SYabin Cui
492*01826a49SYabin Cui
493*01826a49SYabin Cui /* mess with addresses, so that linear scanning dictionaries != linear address scanning */
shuffleCDictionaries(cdict_collection_t dicts)494*01826a49SYabin Cui void shuffleCDictionaries(cdict_collection_t dicts)
495*01826a49SYabin Cui {
496*01826a49SYabin Cui size_t const nbDicts = dicts.nbCDict;
497*01826a49SYabin Cui for (size_t r=0; r<nbDicts; r++) {
498*01826a49SYabin Cui size_t const d = (size_t)rand() % nbDicts;
499*01826a49SYabin Cui ZSTD_CDict* tmpd = dicts.cdicts[d];
500*01826a49SYabin Cui dicts.cdicts[d] = dicts.cdicts[r];
501*01826a49SYabin Cui dicts.cdicts[r] = tmpd;
502*01826a49SYabin Cui }
503*01826a49SYabin Cui for (size_t r=0; r<nbDicts; r++) {
504*01826a49SYabin Cui size_t const d1 = (size_t)rand() % nbDicts;
505*01826a49SYabin Cui size_t const d2 = (size_t)rand() % nbDicts;
506*01826a49SYabin Cui ZSTD_CDict* tmpd = dicts.cdicts[d1];
507*01826a49SYabin Cui dicts.cdicts[d1] = dicts.cdicts[d2];
508*01826a49SYabin Cui dicts.cdicts[d2] = tmpd;
509*01826a49SYabin Cui }
510*01826a49SYabin Cui }
511*01826a49SYabin Cui
512*01826a49SYabin Cui /* mess with addresses, so that linear scanning dictionaries != linear address scanning */
shuffleDDictionaries(ddict_collection_t dicts)513*01826a49SYabin Cui void shuffleDDictionaries(ddict_collection_t dicts)
514*01826a49SYabin Cui {
515*01826a49SYabin Cui size_t const nbDicts = dicts.nbDDict;
516*01826a49SYabin Cui for (size_t r=0; r<nbDicts; r++) {
517*01826a49SYabin Cui size_t const d = (size_t)rand() % nbDicts;
518*01826a49SYabin Cui ZSTD_DDict* tmpd = dicts.ddicts[d];
519*01826a49SYabin Cui dicts.ddicts[d] = dicts.ddicts[r];
520*01826a49SYabin Cui dicts.ddicts[r] = tmpd;
521*01826a49SYabin Cui }
522*01826a49SYabin Cui for (size_t r=0; r<nbDicts; r++) {
523*01826a49SYabin Cui size_t const d1 = (size_t)rand() % nbDicts;
524*01826a49SYabin Cui size_t const d2 = (size_t)rand() % nbDicts;
525*01826a49SYabin Cui ZSTD_DDict* tmpd = dicts.ddicts[d1];
526*01826a49SYabin Cui dicts.ddicts[d1] = dicts.ddicts[d2];
527*01826a49SYabin Cui dicts.ddicts[d2] = tmpd;
528*01826a49SYabin Cui }
529*01826a49SYabin Cui }
530*01826a49SYabin Cui
531*01826a49SYabin Cui
532*01826a49SYabin Cui /* --- Compression --- */
533*01826a49SYabin Cui
534*01826a49SYabin Cui /* compressBlocks() :
535*01826a49SYabin Cui * @return : total compressed size of all blocks,
536*01826a49SYabin Cui * or 0 if error.
537*01826a49SYabin Cui */
compressBlocks(size_t * cSizes,slice_collection_t dstBlockBuffers,slice_collection_t srcBlockBuffers,ZSTD_CDict * cdict,int cLevel)538*01826a49SYabin Cui static size_t compressBlocks(size_t* cSizes, /* optional (can be NULL). If present, must contain at least nbBlocks fields */
539*01826a49SYabin Cui slice_collection_t dstBlockBuffers,
540*01826a49SYabin Cui slice_collection_t srcBlockBuffers,
541*01826a49SYabin Cui ZSTD_CDict* cdict, int cLevel)
542*01826a49SYabin Cui {
543*01826a49SYabin Cui size_t const nbBlocks = srcBlockBuffers.nbSlices;
544*01826a49SYabin Cui assert(dstBlockBuffers.nbSlices == srcBlockBuffers.nbSlices);
545*01826a49SYabin Cui
546*01826a49SYabin Cui ZSTD_CCtx* const cctx = ZSTD_createCCtx();
547*01826a49SYabin Cui assert(cctx != NULL);
548*01826a49SYabin Cui
549*01826a49SYabin Cui size_t totalCSize = 0;
550*01826a49SYabin Cui for (size_t blockNb=0; blockNb < nbBlocks; blockNb++) {
551*01826a49SYabin Cui size_t cBlockSize;
552*01826a49SYabin Cui if (cdict == NULL) {
553*01826a49SYabin Cui cBlockSize = ZSTD_compressCCtx(cctx,
554*01826a49SYabin Cui dstBlockBuffers.slicePtrs[blockNb], dstBlockBuffers.capacities[blockNb],
555*01826a49SYabin Cui srcBlockBuffers.slicePtrs[blockNb], srcBlockBuffers.capacities[blockNb],
556*01826a49SYabin Cui cLevel);
557*01826a49SYabin Cui } else {
558*01826a49SYabin Cui cBlockSize = ZSTD_compress_usingCDict(cctx,
559*01826a49SYabin Cui dstBlockBuffers.slicePtrs[blockNb], dstBlockBuffers.capacities[blockNb],
560*01826a49SYabin Cui srcBlockBuffers.slicePtrs[blockNb], srcBlockBuffers.capacities[blockNb],
561*01826a49SYabin Cui cdict);
562*01826a49SYabin Cui }
563*01826a49SYabin Cui CONTROL(!ZSTD_isError(cBlockSize));
564*01826a49SYabin Cui if (cSizes) cSizes[blockNb] = cBlockSize;
565*01826a49SYabin Cui totalCSize += cBlockSize;
566*01826a49SYabin Cui }
567*01826a49SYabin Cui return totalCSize;
568*01826a49SYabin Cui }
569*01826a49SYabin Cui
570*01826a49SYabin Cui
571*01826a49SYabin Cui /* --- Benchmark --- */
572*01826a49SYabin Cui
573*01826a49SYabin Cui typedef struct {
574*01826a49SYabin Cui ZSTD_CCtx* cctx;
575*01826a49SYabin Cui size_t nbDicts;
576*01826a49SYabin Cui size_t dictNb;
577*01826a49SYabin Cui cdict_collection_t dictionaries;
578*01826a49SYabin Cui } compressInstructions;
579*01826a49SYabin Cui
createCompressInstructions(cdict_collection_t dictionaries,ZSTD_CCtx_params * cctxParams)580*01826a49SYabin Cui compressInstructions createCompressInstructions(cdict_collection_t dictionaries, ZSTD_CCtx_params* cctxParams)
581*01826a49SYabin Cui {
582*01826a49SYabin Cui compressInstructions ci;
583*01826a49SYabin Cui ci.cctx = ZSTD_createCCtx();
584*01826a49SYabin Cui CONTROL(ci.cctx != NULL);
585*01826a49SYabin Cui if (cctxParams)
586*01826a49SYabin Cui ZSTD_CCtx_setParametersUsingCCtxParams(ci.cctx, cctxParams);
587*01826a49SYabin Cui ci.nbDicts = dictionaries.nbCDict;
588*01826a49SYabin Cui ci.dictNb = 0;
589*01826a49SYabin Cui ci.dictionaries = dictionaries;
590*01826a49SYabin Cui return ci;
591*01826a49SYabin Cui }
592*01826a49SYabin Cui
freeCompressInstructions(compressInstructions ci)593*01826a49SYabin Cui void freeCompressInstructions(compressInstructions ci)
594*01826a49SYabin Cui {
595*01826a49SYabin Cui ZSTD_freeCCtx(ci.cctx);
596*01826a49SYabin Cui }
597*01826a49SYabin Cui
598*01826a49SYabin Cui typedef struct {
599*01826a49SYabin Cui ZSTD_DCtx* dctx;
600*01826a49SYabin Cui size_t nbDicts;
601*01826a49SYabin Cui size_t dictNb;
602*01826a49SYabin Cui ddict_collection_t dictionaries;
603*01826a49SYabin Cui } decompressInstructions;
604*01826a49SYabin Cui
createDecompressInstructions(ddict_collection_t dictionaries)605*01826a49SYabin Cui decompressInstructions createDecompressInstructions(ddict_collection_t dictionaries)
606*01826a49SYabin Cui {
607*01826a49SYabin Cui decompressInstructions di;
608*01826a49SYabin Cui di.dctx = ZSTD_createDCtx();
609*01826a49SYabin Cui assert(di.dctx != NULL);
610*01826a49SYabin Cui di.nbDicts = dictionaries.nbDDict;
611*01826a49SYabin Cui di.dictNb = 0;
612*01826a49SYabin Cui di.dictionaries = dictionaries;
613*01826a49SYabin Cui return di;
614*01826a49SYabin Cui }
615*01826a49SYabin Cui
freeDecompressInstructions(decompressInstructions di)616*01826a49SYabin Cui void freeDecompressInstructions(decompressInstructions di)
617*01826a49SYabin Cui {
618*01826a49SYabin Cui ZSTD_freeDCtx(di.dctx);
619*01826a49SYabin Cui }
620*01826a49SYabin Cui
621*01826a49SYabin Cui /* benched function */
compress(const void * src,size_t srcSize,void * dst,size_t dstCapacity,void * payload)622*01826a49SYabin Cui size_t compress(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* payload)
623*01826a49SYabin Cui {
624*01826a49SYabin Cui compressInstructions* const ci = (compressInstructions*) payload;
625*01826a49SYabin Cui (void)dstCapacity;
626*01826a49SYabin Cui
627*01826a49SYabin Cui ZSTD_CCtx_refCDict(ci->cctx, ci->dictionaries.cdicts[ci->dictNb]);
628*01826a49SYabin Cui ZSTD_compress2(ci->cctx,
629*01826a49SYabin Cui dst, srcSize,
630*01826a49SYabin Cui src, srcSize);
631*01826a49SYabin Cui
632*01826a49SYabin Cui ci->dictNb = ci->dictNb + 1;
633*01826a49SYabin Cui if (ci->dictNb >= ci->nbDicts) ci->dictNb = 0;
634*01826a49SYabin Cui
635*01826a49SYabin Cui return srcSize;
636*01826a49SYabin Cui }
637*01826a49SYabin Cui
638*01826a49SYabin Cui /* benched function */
decompress(const void * src,size_t srcSize,void * dst,size_t dstCapacity,void * payload)639*01826a49SYabin Cui size_t decompress(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* payload)
640*01826a49SYabin Cui {
641*01826a49SYabin Cui decompressInstructions* const di = (decompressInstructions*) payload;
642*01826a49SYabin Cui
643*01826a49SYabin Cui size_t const result = ZSTD_decompress_usingDDict(di->dctx,
644*01826a49SYabin Cui dst, dstCapacity,
645*01826a49SYabin Cui src, srcSize,
646*01826a49SYabin Cui di->dictionaries.ddicts[di->dictNb]);
647*01826a49SYabin Cui
648*01826a49SYabin Cui di->dictNb = di->dictNb + 1;
649*01826a49SYabin Cui if (di->dictNb >= di->nbDicts) di->dictNb = 0;
650*01826a49SYabin Cui
651*01826a49SYabin Cui return result;
652*01826a49SYabin Cui }
653*01826a49SYabin Cui
654*01826a49SYabin Cui typedef enum {
655*01826a49SYabin Cui fastest = 0,
656*01826a49SYabin Cui median = 1,
657*01826a49SYabin Cui } metricAggregatePref_e;
658*01826a49SYabin Cui
659*01826a49SYabin Cui /* compareFunction() :
660*01826a49SYabin Cui * Sort input in decreasing order when used with qsort() */
compareFunction(const void * a,const void * b)661*01826a49SYabin Cui int compareFunction(const void *a, const void *b)
662*01826a49SYabin Cui {
663*01826a49SYabin Cui double x = *(const double *)a;
664*01826a49SYabin Cui double y = *(const double *)b;
665*01826a49SYabin Cui if (x < y)
666*01826a49SYabin Cui return 1;
667*01826a49SYabin Cui else if (x > y)
668*01826a49SYabin Cui return -1;
669*01826a49SYabin Cui return 0;
670*01826a49SYabin Cui }
671*01826a49SYabin Cui
aggregateData(double * data,size_t size,metricAggregatePref_e metricAggregatePref)672*01826a49SYabin Cui double aggregateData(double *data, size_t size,
673*01826a49SYabin Cui metricAggregatePref_e metricAggregatePref)
674*01826a49SYabin Cui {
675*01826a49SYabin Cui qsort(data, size, sizeof(*data), compareFunction);
676*01826a49SYabin Cui if (metricAggregatePref == fastest)
677*01826a49SYabin Cui return data[0];
678*01826a49SYabin Cui else /* median */
679*01826a49SYabin Cui return (data[(size - 1) / 2] + data[size / 2]) / 2;
680*01826a49SYabin Cui }
681*01826a49SYabin Cui
benchMem(slice_collection_t dstBlocks,slice_collection_t srcBlocks,ddict_collection_t ddictionaries,cdict_collection_t cdictionaries,unsigned nbRounds,int benchCompression,const char * exeName,ZSTD_CCtx_params * cctxParams,metricAggregatePref_e metricAggregatePref)682*01826a49SYabin Cui static int benchMem(slice_collection_t dstBlocks, slice_collection_t srcBlocks,
683*01826a49SYabin Cui ddict_collection_t ddictionaries,
684*01826a49SYabin Cui cdict_collection_t cdictionaries, unsigned nbRounds,
685*01826a49SYabin Cui int benchCompression, const char *exeName,
686*01826a49SYabin Cui ZSTD_CCtx_params *cctxParams,
687*01826a49SYabin Cui metricAggregatePref_e metricAggregatePref)
688*01826a49SYabin Cui {
689*01826a49SYabin Cui assert(dstBlocks.nbSlices == srcBlocks.nbSlices);
690*01826a49SYabin Cui if (benchCompression) assert(cctxParams);
691*01826a49SYabin Cui
692*01826a49SYabin Cui unsigned const ms_per_round = RUN_TIME_DEFAULT_MS;
693*01826a49SYabin Cui unsigned const total_time_ms = nbRounds * ms_per_round;
694*01826a49SYabin Cui
695*01826a49SYabin Cui double *const speedPerRound = (double *)malloc(nbRounds * sizeof(double));
696*01826a49SYabin Cui
697*01826a49SYabin Cui BMK_timedFnState_t* const benchState =
698*01826a49SYabin Cui BMK_createTimedFnState(total_time_ms, ms_per_round);
699*01826a49SYabin Cui
700*01826a49SYabin Cui decompressInstructions di = createDecompressInstructions(ddictionaries);
701*01826a49SYabin Cui compressInstructions ci =
702*01826a49SYabin Cui createCompressInstructions(cdictionaries, cctxParams);
703*01826a49SYabin Cui void* payload = benchCompression ? (void*)&ci : (void*)&di;
704*01826a49SYabin Cui BMK_benchParams_t const bp = {
705*01826a49SYabin Cui .benchFn = benchCompression ? compress : decompress,
706*01826a49SYabin Cui .benchPayload = payload,
707*01826a49SYabin Cui .initFn = NULL,
708*01826a49SYabin Cui .initPayload = NULL,
709*01826a49SYabin Cui .errorFn = ZSTD_isError,
710*01826a49SYabin Cui .blockCount = dstBlocks.nbSlices,
711*01826a49SYabin Cui .srcBuffers = (const void* const*) srcBlocks.slicePtrs,
712*01826a49SYabin Cui .srcSizes = srcBlocks.capacities,
713*01826a49SYabin Cui .dstBuffers = dstBlocks.slicePtrs,
714*01826a49SYabin Cui .dstCapacities = dstBlocks.capacities,
715*01826a49SYabin Cui .blockResults = NULL
716*01826a49SYabin Cui };
717*01826a49SYabin Cui
718*01826a49SYabin Cui size_t roundNb = 0;
719*01826a49SYabin Cui for (;;) {
720*01826a49SYabin Cui BMK_runOutcome_t const outcome = BMK_benchTimedFn(benchState, bp);
721*01826a49SYabin Cui CONTROL(BMK_isSuccessful_runOutcome(outcome));
722*01826a49SYabin Cui
723*01826a49SYabin Cui BMK_runTime_t const result = BMK_extract_runTime(outcome);
724*01826a49SYabin Cui double const dTime_ns = result.nanoSecPerRun;
725*01826a49SYabin Cui double const dTime_sec = (double)dTime_ns / 1000000000;
726*01826a49SYabin Cui size_t const srcSize = result.sumOfReturn;
727*01826a49SYabin Cui double const speed_MBps = (double)srcSize / dTime_sec / (1 MB);
728*01826a49SYabin Cui speedPerRound[roundNb] = speed_MBps;
729*01826a49SYabin Cui if (benchCompression)
730*01826a49SYabin Cui DISPLAY("Compression Speed : %.1f MB/s \r", speed_MBps);
731*01826a49SYabin Cui else
732*01826a49SYabin Cui DISPLAY("Decompression Speed : %.1f MB/s \r", speed_MBps);
733*01826a49SYabin Cui
734*01826a49SYabin Cui fflush(stdout);
735*01826a49SYabin Cui if (BMK_isCompleted_TimedFn(benchState)) break;
736*01826a49SYabin Cui roundNb++;
737*01826a49SYabin Cui }
738*01826a49SYabin Cui DISPLAY("\n");
739*01826a49SYabin Cui /* BMK_benchTimedFn may not run exactly nbRounds iterations */
740*01826a49SYabin Cui double speedAggregated =
741*01826a49SYabin Cui aggregateData(speedPerRound, roundNb + 1, metricAggregatePref);
742*01826a49SYabin Cui if (metricAggregatePref == fastest)
743*01826a49SYabin Cui DISPLAY("Fastest Speed : %.1f MB/s \n", speedAggregated);
744*01826a49SYabin Cui else
745*01826a49SYabin Cui DISPLAY("Median Speed : %.1f MB/s \n", speedAggregated);
746*01826a49SYabin Cui
747*01826a49SYabin Cui char* csvFileName = malloc(strlen(exeName) + 5);
748*01826a49SYabin Cui strcpy(csvFileName, exeName);
749*01826a49SYabin Cui strcat(csvFileName, ".csv");
750*01826a49SYabin Cui FILE* csvFile = fopen(csvFileName, "r");
751*01826a49SYabin Cui if (!csvFile) {
752*01826a49SYabin Cui csvFile = fopen(csvFileName, "wt");
753*01826a49SYabin Cui assert(csvFile);
754*01826a49SYabin Cui fprintf(csvFile, "%s\n", exeName);
755*01826a49SYabin Cui /* Print table headers */
756*01826a49SYabin Cui fprintf(
757*01826a49SYabin Cui csvFile,
758*01826a49SYabin Cui "Compression/Decompression,Level,nbDicts,dictAttachPref,metricAggregatePref,Speed\n");
759*01826a49SYabin Cui } else {
760*01826a49SYabin Cui fclose(csvFile);
761*01826a49SYabin Cui csvFile = fopen(csvFileName, "at");
762*01826a49SYabin Cui assert(csvFile);
763*01826a49SYabin Cui }
764*01826a49SYabin Cui
765*01826a49SYabin Cui int cLevel = -1;
766*01826a49SYabin Cui int dictAttachPref = -1;
767*01826a49SYabin Cui if (benchCompression) {
768*01826a49SYabin Cui ZSTD_CCtxParams_getParameter(cctxParams, ZSTD_c_compressionLevel,
769*01826a49SYabin Cui &cLevel);
770*01826a49SYabin Cui ZSTD_CCtxParams_getParameter(cctxParams, ZSTD_c_forceAttachDict,
771*01826a49SYabin Cui &dictAttachPref);
772*01826a49SYabin Cui }
773*01826a49SYabin Cui fprintf(csvFile, "%s,%d,%ld,%d,%d,%.1f\n",
774*01826a49SYabin Cui benchCompression ? "Compression" : "Decompression", cLevel,
775*01826a49SYabin Cui benchCompression ? ci.nbDicts : di.nbDicts, dictAttachPref,
776*01826a49SYabin Cui metricAggregatePref, speedAggregated);
777*01826a49SYabin Cui fclose(csvFile);
778*01826a49SYabin Cui free(csvFileName);
779*01826a49SYabin Cui
780*01826a49SYabin Cui freeDecompressInstructions(di);
781*01826a49SYabin Cui freeCompressInstructions(ci);
782*01826a49SYabin Cui BMK_freeTimedFnState(benchState);
783*01826a49SYabin Cui
784*01826a49SYabin Cui return 0; /* success */
785*01826a49SYabin Cui }
786*01826a49SYabin Cui
787*01826a49SYabin Cui
788*01826a49SYabin Cui /*! bench() :
789*01826a49SYabin Cui * fileName : file to load for benchmarking purpose
790*01826a49SYabin Cui * dictionary : optional (can be NULL), file to load as dictionary,
791*01826a49SYabin Cui * if none provided : will be calculated on the fly by the program.
792*01826a49SYabin Cui * @return : 0 is success, 1+ otherwise */
bench(const char ** fileNameTable,unsigned nbFiles,const char * dictionary,size_t blockSize,int clevel,unsigned nbDictMax,unsigned nbBlocks,unsigned nbRounds,int benchCompression,ZSTD_dictContentType_e dictContentType,ZSTD_CCtx_params * cctxParams,const char * exeName,metricAggregatePref_e metricAggregatePref)793*01826a49SYabin Cui int bench(const char **fileNameTable, unsigned nbFiles, const char *dictionary,
794*01826a49SYabin Cui size_t blockSize, int clevel, unsigned nbDictMax, unsigned nbBlocks,
795*01826a49SYabin Cui unsigned nbRounds, int benchCompression,
796*01826a49SYabin Cui ZSTD_dictContentType_e dictContentType, ZSTD_CCtx_params *cctxParams,
797*01826a49SYabin Cui const char *exeName, metricAggregatePref_e metricAggregatePref)
798*01826a49SYabin Cui {
799*01826a49SYabin Cui int result = 0;
800*01826a49SYabin Cui
801*01826a49SYabin Cui DISPLAYLEVEL(3, "loading %u files... \n", nbFiles);
802*01826a49SYabin Cui buffer_collection_t const srcs = createBufferCollection_fromFiles(fileNameTable, nbFiles);
803*01826a49SYabin Cui CONTROL(srcs.buffer.ptr != NULL);
804*01826a49SYabin Cui buffer_t srcBuffer = srcs.buffer;
805*01826a49SYabin Cui size_t const srcSize = srcBuffer.size;
806*01826a49SYabin Cui DISPLAYLEVEL(3, "created src buffer of size %.1f MB \n",
807*01826a49SYabin Cui (double)srcSize / (1 MB));
808*01826a49SYabin Cui
809*01826a49SYabin Cui slice_collection_t const srcSlices = splitSlices(srcs.slices, blockSize, nbBlocks);
810*01826a49SYabin Cui nbBlocks = (unsigned)(srcSlices.nbSlices);
811*01826a49SYabin Cui DISPLAYLEVEL(3, "split input into %u blocks ", nbBlocks);
812*01826a49SYabin Cui if (blockSize)
813*01826a49SYabin Cui DISPLAYLEVEL(3, "of max size %u bytes ", (unsigned)blockSize);
814*01826a49SYabin Cui DISPLAYLEVEL(3, "\n");
815*01826a49SYabin Cui size_t const totalSrcSlicesSize = sliceCollection_totalCapacity(srcSlices);
816*01826a49SYabin Cui
817*01826a49SYabin Cui
818*01826a49SYabin Cui size_t* const dstCapacities = malloc(nbBlocks * sizeof(*dstCapacities));
819*01826a49SYabin Cui CONTROL(dstCapacities != NULL);
820*01826a49SYabin Cui size_t dstBufferCapacity = 0;
821*01826a49SYabin Cui for (size_t bnb=0; bnb<nbBlocks; bnb++) {
822*01826a49SYabin Cui dstCapacities[bnb] = ZSTD_compressBound(srcSlices.capacities[bnb]);
823*01826a49SYabin Cui dstBufferCapacity += dstCapacities[bnb];
824*01826a49SYabin Cui }
825*01826a49SYabin Cui
826*01826a49SYabin Cui buffer_t dstBuffer = createBuffer(dstBufferCapacity);
827*01826a49SYabin Cui CONTROL(dstBuffer.ptr != NULL);
828*01826a49SYabin Cui
829*01826a49SYabin Cui void** const sliceTable = malloc(nbBlocks * sizeof(*sliceTable));
830*01826a49SYabin Cui CONTROL(sliceTable != NULL);
831*01826a49SYabin Cui
832*01826a49SYabin Cui { char* const ptr = dstBuffer.ptr;
833*01826a49SYabin Cui size_t pos = 0;
834*01826a49SYabin Cui for (size_t snb=0; snb < nbBlocks; snb++) {
835*01826a49SYabin Cui sliceTable[snb] = ptr + pos;
836*01826a49SYabin Cui pos += dstCapacities[snb];
837*01826a49SYabin Cui } }
838*01826a49SYabin Cui
839*01826a49SYabin Cui slice_collection_t dstSlices;
840*01826a49SYabin Cui dstSlices.capacities = dstCapacities;
841*01826a49SYabin Cui dstSlices.slicePtrs = sliceTable;
842*01826a49SYabin Cui dstSlices.nbSlices = nbBlocks;
843*01826a49SYabin Cui
844*01826a49SYabin Cui
845*01826a49SYabin Cui /* dictionary determination */
846*01826a49SYabin Cui buffer_t const dictBuffer = createDictionaryBuffer(dictionary,
847*01826a49SYabin Cui srcs.buffer.ptr,
848*01826a49SYabin Cui srcSlices.capacities, srcSlices.nbSlices,
849*01826a49SYabin Cui DICTSIZE);
850*01826a49SYabin Cui CONTROL(dictBuffer.ptr != NULL);
851*01826a49SYabin Cui
852*01826a49SYabin Cui ZSTD_CDict* const cdict = ZSTD_createCDict_advanced2(dictBuffer.ptr, dictBuffer.size, DICT_LOAD_METHOD, dictContentType, cctxParams, ZSTD_defaultCMem);
853*01826a49SYabin Cui CONTROL(cdict != NULL);
854*01826a49SYabin Cui
855*01826a49SYabin Cui size_t const cTotalSizeNoDict = compressBlocks(NULL, dstSlices, srcSlices, NULL, clevel);
856*01826a49SYabin Cui CONTROL(cTotalSizeNoDict != 0);
857*01826a49SYabin Cui DISPLAYLEVEL(3, "compressing at level %u without dictionary : Ratio=%.2f (%u bytes) \n",
858*01826a49SYabin Cui clevel,
859*01826a49SYabin Cui (double)totalSrcSlicesSize / (double)cTotalSizeNoDict, (unsigned)cTotalSizeNoDict);
860*01826a49SYabin Cui
861*01826a49SYabin Cui size_t* const cSizes = malloc(nbBlocks * sizeof(size_t));
862*01826a49SYabin Cui CONTROL(cSizes != NULL);
863*01826a49SYabin Cui
864*01826a49SYabin Cui size_t const cTotalSize = compressBlocks(cSizes, dstSlices, srcSlices, cdict, clevel);
865*01826a49SYabin Cui CONTROL(cTotalSize != 0);
866*01826a49SYabin Cui DISPLAYLEVEL(3, "compressed using a %u bytes dictionary : Ratio=%.2f (%u bytes) \n",
867*01826a49SYabin Cui (unsigned)dictBuffer.size,
868*01826a49SYabin Cui (double)totalSrcSlicesSize / (double)cTotalSize, (unsigned)cTotalSize);
869*01826a49SYabin Cui
870*01826a49SYabin Cui /* now dstSlices contain the real compressed size of each block, instead of the maximum capacity */
871*01826a49SYabin Cui shrinkSizes(dstSlices, cSizes);
872*01826a49SYabin Cui
873*01826a49SYabin Cui unsigned const nbDicts = nbDictMax ? nbDictMax : nbBlocks;
874*01826a49SYabin Cui
875*01826a49SYabin Cui cdict_collection_t const cdictionaries = createCDictCollection(dictBuffer.ptr, dictBuffer.size, nbDicts, dictContentType, cctxParams);
876*01826a49SYabin Cui CONTROL(cdictionaries.cdicts != NULL);
877*01826a49SYabin Cui
878*01826a49SYabin Cui ddict_collection_t const ddictionaries = createDDictCollection(dictBuffer.ptr, dictBuffer.size, nbDicts);
879*01826a49SYabin Cui CONTROL(ddictionaries.ddicts != NULL);
880*01826a49SYabin Cui
881*01826a49SYabin Cui if (benchCompression) {
882*01826a49SYabin Cui size_t const dictMem = ZSTD_sizeof_CDict(cdictionaries.cdicts[0]);
883*01826a49SYabin Cui size_t const allDictMem = dictMem * nbDicts;
884*01826a49SYabin Cui DISPLAYLEVEL(3, "generating %u dictionaries, using %.1f MB of memory \n",
885*01826a49SYabin Cui nbDicts, (double)allDictMem / (1 MB));
886*01826a49SYabin Cui
887*01826a49SYabin Cui shuffleCDictionaries(cdictionaries);
888*01826a49SYabin Cui
889*01826a49SYabin Cui buffer_collection_t resultCollection = createBufferCollection_fromSliceCollection(srcSlices);
890*01826a49SYabin Cui CONTROL(resultCollection.buffer.ptr != NULL);
891*01826a49SYabin Cui
892*01826a49SYabin Cui result = benchMem(dstSlices, resultCollection.slices, ddictionaries,
893*01826a49SYabin Cui cdictionaries, nbRounds, benchCompression, exeName,
894*01826a49SYabin Cui cctxParams, metricAggregatePref);
895*01826a49SYabin Cui
896*01826a49SYabin Cui freeBufferCollection(resultCollection);
897*01826a49SYabin Cui } else {
898*01826a49SYabin Cui size_t const dictMem = ZSTD_estimateDDictSize(dictBuffer.size, DICT_LOAD_METHOD);
899*01826a49SYabin Cui size_t const allDictMem = dictMem * nbDicts;
900*01826a49SYabin Cui DISPLAYLEVEL(3, "generating %u dictionaries, using %.1f MB of memory \n",
901*01826a49SYabin Cui nbDicts, (double)allDictMem / (1 MB));
902*01826a49SYabin Cui
903*01826a49SYabin Cui shuffleDDictionaries(ddictionaries);
904*01826a49SYabin Cui
905*01826a49SYabin Cui buffer_collection_t resultCollection = createBufferCollection_fromSliceCollectionSizes(srcSlices);
906*01826a49SYabin Cui CONTROL(resultCollection.buffer.ptr != NULL);
907*01826a49SYabin Cui
908*01826a49SYabin Cui result = benchMem(resultCollection.slices, dstSlices, ddictionaries,
909*01826a49SYabin Cui cdictionaries, nbRounds, benchCompression, exeName,
910*01826a49SYabin Cui NULL, metricAggregatePref);
911*01826a49SYabin Cui
912*01826a49SYabin Cui freeBufferCollection(resultCollection);
913*01826a49SYabin Cui }
914*01826a49SYabin Cui
915*01826a49SYabin Cui /* free all heap objects in reverse order */
916*01826a49SYabin Cui freeCDictCollection(cdictionaries);
917*01826a49SYabin Cui freeDDictCollection(ddictionaries);
918*01826a49SYabin Cui free(cSizes);
919*01826a49SYabin Cui ZSTD_freeCDict(cdict);
920*01826a49SYabin Cui freeBuffer(dictBuffer);
921*01826a49SYabin Cui freeSliceCollection(dstSlices);
922*01826a49SYabin Cui freeBuffer(dstBuffer);
923*01826a49SYabin Cui freeSliceCollection(srcSlices);
924*01826a49SYabin Cui freeBufferCollection(srcs);
925*01826a49SYabin Cui
926*01826a49SYabin Cui return result;
927*01826a49SYabin Cui }
928*01826a49SYabin Cui
929*01826a49SYabin Cui
930*01826a49SYabin Cui
931*01826a49SYabin Cui /* --- Command Line --- */
932*01826a49SYabin Cui
933*01826a49SYabin Cui /*! readU32FromChar() :
934*01826a49SYabin Cui * @return : unsigned integer value read from input in `char` format.
935*01826a49SYabin Cui * allows and interprets K, KB, KiB, M, MB and MiB suffix.
936*01826a49SYabin Cui * Will also modify `*stringPtr`, advancing it to position where it stopped reading.
937*01826a49SYabin Cui * Note : function will exit() program if digit sequence overflows */
readU32FromChar(const char ** stringPtr)938*01826a49SYabin Cui static unsigned readU32FromChar(const char** stringPtr)
939*01826a49SYabin Cui {
940*01826a49SYabin Cui unsigned result = 0;
941*01826a49SYabin Cui while ((**stringPtr >='0') && (**stringPtr <='9')) {
942*01826a49SYabin Cui unsigned const max = (((unsigned)(-1)) / 10) - 1;
943*01826a49SYabin Cui assert(result <= max); /* check overflow */
944*01826a49SYabin Cui result *= 10, result += (unsigned)**stringPtr - '0', (*stringPtr)++ ;
945*01826a49SYabin Cui }
946*01826a49SYabin Cui if ((**stringPtr=='K') || (**stringPtr=='M')) {
947*01826a49SYabin Cui unsigned const maxK = ((unsigned)(-1)) >> 10;
948*01826a49SYabin Cui assert(result <= maxK); /* check overflow */
949*01826a49SYabin Cui result <<= 10;
950*01826a49SYabin Cui if (**stringPtr=='M') {
951*01826a49SYabin Cui assert(result <= maxK); /* check overflow */
952*01826a49SYabin Cui result <<= 10;
953*01826a49SYabin Cui }
954*01826a49SYabin Cui (*stringPtr)++; /* skip `K` or `M` */
955*01826a49SYabin Cui if (**stringPtr=='i') (*stringPtr)++;
956*01826a49SYabin Cui if (**stringPtr=='B') (*stringPtr)++;
957*01826a49SYabin Cui }
958*01826a49SYabin Cui return result;
959*01826a49SYabin Cui }
960*01826a49SYabin Cui
961*01826a49SYabin Cui /** longCommandWArg() :
962*01826a49SYabin Cui * check if *stringPtr is the same as longCommand.
963*01826a49SYabin Cui * If yes, @return 1 and advances *stringPtr to the position which immediately follows longCommand.
964*01826a49SYabin Cui * @return 0 and doesn't modify *stringPtr otherwise.
965*01826a49SYabin Cui */
longCommandWArg(const char ** stringPtr,const char * longCommand)966*01826a49SYabin Cui static int longCommandWArg(const char** stringPtr, const char* longCommand)
967*01826a49SYabin Cui {
968*01826a49SYabin Cui size_t const comSize = strlen(longCommand);
969*01826a49SYabin Cui int const result = !strncmp(*stringPtr, longCommand, comSize);
970*01826a49SYabin Cui if (result) *stringPtr += comSize;
971*01826a49SYabin Cui return result;
972*01826a49SYabin Cui }
973*01826a49SYabin Cui
974*01826a49SYabin Cui
usage(const char * exeName)975*01826a49SYabin Cui int usage(const char* exeName)
976*01826a49SYabin Cui {
977*01826a49SYabin Cui DISPLAY (" \n");
978*01826a49SYabin Cui DISPLAY (" %s [Options] filename(s) \n", exeName);
979*01826a49SYabin Cui DISPLAY (" \n");
980*01826a49SYabin Cui DISPLAY ("Options : \n");
981*01826a49SYabin Cui DISPLAY ("-z : benchmark compression (default) \n");
982*01826a49SYabin Cui DISPLAY ("-d : benchmark decompression \n");
983*01826a49SYabin Cui DISPLAY ("-r : recursively load all files in subdirectories (default: off) \n");
984*01826a49SYabin Cui DISPLAY ("-B# : split input into blocks of size # (default: no split) \n");
985*01826a49SYabin Cui DISPLAY ("-# : use compression level # (default: %u) \n", CLEVEL_DEFAULT);
986*01826a49SYabin Cui DISPLAY ("-D # : use # as a dictionary (default: create one) \n");
987*01826a49SYabin Cui DISPLAY ("-i# : nb benchmark rounds (default: %u) \n", BENCH_TIME_DEFAULT_S);
988*01826a49SYabin Cui DISPLAY ("-p# : print speed for all rounds 0=fastest 1=median (default: 0) \n");
989*01826a49SYabin Cui DISPLAY ("--nbBlocks=#: use # blocks for bench (default: one per file) \n");
990*01826a49SYabin Cui DISPLAY ("--nbDicts=# : create # dictionaries for bench (default: one per block) \n");
991*01826a49SYabin Cui DISPLAY ("-h : help (this text) \n");
992*01826a49SYabin Cui DISPLAY (" \n");
993*01826a49SYabin Cui DISPLAY ("Advanced Options (see zstd.h for documentation) : \n");
994*01826a49SYabin Cui DISPLAY ("--dedicated-dict-search\n");
995*01826a49SYabin Cui DISPLAY ("--dict-content-type=#\n");
996*01826a49SYabin Cui DISPLAY ("--dict-attach-pref=#\n");
997*01826a49SYabin Cui return 0;
998*01826a49SYabin Cui }
999*01826a49SYabin Cui
bad_usage(const char * exeName)1000*01826a49SYabin Cui int bad_usage(const char* exeName)
1001*01826a49SYabin Cui {
1002*01826a49SYabin Cui DISPLAY (" bad usage : \n");
1003*01826a49SYabin Cui usage(exeName);
1004*01826a49SYabin Cui return 1;
1005*01826a49SYabin Cui }
1006*01826a49SYabin Cui
main(int argc,const char ** argv)1007*01826a49SYabin Cui int main (int argc, const char** argv)
1008*01826a49SYabin Cui {
1009*01826a49SYabin Cui int recursiveMode = 0;
1010*01826a49SYabin Cui int benchCompression = 1;
1011*01826a49SYabin Cui int dedicatedDictSearch = 0;
1012*01826a49SYabin Cui unsigned nbRounds = BENCH_TIME_DEFAULT_S;
1013*01826a49SYabin Cui const char* const exeName = argv[0];
1014*01826a49SYabin Cui
1015*01826a49SYabin Cui if (argc < 2) return bad_usage(exeName);
1016*01826a49SYabin Cui
1017*01826a49SYabin Cui const char** nameTable = (const char**)malloc((size_t)argc * sizeof(const char*));
1018*01826a49SYabin Cui assert(nameTable != NULL);
1019*01826a49SYabin Cui unsigned nameIdx = 0;
1020*01826a49SYabin Cui
1021*01826a49SYabin Cui const char* dictionary = NULL;
1022*01826a49SYabin Cui int cLevel = CLEVEL_DEFAULT;
1023*01826a49SYabin Cui size_t blockSize = BLOCKSIZE_DEFAULT;
1024*01826a49SYabin Cui unsigned nbDicts = 0; /* determine nbDicts automatically: 1 dictionary per block */
1025*01826a49SYabin Cui unsigned nbBlocks = 0; /* determine nbBlocks automatically, from source and blockSize */
1026*01826a49SYabin Cui ZSTD_dictContentType_e dictContentType = ZSTD_dct_auto;
1027*01826a49SYabin Cui ZSTD_dictAttachPref_e dictAttachPref = ZSTD_dictDefaultAttach;
1028*01826a49SYabin Cui ZSTD_paramSwitch_e prefetchCDictTables = ZSTD_ps_auto;
1029*01826a49SYabin Cui metricAggregatePref_e metricAggregatePref = fastest;
1030*01826a49SYabin Cui
1031*01826a49SYabin Cui for (int argNb = 1; argNb < argc ; argNb++) {
1032*01826a49SYabin Cui const char* argument = argv[argNb];
1033*01826a49SYabin Cui if (!strcmp(argument, "-h")) { free(nameTable); return usage(exeName); }
1034*01826a49SYabin Cui if (!strcmp(argument, "-d")) { benchCompression = 0; continue; }
1035*01826a49SYabin Cui if (!strcmp(argument, "-z")) { benchCompression = 1; continue; }
1036*01826a49SYabin Cui if (!strcmp(argument, "-r")) { recursiveMode = 1; continue; }
1037*01826a49SYabin Cui if (!strcmp(argument, "-D")) { argNb++; assert(argNb < argc); dictionary = argv[argNb]; continue; }
1038*01826a49SYabin Cui if (longCommandWArg(&argument, "-i")) { nbRounds = readU32FromChar(&argument); continue; }
1039*01826a49SYabin Cui if (longCommandWArg(&argument, "-p")) { metricAggregatePref = (int)readU32FromChar(&argument); continue;}
1040*01826a49SYabin Cui if (longCommandWArg(&argument, "--dictionary=")) { dictionary = argument; continue; }
1041*01826a49SYabin Cui if (longCommandWArg(&argument, "-B")) { blockSize = readU32FromChar(&argument); continue; }
1042*01826a49SYabin Cui if (longCommandWArg(&argument, "--blockSize=")) { blockSize = readU32FromChar(&argument); continue; }
1043*01826a49SYabin Cui if (longCommandWArg(&argument, "--nbDicts=")) { nbDicts = readU32FromChar(&argument); continue; }
1044*01826a49SYabin Cui if (longCommandWArg(&argument, "--nbBlocks=")) { nbBlocks = readU32FromChar(&argument); continue; }
1045*01826a49SYabin Cui if (longCommandWArg(&argument, "--clevel=")) { cLevel = (int)readU32FromChar(&argument); continue; }
1046*01826a49SYabin Cui if (longCommandWArg(&argument, "--dedicated-dict-search")) { dedicatedDictSearch = 1; continue; }
1047*01826a49SYabin Cui if (longCommandWArg(&argument, "--dict-content-type=")) { dictContentType = (int)readU32FromChar(&argument); continue; }
1048*01826a49SYabin Cui if (longCommandWArg(&argument, "--dict-attach-pref=")) { dictAttachPref = (int)readU32FromChar(&argument); continue; }
1049*01826a49SYabin Cui if (longCommandWArg(&argument, "--prefetch-cdict-tables=")) { prefetchCDictTables = (int)readU32FromChar(&argument); continue; }
1050*01826a49SYabin Cui if (longCommandWArg(&argument, "-")) { cLevel = (int)readU32FromChar(&argument); continue; }
1051*01826a49SYabin Cui /* anything that's not a command is a filename */
1052*01826a49SYabin Cui nameTable[nameIdx++] = argument;
1053*01826a49SYabin Cui }
1054*01826a49SYabin Cui
1055*01826a49SYabin Cui FileNamesTable* filenameTable;
1056*01826a49SYabin Cui
1057*01826a49SYabin Cui if (recursiveMode) {
1058*01826a49SYabin Cui #ifndef UTIL_HAS_CREATEFILELIST
1059*01826a49SYabin Cui assert(0); /* missing capability, do not run */
1060*01826a49SYabin Cui #endif
1061*01826a49SYabin Cui filenameTable = UTIL_createExpandedFNT(nameTable, nameIdx, 1 /* follow_links */);
1062*01826a49SYabin Cui } else {
1063*01826a49SYabin Cui filenameTable = UTIL_assembleFileNamesTable(nameTable, nameIdx, NULL);
1064*01826a49SYabin Cui nameTable = NULL; /* UTIL_createFileNamesTable() takes ownership of nameTable */
1065*01826a49SYabin Cui }
1066*01826a49SYabin Cui
1067*01826a49SYabin Cui ZSTD_CCtx_params* cctxParams = ZSTD_createCCtxParams();
1068*01826a49SYabin Cui ZSTD_CCtxParams_init(cctxParams, cLevel);
1069*01826a49SYabin Cui ZSTD_CCtxParams_setParameter(cctxParams, ZSTD_c_enableDedicatedDictSearch, dedicatedDictSearch);
1070*01826a49SYabin Cui ZSTD_CCtxParams_setParameter(cctxParams, ZSTD_c_nbWorkers, 0);
1071*01826a49SYabin Cui ZSTD_CCtxParams_setParameter(cctxParams, ZSTD_c_forceAttachDict, dictAttachPref);
1072*01826a49SYabin Cui ZSTD_CCtxParams_setParameter(cctxParams, ZSTD_c_prefetchCDictTables, prefetchCDictTables);
1073*01826a49SYabin Cui
1074*01826a49SYabin Cui int result =
1075*01826a49SYabin Cui bench(filenameTable->fileNames, (unsigned)filenameTable->tableSize,
1076*01826a49SYabin Cui dictionary, blockSize, cLevel, nbDicts, nbBlocks, nbRounds,
1077*01826a49SYabin Cui benchCompression, dictContentType, cctxParams, exeName,
1078*01826a49SYabin Cui metricAggregatePref);
1079*01826a49SYabin Cui
1080*01826a49SYabin Cui UTIL_freeFileNamesTable(filenameTable);
1081*01826a49SYabin Cui free(nameTable);
1082*01826a49SYabin Cui ZSTD_freeCCtxParams(cctxParams);
1083*01826a49SYabin Cui
1084*01826a49SYabin Cui return result;
1085*01826a49SYabin Cui }
1086