contrib/python-zstandard/zstd/dictBuilder/cover.c
changeset 37495 b1fb341d8a61
parent 30895 c32454d69b85
child 40121 73fef626dae3
equal deleted inserted replaced
37494:1ce7a55b09d1 37495:b1fb341d8a61
     1 /**
     1 /*
     2  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
     2  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
     3  * All rights reserved.
     3  * All rights reserved.
     4  *
     4  *
     5  * This source code is licensed under the BSD-style license found in the
     5  * This source code is licensed under both the BSD-style license (found in the
     6  * LICENSE file in the root directory of this source tree. An additional grant
     6  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
     7  * of patent rights can be found in the PATENTS file in the same directory.
     7  * in the COPYING file in the root directory of this source tree).
     8  */
     8  * You may select, at your option, one of the above-listed licenses.
       
     9  */
       
    10 
       
    11 /* *****************************************************************************
       
    12  * Constructs a dictionary using a heuristic based on the following paper:
       
    13  *
       
    14  * Liao, Petri, Moffat, Wirth
       
    15  * Effective Construction of Relative Lempel-Ziv Dictionaries
       
    16  * Published in WWW 2016.
       
    17  *
       
    18  * Adapted from code originally written by @ot (Giuseppe Ottaviano).
       
    19  ******************************************************************************/
     9 
    20 
    10 /*-*************************************
    21 /*-*************************************
    11 *  Dependencies
    22 *  Dependencies
    12 ***************************************/
    23 ***************************************/
    13 #include <stdio.h>  /* fprintf */
    24 #include <stdio.h>  /* fprintf */
    47 #define LOCALDISPLAYUPDATE(displayLevel, l, ...)                               \
    58 #define LOCALDISPLAYUPDATE(displayLevel, l, ...)                               \
    48   if (displayLevel >= l) {                                                     \
    59   if (displayLevel >= l) {                                                     \
    49     if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) {             \
    60     if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) {             \
    50       g_time = clock();                                                        \
    61       g_time = clock();                                                        \
    51       DISPLAY(__VA_ARGS__);                                                    \
    62       DISPLAY(__VA_ARGS__);                                                    \
    52       if (displayLevel >= 4)                                                   \
       
    53         fflush(stdout);                                                        \
       
    54     }                                                                          \
    63     }                                                                          \
    55   }
    64   }
    56 #define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)
    65 #define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)
    57 static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
    66 static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;
    58 static clock_t g_time = 0;
    67 static clock_t g_time = 0;
   224  * Returns -1 if the dmer at lp is less than the dmer at rp.
   233  * Returns -1 if the dmer at lp is less than the dmer at rp.
   225  * Return 0 if the dmers at lp and rp are equal.
   234  * Return 0 if the dmers at lp and rp are equal.
   226  * Returns 1 if the dmer at lp is greater than the dmer at rp.
   235  * Returns 1 if the dmer at lp is greater than the dmer at rp.
   227  */
   236  */
   228 static int COVER_cmp(COVER_ctx_t *ctx, const void *lp, const void *rp) {
   237 static int COVER_cmp(COVER_ctx_t *ctx, const void *lp, const void *rp) {
   229   const U32 lhs = *(const U32 *)lp;
   238   U32 const lhs = *(U32 const *)lp;
   230   const U32 rhs = *(const U32 *)rp;
   239   U32 const rhs = *(U32 const *)rp;
   231   return memcmp(ctx->samples + lhs, ctx->samples + rhs, ctx->d);
   240   return memcmp(ctx->samples + lhs, ctx->samples + rhs, ctx->d);
       
   241 }
       
   242 /**
       
   243  * Faster version for d <= 8.
       
   244  */
       
   245 static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) {
       
   246   U64 const mask = (ctx->d == 8) ? (U64)-1 : (((U64)1 << (8 * ctx->d)) - 1);
       
   247   U64 const lhs = MEM_readLE64(ctx->samples + *(U32 const *)lp) & mask;
       
   248   U64 const rhs = MEM_readLE64(ctx->samples + *(U32 const *)rp) & mask;
       
   249   if (lhs < rhs) {
       
   250     return -1;
       
   251   }
       
   252   return (lhs > rhs);
   232 }
   253 }
   233 
   254 
   234 /**
   255 /**
   235  * Same as COVER_cmp() except ties are broken by pointer value
   256  * Same as COVER_cmp() except ties are broken by pointer value
   236  * NOTE: g_ctx must be set to call this function.  A global is required because
   257  * NOTE: g_ctx must be set to call this function.  A global is required because
   237  * qsort doesn't take an opaque pointer.
   258  * qsort doesn't take an opaque pointer.
   238  */
   259  */
   239 static int COVER_strict_cmp(const void *lp, const void *rp) {
   260 static int COVER_strict_cmp(const void *lp, const void *rp) {
   240   int result = COVER_cmp(g_ctx, lp, rp);
   261   int result = COVER_cmp(g_ctx, lp, rp);
       
   262   if (result == 0) {
       
   263     result = lp < rp ? -1 : 1;
       
   264   }
       
   265   return result;
       
   266 }
       
   267 /**
       
   268  * Faster version for d <= 8.
       
   269  */
       
   270 static int COVER_strict_cmp8(const void *lp, const void *rp) {
       
   271   int result = COVER_cmp8(g_ctx, lp, rp);
   241   if (result == 0) {
   272   if (result == 0) {
   242     result = lp < rp ? -1 : 1;
   273     result = lp < rp ? -1 : 1;
   243   }
   274   }
   244   return result;
   275   return result;
   245 }
   276 }
   350  * A segment is a range in the source as well as the score of the segment.
   381  * A segment is a range in the source as well as the score of the segment.
   351  */
   382  */
   352 typedef struct {
   383 typedef struct {
   353   U32 begin;
   384   U32 begin;
   354   U32 end;
   385   U32 end;
   355   double score;
   386   U32 score;
   356 } COVER_segment_t;
   387 } COVER_segment_t;
   357 
   388 
   358 /**
   389 /**
   359  * Selects the best segment in an epoch.
   390  * Selects the best segment in an epoch.
   360  * Segments of are scored according to the function:
   391  * Segments of are scored according to the function:
   366  *
   397  *
   367  * Once the dmer d is in the dictionay we set F(d) = 0.
   398  * Once the dmer d is in the dictionay we set F(d) = 0.
   368  */
   399  */
   369 static COVER_segment_t COVER_selectSegment(const COVER_ctx_t *ctx, U32 *freqs,
   400 static COVER_segment_t COVER_selectSegment(const COVER_ctx_t *ctx, U32 *freqs,
   370                                            COVER_map_t *activeDmers, U32 begin,
   401                                            COVER_map_t *activeDmers, U32 begin,
   371                                            U32 end, COVER_params_t parameters) {
   402                                            U32 end,
       
   403                                            ZDICT_cover_params_t parameters) {
   372   /* Constants */
   404   /* Constants */
   373   const U32 k = parameters.k;
   405   const U32 k = parameters.k;
   374   const U32 d = parameters.d;
   406   const U32 d = parameters.d;
   375   const U32 dmersInK = k - d + 1;
   407   const U32 dmersInK = k - d + 1;
   376   /* Try each segment (activeSegment) and save the best (bestSegment) */
   408   /* Try each segment (activeSegment) and save the best (bestSegment) */
   446 
   478 
   447 /**
   479 /**
   448  * Check the validity of the parameters.
   480  * Check the validity of the parameters.
   449  * Returns non-zero if the parameters are valid and 0 otherwise.
   481  * Returns non-zero if the parameters are valid and 0 otherwise.
   450  */
   482  */
   451 static int COVER_checkParameters(COVER_params_t parameters) {
   483 static int COVER_checkParameters(ZDICT_cover_params_t parameters,
       
   484                                  size_t maxDictSize) {
   452   /* k and d are required parameters */
   485   /* k and d are required parameters */
   453   if (parameters.d == 0 || parameters.k == 0) {
   486   if (parameters.d == 0 || parameters.k == 0) {
       
   487     return 0;
       
   488   }
       
   489   /* k <= maxDictSize */
       
   490   if (parameters.k > maxDictSize) {
   454     return 0;
   491     return 0;
   455   }
   492   }
   456   /* d <= k */
   493   /* d <= k */
   457   if (parameters.d > parameters.k) {
   494   if (parameters.d > parameters.k) {
   458     return 0;
   495     return 0;
   496                           const size_t *samplesSizes, unsigned nbSamples,
   533                           const size_t *samplesSizes, unsigned nbSamples,
   497                           unsigned d) {
   534                           unsigned d) {
   498   const BYTE *const samples = (const BYTE *)samplesBuffer;
   535   const BYTE *const samples = (const BYTE *)samplesBuffer;
   499   const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples);
   536   const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples);
   500   /* Checks */
   537   /* Checks */
   501   if (totalSamplesSize < d ||
   538   if (totalSamplesSize < MAX(d, sizeof(U64)) ||
   502       totalSamplesSize >= (size_t)COVER_MAX_SAMPLES_SIZE) {
   539       totalSamplesSize >= (size_t)COVER_MAX_SAMPLES_SIZE) {
   503     DISPLAYLEVEL(1, "Total samples size is too large, maximum size is %u MB\n",
   540     DISPLAYLEVEL(1, "Total samples size is too large (%u MB), maximum size is %u MB\n",
   504                  (COVER_MAX_SAMPLES_SIZE >> 20));
   541                  (U32)(totalSamplesSize>>20), (COVER_MAX_SAMPLES_SIZE >> 20));
   505     return 0;
   542     return 0;
   506   }
   543   }
   507   /* Zero the context */
   544   /* Zero the context */
   508   memset(ctx, 0, sizeof(*ctx));
   545   memset(ctx, 0, sizeof(*ctx));
   509   DISPLAYLEVEL(2, "Training on %u samples of total size %u\n", nbSamples,
   546   DISPLAYLEVEL(2, "Training on %u samples of total size %u\n", nbSamples,
   510                (U32)totalSamplesSize);
   547                (U32)totalSamplesSize);
   511   ctx->samples = samples;
   548   ctx->samples = samples;
   512   ctx->samplesSizes = samplesSizes;
   549   ctx->samplesSizes = samplesSizes;
   513   ctx->nbSamples = nbSamples;
   550   ctx->nbSamples = nbSamples;
   514   /* Partial suffix array */
   551   /* Partial suffix array */
   515   ctx->suffixSize = totalSamplesSize - d + 1;
   552   ctx->suffixSize = totalSamplesSize - MAX(d, sizeof(U64)) + 1;
   516   ctx->suffix = (U32 *)malloc(ctx->suffixSize * sizeof(U32));
   553   ctx->suffix = (U32 *)malloc(ctx->suffixSize * sizeof(U32));
   517   /* Maps index to the dmerID */
   554   /* Maps index to the dmerID */
   518   ctx->dmerAt = (U32 *)malloc(ctx->suffixSize * sizeof(U32));
   555   ctx->dmerAt = (U32 *)malloc(ctx->suffixSize * sizeof(U32));
   519   /* The offsets of each file */
   556   /* The offsets of each file */
   520   ctx->offsets = (size_t *)malloc((nbSamples + 1) * sizeof(size_t));
   557   ctx->offsets = (size_t *)malloc((nbSamples + 1) * sizeof(size_t));
   544     for (i = 0; i < ctx->suffixSize; ++i) {
   581     for (i = 0; i < ctx->suffixSize; ++i) {
   545       ctx->suffix[i] = i;
   582       ctx->suffix[i] = i;
   546     }
   583     }
   547     /* qsort doesn't take an opaque pointer, so pass as a global */
   584     /* qsort doesn't take an opaque pointer, so pass as a global */
   548     g_ctx = ctx;
   585     g_ctx = ctx;
   549     qsort(ctx->suffix, ctx->suffixSize, sizeof(U32), &COVER_strict_cmp);
   586     qsort(ctx->suffix, ctx->suffixSize, sizeof(U32),
       
   587           (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp));
   550   }
   588   }
   551   DISPLAYLEVEL(2, "Computing frequencies\n");
   589   DISPLAYLEVEL(2, "Computing frequencies\n");
   552   /* For each dmer group (group of positions with the same first d bytes):
   590   /* For each dmer group (group of positions with the same first d bytes):
   553    * 1. For each position we set dmerAt[position] = dmerID.  The dmerID is
   591    * 1. For each position we set dmerAt[position] = dmerID.  The dmerID is
   554    *    (groupBeginPtr - suffix).  This allows us to go from position to
   592    *    (groupBeginPtr - suffix).  This allows us to go from position to
   555    *    dmerID so we can look up values in freq.
   593    *    dmerID so we can look up values in freq.
   556    * 2. We calculate how many samples the dmer occurs in and save it in
   594    * 2. We calculate how many samples the dmer occurs in and save it in
   557    *    freqs[dmerId].
   595    *    freqs[dmerId].
   558    */
   596    */
   559   COVER_groupBy(ctx->suffix, ctx->suffixSize, sizeof(U32), ctx, &COVER_cmp,
   597   COVER_groupBy(ctx->suffix, ctx->suffixSize, sizeof(U32), ctx,
   560                 &COVER_group);
   598                 (ctx->d <= 8 ? &COVER_cmp8 : &COVER_cmp), &COVER_group);
   561   ctx->freqs = ctx->suffix;
   599   ctx->freqs = ctx->suffix;
   562   ctx->suffix = NULL;
   600   ctx->suffix = NULL;
   563   return 1;
   601   return 1;
   564 }
   602 }
   565 
   603 
   567  * Given the prepared context build the dictionary.
   605  * Given the prepared context build the dictionary.
   568  */
   606  */
   569 static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs,
   607 static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs,
   570                                     COVER_map_t *activeDmers, void *dictBuffer,
   608                                     COVER_map_t *activeDmers, void *dictBuffer,
   571                                     size_t dictBufferCapacity,
   609                                     size_t dictBufferCapacity,
   572                                     COVER_params_t parameters) {
   610                                     ZDICT_cover_params_t parameters) {
   573   BYTE *const dict = (BYTE *)dictBuffer;
   611   BYTE *const dict = (BYTE *)dictBuffer;
   574   size_t tail = dictBufferCapacity;
   612   size_t tail = dictBufferCapacity;
   575   /* Divide the data up into epochs of equal size.
   613   /* Divide the data up into epochs of equal size.
   576    * We will select at least one segment from each epoch.
   614    * We will select at least one segment from each epoch.
   577    */
   615    */
   588     const U32 epochEnd = epochBegin + epochSize;
   626     const U32 epochEnd = epochBegin + epochSize;
   589     size_t segmentSize;
   627     size_t segmentSize;
   590     /* Select a segment */
   628     /* Select a segment */
   591     COVER_segment_t segment = COVER_selectSegment(
   629     COVER_segment_t segment = COVER_selectSegment(
   592         ctx, freqs, activeDmers, epochBegin, epochEnd, parameters);
   630         ctx, freqs, activeDmers, epochBegin, epochEnd, parameters);
   593     /* Trim the segment if necessary and if it is empty then we are done */
   631     /* If the segment covers no dmers, then we are out of content */
       
   632     if (segment.score == 0) {
       
   633       break;
       
   634     }
       
   635     /* Trim the segment if necessary and if it is too small then we are done */
   594     segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail);
   636     segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail);
   595     if (segmentSize == 0) {
   637     if (segmentSize < parameters.d) {
   596       break;
   638       break;
   597     }
   639     }
   598     /* We fill the dictionary from the back to allow the best segments to be
   640     /* We fill the dictionary from the back to allow the best segments to be
   599      * referenced with the smallest offsets.
   641      * referenced with the smallest offsets.
   600      */
   642      */
   606   }
   648   }
   607   DISPLAYLEVEL(2, "\r%79s\r", "");
   649   DISPLAYLEVEL(2, "\r%79s\r", "");
   608   return tail;
   650   return tail;
   609 }
   651 }
   610 
   652 
   611 /**
   653 ZDICTLIB_API size_t ZDICT_trainFromBuffer_cover(
   612  * Translate from COVER_params_t to ZDICT_params_t required for finalizing the
   654     void *dictBuffer, size_t dictBufferCapacity,
   613  * dictionary.
   655     const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,
   614  */
   656     ZDICT_cover_params_t parameters)
   615 static ZDICT_params_t COVER_translateParams(COVER_params_t parameters) {
   657 {
   616   ZDICT_params_t zdictParams;
   658   BYTE* const dict = (BYTE*)dictBuffer;
   617   memset(&zdictParams, 0, sizeof(zdictParams));
       
   618   zdictParams.notificationLevel = 1;
       
   619   zdictParams.dictID = parameters.dictID;
       
   620   zdictParams.compressionLevel = parameters.compressionLevel;
       
   621   return zdictParams;
       
   622 }
       
   623 
       
   624 /**
       
   625  * Constructs a dictionary using a heuristic based on the following paper:
       
   626  *
       
   627  * Liao, Petri, Moffat, Wirth
       
   628  * Effective Construction of Relative Lempel-Ziv Dictionaries
       
   629  * Published in WWW 2016.
       
   630  */
       
   631 ZDICTLIB_API size_t COVER_trainFromBuffer(
       
   632     void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer,
       
   633     const size_t *samplesSizes, unsigned nbSamples, COVER_params_t parameters) {
       
   634   BYTE *const dict = (BYTE *)dictBuffer;
       
   635   COVER_ctx_t ctx;
   659   COVER_ctx_t ctx;
   636   COVER_map_t activeDmers;
   660   COVER_map_t activeDmers;
       
   661 
       
   662   /* Initialize global data */
       
   663   g_displayLevel = parameters.zParams.notificationLevel;
   637   /* Checks */
   664   /* Checks */
   638   if (!COVER_checkParameters(parameters)) {
   665   if (!COVER_checkParameters(parameters, dictBufferCapacity)) {
   639     DISPLAYLEVEL(1, "Cover parameters incorrect\n");
   666     DISPLAYLEVEL(1, "Cover parameters incorrect\n");
   640     return ERROR(GENERIC);
   667     return ERROR(GENERIC);
   641   }
   668   }
   642   if (nbSamples == 0) {
   669   if (nbSamples == 0) {
   643     DISPLAYLEVEL(1, "Cover must have at least one input file\n");
   670     DISPLAYLEVEL(1, "Cover must have at least one input file\n");
   646   if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
   673   if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
   647     DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n",
   674     DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n",
   648                  ZDICT_DICTSIZE_MIN);
   675                  ZDICT_DICTSIZE_MIN);
   649     return ERROR(dstSize_tooSmall);
   676     return ERROR(dstSize_tooSmall);
   650   }
   677   }
   651   /* Initialize global data */
       
   652   g_displayLevel = parameters.notificationLevel;
       
   653   /* Initialize context and activeDmers */
   678   /* Initialize context and activeDmers */
   654   if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples,
   679   if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples,
   655                       parameters.d)) {
   680                       parameters.d)) {
   656     return ERROR(GENERIC);
   681     return ERROR(GENERIC);
   657   }
   682   }
   664   DISPLAYLEVEL(2, "Building dictionary\n");
   689   DISPLAYLEVEL(2, "Building dictionary\n");
   665   {
   690   {
   666     const size_t tail =
   691     const size_t tail =
   667         COVER_buildDictionary(&ctx, ctx.freqs, &activeDmers, dictBuffer,
   692         COVER_buildDictionary(&ctx, ctx.freqs, &activeDmers, dictBuffer,
   668                               dictBufferCapacity, parameters);
   693                               dictBufferCapacity, parameters);
   669     ZDICT_params_t zdictParams = COVER_translateParams(parameters);
       
   670     const size_t dictionarySize = ZDICT_finalizeDictionary(
   694     const size_t dictionarySize = ZDICT_finalizeDictionary(
   671         dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
   695         dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
   672         samplesBuffer, samplesSizes, nbSamples, zdictParams);
   696         samplesBuffer, samplesSizes, nbSamples, parameters.zParams);
   673     if (!ZSTD_isError(dictionarySize)) {
   697     if (!ZSTD_isError(dictionarySize)) {
   674       DISPLAYLEVEL(2, "Constructed dictionary of size %u\n",
   698       DISPLAYLEVEL(2, "Constructed dictionary of size %u\n",
   675                    (U32)dictionarySize);
   699                    (U32)dictionarySize);
   676     }
   700     }
   677     COVER_ctx_destroy(&ctx);
   701     COVER_ctx_destroy(&ctx);
   687  *
   711  *
   688  * All of the methods except COVER_best_init() are thread safe if zstd is
   712  * All of the methods except COVER_best_init() are thread safe if zstd is
   689  * compiled with multithreaded support.
   713  * compiled with multithreaded support.
   690  */
   714  */
   691 typedef struct COVER_best_s {
   715 typedef struct COVER_best_s {
   692   pthread_mutex_t mutex;
   716   ZSTD_pthread_mutex_t mutex;
   693   pthread_cond_t cond;
   717   ZSTD_pthread_cond_t cond;
   694   size_t liveJobs;
   718   size_t liveJobs;
   695   void *dict;
   719   void *dict;
   696   size_t dictSize;
   720   size_t dictSize;
   697   COVER_params_t parameters;
   721   ZDICT_cover_params_t parameters;
   698   size_t compressedSize;
   722   size_t compressedSize;
   699 } COVER_best_t;
   723 } COVER_best_t;
   700 
   724 
   701 /**
   725 /**
   702  * Initialize the `COVER_best_t`.
   726  * Initialize the `COVER_best_t`.
   703  */
   727  */
   704 static void COVER_best_init(COVER_best_t *best) {
   728 static void COVER_best_init(COVER_best_t *best) {
   705   if (!best) {
   729   if (best==NULL) return; /* compatible with init on NULL */
   706     return;
   730   (void)ZSTD_pthread_mutex_init(&best->mutex, NULL);
   707   }
   731   (void)ZSTD_pthread_cond_init(&best->cond, NULL);
   708   pthread_mutex_init(&best->mutex, NULL);
       
   709   pthread_cond_init(&best->cond, NULL);
       
   710   best->liveJobs = 0;
   732   best->liveJobs = 0;
   711   best->dict = NULL;
   733   best->dict = NULL;
   712   best->dictSize = 0;
   734   best->dictSize = 0;
   713   best->compressedSize = (size_t)-1;
   735   best->compressedSize = (size_t)-1;
   714   memset(&best->parameters, 0, sizeof(best->parameters));
   736   memset(&best->parameters, 0, sizeof(best->parameters));
   719  */
   741  */
   720 static void COVER_best_wait(COVER_best_t *best) {
   742 static void COVER_best_wait(COVER_best_t *best) {
   721   if (!best) {
   743   if (!best) {
   722     return;
   744     return;
   723   }
   745   }
   724   pthread_mutex_lock(&best->mutex);
   746   ZSTD_pthread_mutex_lock(&best->mutex);
   725   while (best->liveJobs != 0) {
   747   while (best->liveJobs != 0) {
   726     pthread_cond_wait(&best->cond, &best->mutex);
   748     ZSTD_pthread_cond_wait(&best->cond, &best->mutex);
   727   }
   749   }
   728   pthread_mutex_unlock(&best->mutex);
   750   ZSTD_pthread_mutex_unlock(&best->mutex);
   729 }
   751 }
   730 
   752 
   731 /**
   753 /**
   732  * Call COVER_best_wait() and then destroy the COVER_best_t.
   754  * Call COVER_best_wait() and then destroy the COVER_best_t.
   733  */
   755  */
   737   }
   759   }
   738   COVER_best_wait(best);
   760   COVER_best_wait(best);
   739   if (best->dict) {
   761   if (best->dict) {
   740     free(best->dict);
   762     free(best->dict);
   741   }
   763   }
   742   pthread_mutex_destroy(&best->mutex);
   764   ZSTD_pthread_mutex_destroy(&best->mutex);
   743   pthread_cond_destroy(&best->cond);
   765   ZSTD_pthread_cond_destroy(&best->cond);
   744 }
   766 }
   745 
   767 
   746 /**
   768 /**
   747  * Called when a thread is about to be launched.
   769  * Called when a thread is about to be launched.
   748  * Increments liveJobs.
   770  * Increments liveJobs.
   749  */
   771  */
   750 static void COVER_best_start(COVER_best_t *best) {
   772 static void COVER_best_start(COVER_best_t *best) {
   751   if (!best) {
   773   if (!best) {
   752     return;
   774     return;
   753   }
   775   }
   754   pthread_mutex_lock(&best->mutex);
   776   ZSTD_pthread_mutex_lock(&best->mutex);
   755   ++best->liveJobs;
   777   ++best->liveJobs;
   756   pthread_mutex_unlock(&best->mutex);
   778   ZSTD_pthread_mutex_unlock(&best->mutex);
   757 }
   779 }
   758 
   780 
   759 /**
   781 /**
   760  * Called when a thread finishes executing, both on error or success.
   782  * Called when a thread finishes executing, both on error or success.
   761  * Decrements liveJobs and signals any waiting threads if liveJobs == 0.
   783  * Decrements liveJobs and signals any waiting threads if liveJobs == 0.
   762  * If this dictionary is the best so far save it and its parameters.
   784  * If this dictionary is the best so far save it and its parameters.
   763  */
   785  */
   764 static void COVER_best_finish(COVER_best_t *best, size_t compressedSize,
   786 static void COVER_best_finish(COVER_best_t *best, size_t compressedSize,
   765                               COVER_params_t parameters, void *dict,
   787                               ZDICT_cover_params_t parameters, void *dict,
   766                               size_t dictSize) {
   788                               size_t dictSize) {
   767   if (!best) {
   789   if (!best) {
   768     return;
   790     return;
   769   }
   791   }
   770   {
   792   {
   771     size_t liveJobs;
   793     size_t liveJobs;
   772     pthread_mutex_lock(&best->mutex);
   794     ZSTD_pthread_mutex_lock(&best->mutex);
   773     --best->liveJobs;
   795     --best->liveJobs;
   774     liveJobs = best->liveJobs;
   796     liveJobs = best->liveJobs;
   775     /* If the new dictionary is better */
   797     /* If the new dictionary is better */
   776     if (compressedSize < best->compressedSize) {
   798     if (compressedSize < best->compressedSize) {
   777       /* Allocate space if necessary */
   799       /* Allocate space if necessary */
   790       memcpy(best->dict, dict, dictSize);
   812       memcpy(best->dict, dict, dictSize);
   791       best->dictSize = dictSize;
   813       best->dictSize = dictSize;
   792       best->parameters = parameters;
   814       best->parameters = parameters;
   793       best->compressedSize = compressedSize;
   815       best->compressedSize = compressedSize;
   794     }
   816     }
   795     pthread_mutex_unlock(&best->mutex);
   817     ZSTD_pthread_mutex_unlock(&best->mutex);
   796     if (liveJobs == 0) {
   818     if (liveJobs == 0) {
   797       pthread_cond_broadcast(&best->cond);
   819       ZSTD_pthread_cond_broadcast(&best->cond);
   798     }
   820     }
   799   }
   821   }
   800 }
   822 }
   801 
   823 
   802 /**
   824 /**
   804  */
   826  */
   805 typedef struct COVER_tryParameters_data_s {
   827 typedef struct COVER_tryParameters_data_s {
   806   const COVER_ctx_t *ctx;
   828   const COVER_ctx_t *ctx;
   807   COVER_best_t *best;
   829   COVER_best_t *best;
   808   size_t dictBufferCapacity;
   830   size_t dictBufferCapacity;
   809   COVER_params_t parameters;
   831   ZDICT_cover_params_t parameters;
   810 } COVER_tryParameters_data_t;
   832 } COVER_tryParameters_data_t;
   811 
   833 
   812 /**
   834 /**
   813  * Tries a set of parameters and upates the COVER_best_t with the results.
   835  * Tries a set of parameters and upates the COVER_best_t with the results.
   814  * This function is thread safe if zstd is compiled with multithreaded support.
   836  * This function is thread safe if zstd is compiled with multithreaded support.
   816  */
   838  */
   817 static void COVER_tryParameters(void *opaque) {
   839 static void COVER_tryParameters(void *opaque) {
   818   /* Save parameters as local variables */
   840   /* Save parameters as local variables */
   819   COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t *)opaque;
   841   COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t *)opaque;
   820   const COVER_ctx_t *const ctx = data->ctx;
   842   const COVER_ctx_t *const ctx = data->ctx;
   821   const COVER_params_t parameters = data->parameters;
   843   const ZDICT_cover_params_t parameters = data->parameters;
   822   size_t dictBufferCapacity = data->dictBufferCapacity;
   844   size_t dictBufferCapacity = data->dictBufferCapacity;
   823   size_t totalCompressedSize = ERROR(GENERIC);
   845   size_t totalCompressedSize = ERROR(GENERIC);
   824   /* Allocate space for hash table, dict, and freqs */
   846   /* Allocate space for hash table, dict, and freqs */
   825   COVER_map_t activeDmers;
   847   COVER_map_t activeDmers;
   826   BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity);
   848   BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity);
   837   memcpy(freqs, ctx->freqs, ctx->suffixSize * sizeof(U32));
   859   memcpy(freqs, ctx->freqs, ctx->suffixSize * sizeof(U32));
   838   /* Build the dictionary */
   860   /* Build the dictionary */
   839   {
   861   {
   840     const size_t tail = COVER_buildDictionary(ctx, freqs, &activeDmers, dict,
   862     const size_t tail = COVER_buildDictionary(ctx, freqs, &activeDmers, dict,
   841                                               dictBufferCapacity, parameters);
   863                                               dictBufferCapacity, parameters);
   842     const ZDICT_params_t zdictParams = COVER_translateParams(parameters);
       
   843     dictBufferCapacity = ZDICT_finalizeDictionary(
   864     dictBufferCapacity = ZDICT_finalizeDictionary(
   844         dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
   865         dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
   845         ctx->samples, ctx->samplesSizes, (unsigned)ctx->nbSamples, zdictParams);
   866         ctx->samples, ctx->samplesSizes, (unsigned)ctx->nbSamples,
       
   867         parameters.zParams);
   846     if (ZDICT_isError(dictBufferCapacity)) {
   868     if (ZDICT_isError(dictBufferCapacity)) {
   847       DISPLAYLEVEL(1, "Failed to finalize dictionary\n");
   869       DISPLAYLEVEL(1, "Failed to finalize dictionary\n");
   848       goto _cleanup;
   870       goto _cleanup;
   849     }
   871     }
   850   }
   872   }
   866       dstCapacity = ZSTD_compressBound(maxSampleSize);
   888       dstCapacity = ZSTD_compressBound(maxSampleSize);
   867       dst = malloc(dstCapacity);
   889       dst = malloc(dstCapacity);
   868     }
   890     }
   869     /* Create the cctx and cdict */
   891     /* Create the cctx and cdict */
   870     cctx = ZSTD_createCCtx();
   892     cctx = ZSTD_createCCtx();
   871     cdict =
   893     cdict = ZSTD_createCDict(dict, dictBufferCapacity,
   872         ZSTD_createCDict(dict, dictBufferCapacity, parameters.compressionLevel);
   894                              parameters.zParams.compressionLevel);
   873     if (!dst || !cctx || !cdict) {
   895     if (!dst || !cctx || !cdict) {
   874       goto _compressCleanup;
   896       goto _compressCleanup;
   875     }
   897     }
   876     /* Compress each sample and sum their sizes (or error) */
   898     /* Compress each sample and sum their sizes (or error) */
   877     totalCompressedSize = 0;
   899     totalCompressedSize = dictBufferCapacity;
   878     for (i = 0; i < ctx->nbSamples; ++i) {
   900     for (i = 0; i < ctx->nbSamples; ++i) {
   879       const size_t size = ZSTD_compress_usingCDict(
   901       const size_t size = ZSTD_compress_usingCDict(
   880           cctx, dst, dstCapacity, ctx->samples + ctx->offsets[i],
   902           cctx, dst, dstCapacity, ctx->samples + ctx->offsets[i],
   881           ctx->samplesSizes[i], cdict);
   903           ctx->samplesSizes[i], cdict);
   882       if (ZSTD_isError(size)) {
   904       if (ZSTD_isError(size)) {
   904   if (freqs) {
   926   if (freqs) {
   905     free(freqs);
   927     free(freqs);
   906   }
   928   }
   907 }
   929 }
   908 
   930 
   909 ZDICTLIB_API size_t COVER_optimizeTrainFromBuffer(void *dictBuffer,
   931 ZDICTLIB_API size_t ZDICT_optimizeTrainFromBuffer_cover(
   910                                                   size_t dictBufferCapacity,
   932     void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer,
   911                                                   const void *samplesBuffer,
   933     const size_t *samplesSizes, unsigned nbSamples,
   912                                                   const size_t *samplesSizes,
   934     ZDICT_cover_params_t *parameters) {
   913                                                   unsigned nbSamples,
       
   914                                                   COVER_params_t *parameters) {
       
   915   /* constants */
   935   /* constants */
   916   const unsigned nbThreads = parameters->nbThreads;
   936   const unsigned nbThreads = parameters->nbThreads;
   917   const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;
   937   const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;
   918   const unsigned kMaxD = parameters->d == 0 ? 16 : parameters->d;
   938   const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d;
   919   const unsigned kMinK = parameters->k == 0 ? kMaxD : parameters->k;
   939   const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k;
   920   const unsigned kMaxK = parameters->k == 0 ? 2048 : parameters->k;
   940   const unsigned kMaxK = parameters->k == 0 ? 2000 : parameters->k;
   921   const unsigned kSteps = parameters->steps == 0 ? 32 : parameters->steps;
   941   const unsigned kSteps = parameters->steps == 0 ? 40 : parameters->steps;
   922   const unsigned kStepSize = MAX((kMaxK - kMinK) / kSteps, 1);
   942   const unsigned kStepSize = MAX((kMaxK - kMinK) / kSteps, 1);
   923   const unsigned kIterations =
   943   const unsigned kIterations =
   924       (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize);
   944       (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize);
   925   /* Local variables */
   945   /* Local variables */
   926   const int displayLevel = parameters->notificationLevel;
   946   const int displayLevel = parameters->zParams.notificationLevel;
   927   unsigned iteration = 1;
   947   unsigned iteration = 1;
   928   unsigned d;
   948   unsigned d;
   929   unsigned k;
   949   unsigned k;
   930   COVER_best_t best;
   950   COVER_best_t best;
   931   POOL_ctx *pool = NULL;
   951   POOL_ctx *pool = NULL;
       
   952 
   932   /* Checks */
   953   /* Checks */
   933   if (kMinK < kMaxD || kMaxK < kMinK) {
   954   if (kMinK < kMaxD || kMaxK < kMinK) {
   934     LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n");
   955     LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n");
   935     return ERROR(GENERIC);
   956     return ERROR(GENERIC);
   936   }
   957   }
   950     }
   971     }
   951   }
   972   }
   952   /* Initialization */
   973   /* Initialization */
   953   COVER_best_init(&best);
   974   COVER_best_init(&best);
   954   /* Turn down global display level to clean up display at level 2 and below */
   975   /* Turn down global display level to clean up display at level 2 and below */
   955   g_displayLevel = parameters->notificationLevel - 1;
   976   g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1;
   956   /* Loop through d first because each new value needs a new context */
   977   /* Loop through d first because each new value needs a new context */
   957   LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n",
   978   LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n",
   958                     kIterations);
   979                     kIterations);
   959   for (d = kMinD; d <= kMaxD; d += 2) {
   980   for (d = kMinD; d <= kMaxD; d += 2) {
   960     /* Initialize the context for this value of d */
   981     /* Initialize the context for this value of d */
   961     COVER_ctx_t ctx;
   982     COVER_ctx_t ctx;
   962     LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d);
   983     LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d);
   963     if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d)) {
   984     if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d)) {
   964       LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n");
   985       LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n");
   965       COVER_best_destroy(&best);
   986       COVER_best_destroy(&best);
       
   987       POOL_free(pool);
   966       return ERROR(GENERIC);
   988       return ERROR(GENERIC);
   967     }
   989     }
   968     /* Loop through k reusing the same context */
   990     /* Loop through k reusing the same context */
   969     for (k = kMinK; k <= kMaxK; k += kStepSize) {
   991     for (k = kMinK; k <= kMaxK; k += kStepSize) {
   970       /* Prepare the arguments */
   992       /* Prepare the arguments */
   973       LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k);
   995       LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k);
   974       if (!data) {
   996       if (!data) {
   975         LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n");
   997         LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n");
   976         COVER_best_destroy(&best);
   998         COVER_best_destroy(&best);
   977         COVER_ctx_destroy(&ctx);
   999         COVER_ctx_destroy(&ctx);
       
  1000         POOL_free(pool);
   978         return ERROR(GENERIC);
  1001         return ERROR(GENERIC);
   979       }
  1002       }
   980       data->ctx = &ctx;
  1003       data->ctx = &ctx;
   981       data->best = &best;
  1004       data->best = &best;
   982       data->dictBufferCapacity = dictBufferCapacity;
  1005       data->dictBufferCapacity = dictBufferCapacity;
   983       data->parameters = *parameters;
  1006       data->parameters = *parameters;
   984       data->parameters.k = k;
  1007       data->parameters.k = k;
   985       data->parameters.d = d;
  1008       data->parameters.d = d;
   986       data->parameters.steps = kSteps;
  1009       data->parameters.steps = kSteps;
       
  1010       data->parameters.zParams.notificationLevel = g_displayLevel;
   987       /* Check the parameters */
  1011       /* Check the parameters */
   988       if (!COVER_checkParameters(data->parameters)) {
  1012       if (!COVER_checkParameters(data->parameters, dictBufferCapacity)) {
   989         DISPLAYLEVEL(1, "Cover parameters incorrect\n");
  1013         DISPLAYLEVEL(1, "Cover parameters incorrect\n");
       
  1014         free(data);
   990         continue;
  1015         continue;
   991       }
  1016       }
   992       /* Call the function and pass ownership of data to it */
  1017       /* Call the function and pass ownership of data to it */
   993       COVER_best_start(&best);
  1018       COVER_best_start(&best);
   994       if (pool) {
  1019       if (pool) {
  1007   LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", "");
  1032   LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", "");
  1008   /* Fill the output buffer and parameters with output of the best parameters */
  1033   /* Fill the output buffer and parameters with output of the best parameters */
  1009   {
  1034   {
  1010     const size_t dictSize = best.dictSize;
  1035     const size_t dictSize = best.dictSize;
  1011     if (ZSTD_isError(best.compressedSize)) {
  1036     if (ZSTD_isError(best.compressedSize)) {
       
  1037       const size_t compressedSize = best.compressedSize;
  1012       COVER_best_destroy(&best);
  1038       COVER_best_destroy(&best);
  1013       return best.compressedSize;
  1039       POOL_free(pool);
       
  1040       return compressedSize;
  1014     }
  1041     }
  1015     *parameters = best.parameters;
  1042     *parameters = best.parameters;
  1016     memcpy(dictBuffer, best.dict, dictSize);
  1043     memcpy(dictBuffer, best.dict, dictSize);
  1017     COVER_best_destroy(&best);
  1044     COVER_best_destroy(&best);
  1018     POOL_free(pool);
  1045     POOL_free(pool);