1 1.1 christos /* 2 1.1 christos * Copyright (c) Meta Platforms, Inc. and affiliates. 3 1.1 christos * All rights reserved. 4 1.1 christos * 5 1.1 christos * This source code is licensed under both the BSD-style license (found in the 6 1.1 christos * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 1.1 christos * in the COPYING file in the root directory of this source tree). 8 1.1 christos * You may select, at your option, one of the above-listed licenses. 9 1.1 christos */ 10 1.1 christos 11 1.1 christos 12 1.1 christos 13 1.1 christos /* ************************************** 14 1.1 christos * Compiler Warnings 15 1.1 christos ****************************************/ 16 1.1 christos #ifdef _MSC_VER 17 1.1 christos # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ 18 1.1 christos #endif 19 1.1 christos 20 1.1 christos 21 1.1 christos /*-************************************* 22 1.1 christos * Includes 23 1.1 christos ***************************************/ 24 1.1 christos #include "platform.h" /* Large Files support */ 25 1.1 christos #include "util.h" /* UTIL_getFileSize, UTIL_getTotalFileSize */ 26 1.1 christos #include <stdlib.h> /* malloc, free */ 27 1.1 christos #include <string.h> /* memset */ 28 1.1 christos #include <stdio.h> /* fprintf, fopen, ftello64 */ 29 1.1 christos #include <errno.h> /* errno */ 30 1.1 christos 31 1.1 christos #include "timefn.h" /* UTIL_time_t, UTIL_clockSpanMicro, UTIL_getTime */ 32 1.1 christos #include "../lib/common/debug.h" /* assert */ 33 1.1 christos #include "../lib/common/mem.h" /* read */ 34 1.1 christos #include "../lib/zstd_errors.h" 35 1.1 christos #include "dibio.h" 36 1.1 christos 37 1.1 christos 38 1.1 christos /*-************************************* 39 1.1 christos * Constants 40 1.1 christos ***************************************/ 41 1.1 christos #define KB *(1 <<10) 42 1.1 christos #define MB *(1 <<20) 43 1.1 christos #define GB *(1U<<30) 44 1.1 christos 45 1.1 christos #define SAMPLESIZE_MAX (128 KB) 46 1.1 christos #define MEMMULT 11 /* rough estimation : memory cost to analyze 1 byte of sample */ 47 1.1 christos #define COVER_MEMMULT 9 /* rough estimation : memory cost to analyze 1 byte of sample */ 48 1.1 christos #define FASTCOVER_MEMMULT 1 /* rough estimation : memory cost to analyze 1 byte of sample */ 49 1.1 christos static const size_t g_maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((size_t)(512 MB) << sizeof(size_t)); 50 1.1 christos 51 1.1 christos #define NOISELENGTH 32 52 1.1 christos #define MAX_SAMPLES_SIZE (2 GB) /* training dataset limited to 2GB */ 53 1.1 christos 54 1.1 christos 55 1.1 christos /*-************************************* 56 1.1 christos * Console display 57 1.1 christos ***************************************/ 58 1.1 christos #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) 59 1.1 christos #define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); } 60 1.1 christos 61 1.1 christos static const U64 g_refreshRate = SEC_TO_MICRO / 6; 62 1.1 christos static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER; 63 1.1 christos 64 1.1 christos #define DISPLAYUPDATE(l, ...) { if (displayLevel>=l) { \ 65 1.1 christos if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (displayLevel>=4)) \ 66 1.1 christos { g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \ 67 1.1 christos if (displayLevel>=4) fflush(stderr); } } } 68 1.1 christos 69 1.1 christos /*-************************************* 70 1.1 christos * Exceptions 71 1.1 christos ***************************************/ 72 1.1 christos #ifndef DEBUG 73 1.1 christos # define DEBUG 0 74 1.1 christos #endif 75 1.1 christos #define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__); 76 1.1 christos #define EXM_THROW(error, ...) \ 77 1.1 christos { \ 78 1.1 christos DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \ 79 1.1 christos DISPLAY("Error %i : ", error); \ 80 1.1 christos DISPLAY(__VA_ARGS__); \ 81 1.1 christos DISPLAY("\n"); \ 82 1.1 christos exit(error); \ 83 1.1 christos } 84 1.1 christos 85 1.1 christos 86 1.1 christos /* ******************************************************** 87 1.1 christos * Helper functions 88 1.1 christos **********************************************************/ 89 1.1 christos #undef MIN 90 1.1 christos #define MIN(a,b) ((a) < (b) ? (a) : (b)) 91 1.1 christos 92 1.1 christos /** 93 1.1 christos Returns the size of a file. 94 1.1 christos If error returns -1. 95 1.1 christos */ 96 1.1 christos static S64 DiB_getFileSize (const char * fileName) 97 1.1 christos { 98 1.1 christos U64 const fileSize = UTIL_getFileSize(fileName); 99 1.1 christos return (fileSize == UTIL_FILESIZE_UNKNOWN) ? -1 : (S64)fileSize; 100 1.1 christos } 101 1.1 christos 102 1.1 christos /* ******************************************************** 103 1.1 christos * File related operations 104 1.1 christos **********************************************************/ 105 1.1 christos /** DiB_loadFiles() : 106 1.1 christos * load samples from files listed in fileNamesTable into buffer. 107 1.1 christos * works even if buffer is too small to load all samples. 108 1.1 christos * Also provides the size of each sample into sampleSizes table 109 1.1 christos * which must be sized correctly, using DiB_fileStats(). 110 1.1 christos * @return : nb of samples effectively loaded into `buffer` 111 1.1 christos * *bufferSizePtr is modified, it provides the amount data loaded within buffer. 112 1.1 christos * sampleSizes is filled with the size of each sample. 113 1.1 christos */ 114 1.1 christos static int DiB_loadFiles( 115 1.1 christos void* buffer, size_t* bufferSizePtr, 116 1.1 christos size_t* sampleSizes, int sstSize, 117 1.1 christos const char** fileNamesTable, int nbFiles, 118 1.1 christos size_t targetChunkSize, int displayLevel ) 119 1.1 christos { 120 1.1 christos char* const buff = (char*)buffer; 121 1.1 christos size_t totalDataLoaded = 0; 122 1.1 christos int nbSamplesLoaded = 0; 123 1.1 christos int fileIndex = 0; 124 1.1 christos FILE * f = NULL; 125 1.1 christos 126 1.1 christos assert(targetChunkSize <= SAMPLESIZE_MAX); 127 1.1 christos 128 1.1 christos while ( nbSamplesLoaded < sstSize && fileIndex < nbFiles ) { 129 1.1 christos size_t fileDataLoaded; 130 1.1 christos S64 const fileSize = DiB_getFileSize(fileNamesTable[fileIndex]); 131 1.1 christos if (fileSize <= 0) { 132 1.1 christos /* skip if zero-size or file error */ 133 1.1 christos ++fileIndex; 134 1.1 christos continue; 135 1.1 christos } 136 1.1 christos 137 1.1 christos f = fopen( fileNamesTable[fileIndex], "rb"); 138 1.1 christos if (f == NULL) 139 1.1 christos EXM_THROW(10, "zstd: dictBuilder: %s %s ", fileNamesTable[fileIndex], strerror(errno)); 140 1.1 christos DISPLAYUPDATE(2, "Loading %s... \r", fileNamesTable[fileIndex]); 141 1.1 christos 142 1.1 christos /* Load the first chunk of data from the file */ 143 1.1 christos fileDataLoaded = targetChunkSize > 0 ? 144 1.1 christos (size_t)MIN(fileSize, (S64)targetChunkSize) : 145 1.1 christos (size_t)MIN(fileSize, SAMPLESIZE_MAX ); 146 1.1 christos if (totalDataLoaded + fileDataLoaded > *bufferSizePtr) 147 1.1 christos break; 148 1.1 christos if (fread( buff+totalDataLoaded, 1, fileDataLoaded, f ) != fileDataLoaded) 149 1.1 christos EXM_THROW(11, "Pb reading %s", fileNamesTable[fileIndex]); 150 1.1 christos sampleSizes[nbSamplesLoaded++] = fileDataLoaded; 151 1.1 christos totalDataLoaded += fileDataLoaded; 152 1.1 christos 153 1.1 christos /* If file-chunking is enabled, load the rest of the file as more samples */ 154 1.1 christos if (targetChunkSize > 0) { 155 1.1 christos while( (S64)fileDataLoaded < fileSize && nbSamplesLoaded < sstSize ) { 156 1.1 christos size_t const chunkSize = MIN((size_t)(fileSize-fileDataLoaded), targetChunkSize); 157 1.1 christos if (totalDataLoaded + chunkSize > *bufferSizePtr) /* buffer is full */ 158 1.1 christos break; 159 1.1 christos 160 1.1 christos if (fread( buff+totalDataLoaded, 1, chunkSize, f ) != chunkSize) 161 1.1 christos EXM_THROW(11, "Pb reading %s", fileNamesTable[fileIndex]); 162 1.1 christos sampleSizes[nbSamplesLoaded++] = chunkSize; 163 1.1 christos totalDataLoaded += chunkSize; 164 1.1 christos fileDataLoaded += chunkSize; 165 1.1 christos } 166 1.1 christos } 167 1.1 christos fileIndex += 1; 168 1.1 christos fclose(f); f = NULL; 169 1.1 christos } 170 1.1 christos if (f != NULL) 171 1.1 christos fclose(f); 172 1.1 christos 173 1.1 christos DISPLAYLEVEL(2, "\r%79s\r", ""); 174 1.1 christos DISPLAYLEVEL(4, "Loaded %d KB total training data, %d nb samples \n", 175 1.1 christos (int)(totalDataLoaded / (1 KB)), nbSamplesLoaded ); 176 1.1 christos *bufferSizePtr = totalDataLoaded; 177 1.1 christos return nbSamplesLoaded; 178 1.1 christos } 179 1.1 christos 180 1.1 christos #define DiB_rotl32(x,r) ((x << r) | (x >> (32 - r))) 181 1.1 christos static U32 DiB_rand(U32* src) 182 1.1 christos { 183 1.1 christos static const U32 prime1 = 2654435761U; 184 1.1 christos static const U32 prime2 = 2246822519U; 185 1.1 christos U32 rand32 = *src; 186 1.1 christos rand32 *= prime1; 187 1.1 christos rand32 ^= prime2; 188 1.1 christos rand32 = DiB_rotl32(rand32, 13); 189 1.1 christos *src = rand32; 190 1.1 christos return rand32 >> 5; 191 1.1 christos } 192 1.1 christos 193 1.1 christos /* DiB_shuffle() : 194 1.1 christos * shuffle a table of file names in a semi-random way 195 1.1 christos * It improves dictionary quality by reducing "locality" impact, so if sample set is very large, 196 1.1 christos * it will load random elements from it, instead of just the first ones. */ 197 1.1 christos static void DiB_shuffle(const char** fileNamesTable, unsigned nbFiles) { 198 1.1 christos U32 seed = 0xFD2FB528; 199 1.1 christos unsigned i; 200 1.1 christos if (nbFiles == 0) 201 1.1 christos return; 202 1.1 christos for (i = nbFiles - 1; i > 0; --i) { 203 1.1 christos unsigned const j = DiB_rand(&seed) % (i + 1); 204 1.1 christos const char* const tmp = fileNamesTable[j]; 205 1.1 christos fileNamesTable[j] = fileNamesTable[i]; 206 1.1 christos fileNamesTable[i] = tmp; 207 1.1 christos } 208 1.1 christos } 209 1.1 christos 210 1.1 christos 211 1.1 christos /*-******************************************************** 212 1.1 christos * Dictionary training functions 213 1.1 christos **********************************************************/ 214 1.1 christos static size_t DiB_findMaxMem(unsigned long long requiredMem) 215 1.1 christos { 216 1.1 christos size_t const step = 8 MB; 217 1.1 christos void* testmem = NULL; 218 1.1 christos 219 1.1 christos requiredMem = (((requiredMem >> 23) + 1) << 23); 220 1.1 christos requiredMem += step; 221 1.1 christos if (requiredMem > g_maxMemory) requiredMem = g_maxMemory; 222 1.1 christos 223 1.1 christos while (!testmem) { 224 1.1 christos testmem = malloc((size_t)requiredMem); 225 1.1 christos requiredMem -= step; 226 1.1 christos } 227 1.1 christos 228 1.1 christos free(testmem); 229 1.1 christos return (size_t)requiredMem; 230 1.1 christos } 231 1.1 christos 232 1.1 christos 233 1.1 christos static void DiB_fillNoise(void* buffer, size_t length) 234 1.1 christos { 235 1.1 christos unsigned const prime1 = 2654435761U; 236 1.1 christos unsigned const prime2 = 2246822519U; 237 1.1 christos unsigned acc = prime1; 238 1.1 christos size_t p=0; 239 1.1 christos 240 1.1 christos for (p=0; p<length; p++) { 241 1.1 christos acc *= prime2; 242 1.1 christos ((unsigned char*)buffer)[p] = (unsigned char)(acc >> 21); 243 1.1 christos } 244 1.1 christos } 245 1.1 christos 246 1.1 christos 247 1.1 christos static void DiB_saveDict(const char* dictFileName, 248 1.1 christos const void* buff, size_t buffSize) 249 1.1 christos { 250 1.1 christos FILE* const f = fopen(dictFileName, "wb"); 251 1.1 christos if (f==NULL) EXM_THROW(3, "cannot open %s ", dictFileName); 252 1.1 christos 253 1.1 christos { size_t const n = fwrite(buff, 1, buffSize, f); 254 1.1 christos if (n!=buffSize) EXM_THROW(4, "%s : write error", dictFileName) } 255 1.1 christos 256 1.1 christos { size_t const n = (size_t)fclose(f); 257 1.1 christos if (n!=0) EXM_THROW(5, "%s : flush error", dictFileName) } 258 1.1 christos } 259 1.1 christos 260 1.1 christos typedef struct { 261 1.1 christos S64 totalSizeToLoad; 262 1.1 christos int nbSamples; 263 1.1 christos int oneSampleTooLarge; 264 1.1 christos } fileStats; 265 1.1 christos 266 1.1 christos /*! DiB_fileStats() : 267 1.1 christos * Given a list of files, and a chunkSize (0 == no chunk, whole files) 268 1.1 christos * provides the amount of data to be loaded and the resulting nb of samples. 269 1.1 christos * This is useful primarily for allocation purpose => sample buffer, and sample sizes table. 270 1.1 christos */ 271 1.1 christos static fileStats DiB_fileStats(const char** fileNamesTable, int nbFiles, size_t chunkSize, int displayLevel) 272 1.1 christos { 273 1.1 christos fileStats fs; 274 1.1 christos int n; 275 1.1 christos memset(&fs, 0, sizeof(fs)); 276 1.1 christos 277 1.1 christos /* We assume that if chunking is requested, the chunk size is < SAMPLESIZE_MAX */ 278 1.1 christos assert( chunkSize <= SAMPLESIZE_MAX ); 279 1.1 christos 280 1.1 christos for (n=0; n<nbFiles; n++) { 281 1.1 christos S64 const fileSize = DiB_getFileSize(fileNamesTable[n]); 282 1.1 christos /* TODO: is there a minimum sample size? What if the file is 1-byte? */ 283 1.1 christos if (fileSize == 0) { 284 1.1 christos DISPLAYLEVEL(3, "Sample file '%s' has zero size, skipping...\n", fileNamesTable[n]); 285 1.1 christos continue; 286 1.1 christos } 287 1.1 christos 288 1.1 christos /* the case where we are breaking up files in sample chunks */ 289 1.1 christos if (chunkSize > 0) { 290 1.1 christos /* TODO: is there a minimum sample size? Can we have a 1-byte sample? */ 291 1.1 christos fs.nbSamples += (int)((fileSize + chunkSize-1) / chunkSize); 292 1.1 christos fs.totalSizeToLoad += fileSize; 293 1.1 christos } 294 1.1 christos else { 295 1.1 christos /* the case where one file is one sample */ 296 1.1 christos if (fileSize > SAMPLESIZE_MAX) { 297 1.1 christos /* flag excessively large sample files */ 298 1.1 christos fs.oneSampleTooLarge |= (fileSize > 2*SAMPLESIZE_MAX); 299 1.1 christos 300 1.1 christos /* Limit to the first SAMPLESIZE_MAX (128kB) of the file */ 301 1.1.1.2 christos DISPLAYLEVEL(3, "Sample file '%s' is too large, limiting to %d KB\n", 302 1.1 christos fileNamesTable[n], SAMPLESIZE_MAX / (1 KB)); 303 1.1 christos } 304 1.1 christos fs.nbSamples += 1; 305 1.1 christos fs.totalSizeToLoad += MIN(fileSize, SAMPLESIZE_MAX); 306 1.1 christos } 307 1.1 christos } 308 1.1 christos DISPLAYLEVEL(4, "Found training data %d files, %d KB, %d samples\n", nbFiles, (int)(fs.totalSizeToLoad / (1 KB)), fs.nbSamples); 309 1.1 christos return fs; 310 1.1 christos } 311 1.1 christos 312 1.1 christos int DiB_trainFromFiles(const char* dictFileName, size_t maxDictSize, 313 1.1 christos const char** fileNamesTable, int nbFiles, size_t chunkSize, 314 1.1 christos ZDICT_legacy_params_t* params, ZDICT_cover_params_t* coverParams, 315 1.1 christos ZDICT_fastCover_params_t* fastCoverParams, int optimize, unsigned memLimit) 316 1.1 christos { 317 1.1 christos fileStats fs; 318 1.1 christos size_t* sampleSizes; /* vector of sample sizes. Each sample can be up to SAMPLESIZE_MAX */ 319 1.1 christos int nbSamplesLoaded; /* nb of samples effectively loaded in srcBuffer */ 320 1.1 christos size_t loadedSize; /* total data loaded in srcBuffer for all samples */ 321 1.1 christos void* srcBuffer /* contiguous buffer with training data/samples */; 322 1.1 christos void* const dictBuffer = malloc(maxDictSize); 323 1.1 christos int result = 0; 324 1.1 christos 325 1.1 christos int const displayLevel = params ? params->zParams.notificationLevel : 326 1.1 christos coverParams ? coverParams->zParams.notificationLevel : 327 1.1 christos fastCoverParams ? fastCoverParams->zParams.notificationLevel : 0; 328 1.1 christos 329 1.1 christos /* Shuffle input files before we start assessing how much sample datA to load. 330 1.1 christos The purpose of the shuffle is to pick random samples when the sample 331 1.1 christos set is larger than what we can load in memory. */ 332 1.1 christos DISPLAYLEVEL(3, "Shuffling input files\n"); 333 1.1 christos DiB_shuffle(fileNamesTable, nbFiles); 334 1.1 christos 335 1.1 christos /* Figure out how much sample data to load with how many samples */ 336 1.1 christos fs = DiB_fileStats(fileNamesTable, nbFiles, chunkSize, displayLevel); 337 1.1 christos 338 1.1 christos { 339 1.1 christos int const memMult = params ? MEMMULT : 340 1.1 christos coverParams ? COVER_MEMMULT: 341 1.1 christos FASTCOVER_MEMMULT; 342 1.1 christos size_t const maxMem = DiB_findMaxMem(fs.totalSizeToLoad * memMult) / memMult; 343 1.1 christos /* Limit the size of the training data to the free memory */ 344 1.1 christos /* Limit the size of the training data to 2GB */ 345 1.1 christos /* TODO: there is opportunity to stop DiB_fileStats() early when the data limit is reached */ 346 1.1 christos loadedSize = (size_t)MIN( MIN((S64)maxMem, fs.totalSizeToLoad), MAX_SAMPLES_SIZE ); 347 1.1 christos if (memLimit != 0) { 348 1.1 christos DISPLAYLEVEL(2, "! Warning : setting manual memory limit for dictionary training data at %u MB \n", 349 1.1 christos (unsigned)(memLimit / (1 MB))); 350 1.1 christos loadedSize = (size_t)MIN(loadedSize, memLimit); 351 1.1 christos } 352 1.1 christos srcBuffer = malloc(loadedSize+NOISELENGTH); 353 1.1 christos sampleSizes = (size_t*)malloc(fs.nbSamples * sizeof(size_t)); 354 1.1 christos } 355 1.1 christos 356 1.1 christos /* Checks */ 357 1.1 christos if ((fs.nbSamples && !sampleSizes) || (!srcBuffer) || (!dictBuffer)) 358 1.1 christos EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */ 359 1.1 christos if (fs.oneSampleTooLarge) { 360 1.1 christos DISPLAYLEVEL(2, "! Warning : some sample(s) are very large \n"); 361 1.1 christos DISPLAYLEVEL(2, "! Note that dictionary is only useful for small samples. \n"); 362 1.1 christos DISPLAYLEVEL(2, "! As a consequence, only the first %u bytes of each sample are loaded \n", SAMPLESIZE_MAX); 363 1.1 christos } 364 1.1 christos if (fs.nbSamples < 5) { 365 1.1 christos DISPLAYLEVEL(2, "! Warning : nb of samples too low for proper processing ! \n"); 366 1.1 christos DISPLAYLEVEL(2, "! Please provide _one file per sample_. \n"); 367 1.1 christos DISPLAYLEVEL(2, "! Alternatively, split files into fixed-size blocks representative of samples, with -B# \n"); 368 1.1 christos EXM_THROW(14, "nb of samples too low"); /* we now clearly forbid this case */ 369 1.1 christos } 370 1.1 christos if (fs.totalSizeToLoad < (S64)maxDictSize * 8) { 371 1.1 christos DISPLAYLEVEL(2, "! Warning : data size of samples too small for target dictionary size \n"); 372 1.1 christos DISPLAYLEVEL(2, "! Samples should be about 100x larger than target dictionary size \n"); 373 1.1 christos } 374 1.1 christos 375 1.1 christos /* init */ 376 1.1 christos if ((S64)loadedSize < fs.totalSizeToLoad) 377 1.1 christos DISPLAYLEVEL(1, "Training samples set too large (%u MB); training on %u MB only...\n", 378 1.1 christos (unsigned)(fs.totalSizeToLoad / (1 MB)), 379 1.1 christos (unsigned)(loadedSize / (1 MB))); 380 1.1 christos 381 1.1 christos /* Load input buffer */ 382 1.1 christos nbSamplesLoaded = DiB_loadFiles( 383 1.1 christos srcBuffer, &loadedSize, sampleSizes, fs.nbSamples, fileNamesTable, 384 1.1 christos nbFiles, chunkSize, displayLevel); 385 1.1 christos 386 1.1 christos { size_t dictSize = ZSTD_error_GENERIC; 387 1.1 christos if (params) { 388 1.1 christos DiB_fillNoise((char*)srcBuffer + loadedSize, NOISELENGTH); /* guard band, for end of buffer condition */ 389 1.1 christos dictSize = ZDICT_trainFromBuffer_legacy(dictBuffer, maxDictSize, 390 1.1 christos srcBuffer, sampleSizes, nbSamplesLoaded, 391 1.1 christos *params); 392 1.1 christos } else if (coverParams) { 393 1.1 christos if (optimize) { 394 1.1 christos dictSize = ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, maxDictSize, 395 1.1 christos srcBuffer, sampleSizes, nbSamplesLoaded, 396 1.1 christos coverParams); 397 1.1 christos if (!ZDICT_isError(dictSize)) { 398 1.1 christos unsigned splitPercentage = (unsigned)(coverParams->splitPoint * 100); 399 1.1 christos DISPLAYLEVEL(2, "k=%u\nd=%u\nsteps=%u\nsplit=%u\n", coverParams->k, coverParams->d, 400 1.1 christos coverParams->steps, splitPercentage); 401 1.1 christos } 402 1.1 christos } else { 403 1.1 christos dictSize = ZDICT_trainFromBuffer_cover(dictBuffer, maxDictSize, srcBuffer, 404 1.1 christos sampleSizes, nbSamplesLoaded, *coverParams); 405 1.1 christos } 406 1.1 christos } else if (fastCoverParams != NULL) { 407 1.1 christos if (optimize) { 408 1.1 christos dictSize = ZDICT_optimizeTrainFromBuffer_fastCover(dictBuffer, maxDictSize, 409 1.1 christos srcBuffer, sampleSizes, nbSamplesLoaded, 410 1.1 christos fastCoverParams); 411 1.1 christos if (!ZDICT_isError(dictSize)) { 412 1.1 christos unsigned splitPercentage = (unsigned)(fastCoverParams->splitPoint * 100); 413 1.1 christos DISPLAYLEVEL(2, "k=%u\nd=%u\nf=%u\nsteps=%u\nsplit=%u\naccel=%u\n", fastCoverParams->k, 414 1.1 christos fastCoverParams->d, fastCoverParams->f, fastCoverParams->steps, splitPercentage, 415 1.1 christos fastCoverParams->accel); 416 1.1 christos } 417 1.1 christos } else { 418 1.1 christos dictSize = ZDICT_trainFromBuffer_fastCover(dictBuffer, maxDictSize, srcBuffer, 419 1.1 christos sampleSizes, nbSamplesLoaded, *fastCoverParams); 420 1.1 christos } 421 1.1 christos } else { 422 1.1 christos assert(0 /* Impossible */); 423 1.1 christos } 424 1.1 christos if (ZDICT_isError(dictSize)) { 425 1.1 christos DISPLAYLEVEL(1, "dictionary training failed : %s \n", ZDICT_getErrorName(dictSize)); /* should not happen */ 426 1.1 christos result = 1; 427 1.1 christos goto _cleanup; 428 1.1 christos } 429 1.1 christos /* save dict */ 430 1.1 christos DISPLAYLEVEL(2, "Save dictionary of size %u into file %s \n", (unsigned)dictSize, dictFileName); 431 1.1 christos DiB_saveDict(dictFileName, dictBuffer, dictSize); 432 1.1 christos } 433 1.1 christos 434 1.1 christos /* clean up */ 435 1.1 christos _cleanup: 436 1.1 christos free(srcBuffer); 437 1.1 christos free(sampleSizes); 438 1.1 christos free(dictBuffer); 439 1.1 christos return result; 440 1.1 christos } 441