19#ifndef ZDICT_STATIC_LINKING_ONLY
20# define ZDICT_STATIC_LINKING_ONLY
23#include "../common/mem.h"
24#include "../common/pool.h"
25#include "../common/threading.h"
26#include "../common/zstd_internal.h"
27#include "../compress/zstd_compress_internal.h"
42#define FASTCOVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB))
43#define FASTCOVER_MAX_F 31
44#define FASTCOVER_MAX_ACCEL 10
45#define FASTCOVER_DEFAULT_SPLITPOINT 0.75
47#define DEFAULT_ACCEL 1
53#ifndef LOCALDISPLAYLEVEL
54static int g_displayLevel = 0;
59 fprintf(stderr, __VA_ARGS__); \
62#undef LOCALDISPLAYLEVEL
63#define LOCALDISPLAYLEVEL(displayLevel, l, ...) \
64 if (displayLevel >= l) { \
65 DISPLAY(__VA_ARGS__); \
68#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__)
70#ifndef LOCALDISPLAYUPDATE
71static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100;
72static clock_t g_time = 0;
74#undef LOCALDISPLAYUPDATE
75#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \
76 if (displayLevel >= l) { \
77 if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \
79 DISPLAY(__VA_ARGS__); \
83#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)
92static size_t FASTCOVER_hashPtrToIndex(
const void* p,
U32 f,
unsigned d) {
94 return ZSTD_hash6Ptr(p, f);
96 return ZSTD_hash8Ptr(p, f);
158 ZDICT_cover_params_t parameters,
161 const U32 k = parameters.k;
162 const U32 d = parameters.d;
163 const U32 f = ctx->
f;
164 const U32 dmersInK = k - d + 1;
172 activeSegment.
begin = begin;
173 activeSegment.
end = begin;
174 activeSegment.
score = 0;
179 while (activeSegment.
end < end) {
181 const size_t idx = FASTCOVER_hashPtrToIndex(ctx->
samples + activeSegment.
end, f, d);
184 if (segmentFreqs[idx] == 0) {
185 activeSegment.
score += freqs[idx];
188 activeSegment.
end += 1;
189 segmentFreqs[idx] += 1;
191 if (activeSegment.
end - activeSegment.
begin == dmersInK + 1) {
193 const size_t delIndex = FASTCOVER_hashPtrToIndex(ctx->
samples + activeSegment.
begin, f, d);
194 segmentFreqs[delIndex] -= 1;
196 if (segmentFreqs[delIndex] == 0) {
197 activeSegment.
score -= freqs[delIndex];
200 activeSegment.
begin += 1;
204 if (activeSegment.
score > bestSegment.
score) {
205 bestSegment = activeSegment;
210 while (activeSegment.
begin < end) {
211 const size_t delIndex = FASTCOVER_hashPtrToIndex(ctx->
samples + activeSegment.
begin, f, d);
212 segmentFreqs[delIndex] -= 1;
213 activeSegment.
begin += 1;
219 for (pos = bestSegment.
begin; pos != bestSegment.
end; ++pos) {
220 const size_t i = FASTCOVER_hashPtrToIndex(ctx->
samples + pos, f, d);
229static int FASTCOVER_checkParameters(ZDICT_cover_params_t parameters,
230 size_t maxDictSize,
unsigned f,
233 if (parameters.d == 0 || parameters.k == 0) {
237 if (parameters.d != 6 && parameters.d != 8) {
241 if (parameters.k > maxDictSize) {
245 if (parameters.d > parameters.k) {
253 if (parameters.splitPoint <= 0 || parameters.splitPoint > 1) {
257 if (accel > 10 || accel == 0) {
286 const unsigned f = ctx->
f;
287 const unsigned d = ctx->
d;
289 const unsigned readLength =
MAX(d, 8);
294 size_t start = ctx->
offsets[i];
295 size_t const currSampleEnd = ctx->
offsets[i+1];
296 while (start + readLength <= currSampleEnd) {
297 const size_t dmerIndex = FASTCOVER_hashPtrToIndex(ctx->
samples + start, f, d);
299 start = start + skip + 1;
314 const void* samplesBuffer,
315 const size_t* samplesSizes,
unsigned nbSamples,
316 unsigned d,
double splitPoint,
unsigned f,
319 const BYTE*
const samples = (
const BYTE*)samplesBuffer;
320 const size_t totalSamplesSize =
COVER_sum(samplesSizes, nbSamples);
322 const unsigned nbTrainSamples = splitPoint < 1.0 ? (unsigned)((
double)nbSamples * splitPoint) : nbSamples;
323 const unsigned nbTestSamples = splitPoint < 1.0 ? nbSamples - nbTrainSamples : nbSamples;
324 const size_t trainingSamplesSize = splitPoint < 1.0 ?
COVER_sum(samplesSizes, nbTrainSamples) : totalSamplesSize;
325 const size_t testSamplesSize = splitPoint < 1.0 ?
COVER_sum(samplesSizes + nbTrainSamples, nbTestSamples) : totalSamplesSize;
328 if (totalSamplesSize <
MAX(d,
sizeof(
U64)) ||
330 DISPLAYLEVEL(1,
"Total samples size is too large (%u MB), maximum size is %u MB\n",
332 return ERROR(srcSize_wrong);
336 if (nbTrainSamples < 5) {
337 DISPLAYLEVEL(1,
"Total number of training samples is %u and is invalid\n", nbTrainSamples);
338 return ERROR(srcSize_wrong);
342 if (nbTestSamples < 1) {
343 DISPLAYLEVEL(1,
"Total number of testing samples is %u and is invalid.\n", nbTestSamples);
344 return ERROR(srcSize_wrong);
348 memset(ctx, 0,
sizeof(*ctx));
349 DISPLAYLEVEL(2,
"Training on %u samples of total size %u\n", nbTrainSamples,
350 (
unsigned)trainingSamplesSize);
351 DISPLAYLEVEL(2,
"Testing on %u samples of total size %u\n", nbTestSamples,
352 (
unsigned)testSamplesSize);
359 ctx->
nbDmers = trainingSamplesSize -
MAX(d,
sizeof(
U64)) + 1;
365 ctx->
offsets = (
size_t*)calloc((nbSamples + 1),
sizeof(size_t));
367 DISPLAYLEVEL(1,
"Failed to allocate scratch buffers \n");
368 FASTCOVER_ctx_destroy(ctx);
369 return ERROR(memory_allocation);
376 for (i = 1; i <= nbSamples; ++i) {
383 if (ctx->
freqs == NULL) {
384 DISPLAYLEVEL(1,
"Failed to allocate frequency table \n");
385 FASTCOVER_ctx_destroy(ctx);
386 return ERROR(memory_allocation);
390 FASTCOVER_computeFrequency(ctx->
freqs, ctx);
402 void* dictBuffer,
size_t dictBufferCapacity,
403 ZDICT_cover_params_t parameters,
406 BYTE *
const dict = (
BYTE *)dictBuffer;
407 size_t tail = dictBufferCapacity;
410 (
U32)dictBufferCapacity, (
U32)ctx->
nbDmers, parameters.k, 1);
411 const size_t maxZeroScoreRun = 10;
412 size_t zeroScoreRun = 0;
414 DISPLAYLEVEL(2,
"Breaking content into %u epochs of size %u\n",
419 for (epoch = 0; tail > 0; epoch = (epoch + 1) % epochs.
num) {
420 const U32 epochBegin = (
U32)(epoch * epochs.
size);
421 const U32 epochEnd = epochBegin + epochs.
size;
425 ctx, freqs, epochBegin, epochEnd, parameters, segmentFreqs);
430 if (segment.
score == 0) {
431 if (++zeroScoreRun >= maxZeroScoreRun) {
439 segmentSize =
MIN(segment.
end - segment.
begin + parameters.d - 1, tail);
440 if (segmentSize < parameters.d) {
448 memcpy(dict + tail, ctx->
samples + segment.
begin, segmentSize);
451 (
unsigned)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity));
473static void FASTCOVER_tryParameters(
void* opaque)
478 const ZDICT_cover_params_t parameters = data->
parameters;
480 size_t totalCompressedSize =
ERROR(GENERIC);
482 U16* segmentFreqs = (
U16*)calloc(((
U64)1 << ctx->
f),
sizeof(
U16));
484 BYTE *
const dict = (
BYTE*)malloc(dictBufferCapacity);
486 U32* freqs = (
U32*) malloc(((
U64)1 << ctx->
f) *
sizeof(
U32));
487 if (!segmentFreqs || !dict || !freqs) {
488 DISPLAYLEVEL(1,
"Failed to allocate buffers: out of memory\n");
492 memcpy(freqs, ctx->
freqs, ((
U64)1 << ctx->
f) *
sizeof(
U32));
494 {
const size_t tail = FASTCOVER_buildDictionary(ctx, freqs, dict, dictBufferCapacity,
495 parameters, segmentFreqs);
498 selection =
COVER_selectDict(dict + tail, dictBufferCapacity, dictBufferCapacity - tail,
500 totalCompressedSize);
518FASTCOVER_convertToCoverParams(ZDICT_fastCover_params_t fastCoverParams,
519 ZDICT_cover_params_t* coverParams)
521 coverParams->k = fastCoverParams.k;
522 coverParams->d = fastCoverParams.d;
523 coverParams->steps = fastCoverParams.steps;
524 coverParams->nbThreads = fastCoverParams.nbThreads;
525 coverParams->splitPoint = fastCoverParams.splitPoint;
526 coverParams->zParams = fastCoverParams.zParams;
527 coverParams->shrinkDict = fastCoverParams.shrinkDict;
532FASTCOVER_convertToFastCoverParams(ZDICT_cover_params_t coverParams,
533 ZDICT_fastCover_params_t* fastCoverParams,
534 unsigned f,
unsigned accel)
536 fastCoverParams->k = coverParams.k;
537 fastCoverParams->d = coverParams.d;
538 fastCoverParams->steps = coverParams.steps;
539 fastCoverParams->nbThreads = coverParams.nbThreads;
540 fastCoverParams->splitPoint = coverParams.splitPoint;
541 fastCoverParams->f = f;
542 fastCoverParams->accel = accel;
543 fastCoverParams->zParams = coverParams.zParams;
544 fastCoverParams->shrinkDict = coverParams.shrinkDict;
548ZDICTLIB_STATIC_API
size_t
550 const void* samplesBuffer,
551 const size_t* samplesSizes,
unsigned nbSamples,
552 ZDICT_fastCover_params_t parameters)
554 BYTE*
const dict = (
BYTE*)dictBuffer;
556 ZDICT_cover_params_t coverParams;
559 g_displayLevel = (int)parameters.zParams.notificationLevel;
561 parameters.splitPoint = 1.0;
562 parameters.f = parameters.f == 0 ?
DEFAULT_F : parameters.f;
563 parameters.accel = parameters.accel == 0 ?
DEFAULT_ACCEL : parameters.accel;
565 memset(&coverParams, 0 ,
sizeof(coverParams));
566 FASTCOVER_convertToCoverParams(parameters, &coverParams);
568 if (!FASTCOVER_checkParameters(coverParams, dictBufferCapacity, parameters.f,
571 return ERROR(parameter_outOfBound);
573 if (nbSamples == 0) {
574 DISPLAYLEVEL(1,
"FASTCOVER must have at least one input file\n");
575 return ERROR(srcSize_wrong);
577 if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
578 DISPLAYLEVEL(1,
"dictBufferCapacity must be at least %u\n",
580 return ERROR(dstSize_tooSmall);
583 accelParams = FASTCOVER_defaultAccelParameters[parameters.accel];
586 size_t const initVal = FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples,
587 coverParams.
d, parameters.splitPoint, parameters.f,
599 U16* segmentFreqs = (
U16 *)calloc(((
U64)1 << parameters.f),
sizeof(
U16));
600 const size_t tail = FASTCOVER_buildDictionary(&ctx, ctx.
freqs, dictBuffer,
601 dictBufferCapacity, coverParams, segmentFreqs);
604 dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,
605 samplesBuffer, samplesSizes, nbFinalizeSamples, coverParams.zParams);
608 (
unsigned)dictionarySize);
610 FASTCOVER_ctx_destroy(&ctx);
612 return dictionarySize;
617ZDICTLIB_STATIC_API
size_t
619 void* dictBuffer,
size_t dictBufferCapacity,
620 const void* samplesBuffer,
621 const size_t* samplesSizes,
unsigned nbSamples,
622 ZDICT_fastCover_params_t* parameters)
624 ZDICT_cover_params_t coverParams;
627 const unsigned nbThreads = parameters->nbThreads;
628 const double splitPoint =
630 const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;
631 const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d;
632 const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k;
633 const unsigned kMaxK = parameters->k == 0 ? 2000 : parameters->k;
634 const unsigned kSteps = parameters->steps == 0 ? 40 : parameters->steps;
635 const unsigned kStepSize =
MAX((kMaxK - kMinK) / kSteps, 1);
636 const unsigned kIterations =
637 (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize);
638 const unsigned f = parameters->f == 0 ?
DEFAULT_F : parameters->f;
639 const unsigned accel = parameters->accel == 0 ?
DEFAULT_ACCEL : parameters->accel;
640 const unsigned shrinkDict = 0;
642 const int displayLevel = (int)parameters->zParams.notificationLevel;
643 unsigned iteration = 1;
650 if (splitPoint <= 0 || splitPoint > 1) {
652 return ERROR(parameter_outOfBound);
656 return ERROR(parameter_outOfBound);
658 if (kMinK < kMaxD || kMaxK < kMinK) {
660 return ERROR(parameter_outOfBound);
662 if (nbSamples == 0) {
663 LOCALDISPLAYLEVEL(displayLevel, 1,
"FASTCOVER must have at least one input file\n");
664 return ERROR(srcSize_wrong);
666 if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {
669 return ERROR(dstSize_tooSmall);
674 return ERROR(memory_allocation);
679 memset(&coverParams, 0 ,
sizeof(coverParams));
680 FASTCOVER_convertToCoverParams(*parameters, &coverParams);
681 accelParams = FASTCOVER_defaultAccelParameters[accel];
683 g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1;
687 for (d = kMinD; d <= kMaxD; d += 2) {
692 size_t const initVal = FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint, f, accelParams);
705 for (k = kMinK; k <= kMaxK; k += kStepSize) {
713 FASTCOVER_ctx_destroy(&ctx);
715 return ERROR(memory_allocation);
726 data->
parameters.zParams.notificationLevel = (unsigned)g_displayLevel;
728 if (!FASTCOVER_checkParameters(data->
parameters, dictBufferCapacity,
729 data->
ctx->
f, accel)) {
737 POOL_add(pool, &FASTCOVER_tryParameters, data);
739 FASTCOVER_tryParameters(data);
743 (
unsigned)((iteration * 100) / kIterations));
747 FASTCOVER_ctx_destroy(&ctx);
752 const size_t dictSize = best.dictSize;
754 const size_t compressedSize = best.compressedSize;
757 return compressedSize;
759 FASTCOVER_convertToFastCoverParams(best.parameters, parameters, f, accel);
760 memcpy(dictBuffer, best.dict, dictSize);
COVER_dictSelection_t COVER_dictSelectionError(size_t error)
COVER_epoch_info_t COVER_computeEpochs(U32 maxDictSize, U32 nbDmers, U32 k, U32 passes)
void COVER_warnOnSmallCorpus(size_t maxDictSize, size_t nbDmers, int displayLevel)
void COVER_best_finish(COVER_best_t *best, ZDICT_cover_params_t parameters, COVER_dictSelection_t selection)
COVER_dictSelection_t COVER_selectDict(BYTE *customDictContent, size_t dictBufferCapacity, size_t dictContentSize, const BYTE *samplesBuffer, const size_t *samplesSizes, unsigned nbFinalizeSamples, size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t *offsets, size_t totalCompressedSize)
void COVER_dictSelectionFree(COVER_dictSelection_t selection)
void COVER_best_wait(COVER_best_t *best)
unsigned COVER_dictSelectionIsError(COVER_dictSelection_t selection)
size_t COVER_sum(const size_t *samplesSizes, unsigned nbSamples)
void COVER_best_start(COVER_best_t *best)
void COVER_best_init(COVER_best_t *best)
void COVER_best_destroy(COVER_best_t *best)
#define assert(condition)
#define LOCALDISPLAYUPDATE(displayLevel, l,...)
#define DISPLAYUPDATE(l,...)
#define FASTCOVER_MAX_ACCEL
ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_fastCover(void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, ZDICT_fastCover_params_t parameters)
struct FASTCOVER_tryParameters_data_s FASTCOVER_tryParameters_data_t
#define DISPLAYLEVEL(l,...)
#define FASTCOVER_MAX_SAMPLES_SIZE
#define LOCALDISPLAYLEVEL(displayLevel, l,...)
#define FASTCOVER_DEFAULT_SPLITPOINT
ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_fastCover(void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, ZDICT_fastCover_params_t *parameters)
POOL_ctx * POOL_create(size_t numThreads, size_t queueSize)
void POOL_add(POOL_ctx *ctx, POOL_function function, void *opaque)
void POOL_free(POOL_ctx *ctx)
const size_t * samplesSizes
FASTCOVER_accel_t accelParams
size_t dictBufferCapacity
ZDICT_cover_params_t parameters
const FASTCOVER_ctx_t * ctx
size_t ZDICT_finalizeDictionary(void *dictBuffer, size_t dictBufferCapacity, const void *customDictContent, size_t dictContentSize, const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, ZDICT_params_t params)