Home | History | Annotate | Line # | Download | only in programs
dibio.c revision 1.1.1.2
      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