zstd/programs/datagen.c

187 lines
6.0 KiB
C
Raw Normal View History

/*
2016-08-30 17:04:33 +00:00
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
2016-08-30 17:04:33 +00:00
*/
2015-01-24 00:58:16 +00:00
2016-02-02 13:36:49 +00:00
/*-************************************
2016-07-13 15:38:39 +00:00
* Dependencies
2015-01-24 00:58:16 +00:00
**************************************/
2018-09-27 22:13:43 +00:00
#include "datagen.h"
2016-12-21 12:23:34 +00:00
#include "platform.h" /* SET_BINARY_MODE */
2016-09-15 15:02:06 +00:00
#include <stdlib.h> /* malloc, free */
#include <stdio.h> /* FILE, fwrite, fprintf */
#include <string.h> /* memcpy */
2016-12-21 12:23:34 +00:00
#include "mem.h" /* U32 */
2015-01-24 12:31:55 +00:00
2016-02-02 13:36:49 +00:00
/*-************************************
2016-05-09 10:20:50 +00:00
* Macros
2015-01-24 00:58:16 +00:00
**************************************/
#define KB *(1 <<10)
2016-05-18 15:18:48 +00:00
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
#define RDG_DEBUG 0
#define TRACE(...) if (RDG_DEBUG) fprintf(stderr, __VA_ARGS__ )
2015-01-24 00:58:16 +00:00
2016-02-02 13:36:49 +00:00
/*-************************************
2016-05-18 15:18:48 +00:00
* Local constants
2015-07-05 00:23:52 +00:00
**************************************/
#define LTLOG 13
#define LTSIZE (1<<LTLOG)
#define LTMASK (LTSIZE-1)
2016-02-02 13:36:49 +00:00
/*-*******************************************************
2015-01-24 00:58:16 +00:00
* Local Functions
*********************************************************/
#define RDG_rotl32(x,r) ((x << r) | (x >> (32 - r)))
2016-05-18 15:18:48 +00:00
static U32 RDG_rand(U32* src)
2015-01-24 00:58:16 +00:00
{
2016-04-10 23:12:32 +00:00
static const U32 prime1 = 2654435761U;
static const U32 prime2 = 2246822519U;
2015-01-24 00:58:16 +00:00
U32 rand32 = *src;
2016-04-10 23:12:32 +00:00
rand32 *= prime1;
rand32 ^= prime2;
rand32 = RDG_rotl32(rand32, 13);
2015-01-24 00:58:16 +00:00
*src = rand32;
2016-05-18 15:18:48 +00:00
return rand32 >> 5;
2015-01-24 00:58:16 +00:00
}
typedef U32 fixedPoint_24_8;
2015-01-24 00:58:16 +00:00
static void RDG_fillLiteralDistrib(BYTE* ldt, fixedPoint_24_8 ld)
2015-01-24 00:58:16 +00:00
{
2016-05-18 15:18:48 +00:00
BYTE const firstChar = (ld<=0.0) ? 0 : '(';
BYTE const lastChar = (ld<=0.0) ? 255 : '}';
2016-05-09 10:20:50 +00:00
BYTE character = (ld<=0.0) ? 0 : '0';
2016-05-18 15:18:48 +00:00
U32 u;
if (ld<=0) ld = 0;
2016-05-18 15:18:48 +00:00
for (u=0; u<LTSIZE; ) {
U32 const weight = (((LTSIZE - u) * ld) >> 8) + 1;
2016-05-18 15:18:48 +00:00
U32 const end = MIN ( u + weight , LTSIZE);
2016-07-13 15:38:39 +00:00
while (u < end) ldt[u++] = character;
2015-01-24 00:58:16 +00:00
character++;
if (character > lastChar) character = firstChar;
}
}
2015-07-05 00:23:52 +00:00
2016-05-18 15:18:48 +00:00
static BYTE RDG_genChar(U32* seed, const BYTE* ldt)
2015-01-24 00:58:16 +00:00
{
2016-04-10 23:12:32 +00:00
U32 const id = RDG_rand(seed) & LTMASK;
2016-07-02 09:14:30 +00:00
return ldt[id]; /* memory-sanitizer fails here, stating "uninitialized value" when table initialized with P==0.0. Checked : table is fully initialized */
2015-01-24 00:58:16 +00:00
}
2015-07-05 00:23:52 +00:00
fix confusion between unsigned <-> U32 as suggested in #1441. generally U32 and unsigned are the same thing, except when they are not ... case : 32-bit compilation for MIPS (uint32_t == unsigned long) A vast majority of transformation consists in transforming U32 into unsigned. In rare cases, it's the other way around (typically for internal code, such as seeds). Among a few issues this patches solves : - some parameters were declared with type `unsigned` in *.h, but with type `U32` in their implementation *.c . - some parameters have type unsigned*, but the caller user a pointer to U32 instead. These fixes are useful. However, the bulk of changes is about %u formating, which requires unsigned type, but generally receives U32 values instead, often just for brevity (U32 is shorter than unsigned). These changes are generally minor, or even annoying. As a consequence, the amount of code changed is larger than I would expect for such a patch. Testing is also a pain : it requires manually modifying `mem.h`, in order to lie about `U32` and force it to be an `unsigned long` typically. On a 64-bit system, this will break the equivalence unsigned == U32. Unfortunately, it will also break a few static_assert(), controlling structure sizes. So it also requires modifying `debug.h` to make `static_assert()` a noop. And then reverting these changes. So it's inconvenient, and as a consequence, this property is currently not checked during CI tests. Therefore, these problems can emerge again in the future. I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests. It's another restriction for coding, adding more frustration during merge tests, since most platforms don't need this distinction (hence contributor will not see it), and while this can matter in theory, the number of platforms impacted seems minimal. Thoughts ?
2018-12-22 00:19:44 +00:00
static U32 RDG_rand15Bits (U32* seedPtr)
{
return RDG_rand(seedPtr) & 0x7FFF;
}
fix confusion between unsigned <-> U32 as suggested in #1441. generally U32 and unsigned are the same thing, except when they are not ... case : 32-bit compilation for MIPS (uint32_t == unsigned long) A vast majority of transformation consists in transforming U32 into unsigned. In rare cases, it's the other way around (typically for internal code, such as seeds). Among a few issues this patches solves : - some parameters were declared with type `unsigned` in *.h, but with type `U32` in their implementation *.c . - some parameters have type unsigned*, but the caller user a pointer to U32 instead. These fixes are useful. However, the bulk of changes is about %u formating, which requires unsigned type, but generally receives U32 values instead, often just for brevity (U32 is shorter than unsigned). These changes are generally minor, or even annoying. As a consequence, the amount of code changed is larger than I would expect for such a patch. Testing is also a pain : it requires manually modifying `mem.h`, in order to lie about `U32` and force it to be an `unsigned long` typically. On a 64-bit system, this will break the equivalence unsigned == U32. Unfortunately, it will also break a few static_assert(), controlling structure sizes. So it also requires modifying `debug.h` to make `static_assert()` a noop. And then reverting these changes. So it's inconvenient, and as a consequence, this property is currently not checked during CI tests. Therefore, these problems can emerge again in the future. I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests. It's another restriction for coding, adding more frustration during merge tests, since most platforms don't need this distinction (hence contributor will not see it), and while this can matter in theory, the number of platforms impacted seems minimal. Thoughts ?
2018-12-22 00:19:44 +00:00
static U32 RDG_randLength(U32* seedPtr)
{
2016-07-02 09:14:30 +00:00
if (RDG_rand(seedPtr) & 7) return (RDG_rand(seedPtr) & 0xF); /* small length */
return (RDG_rand(seedPtr) & 0x1FF) + 0xF;
}
static void RDG_genBlock(void* buffer, size_t buffSize, size_t prefixSize,
double matchProba, const BYTE* ldt, U32* seedPtr)
2015-01-24 00:58:16 +00:00
{
BYTE* const buffPtr = (BYTE*)buffer;
U32 const matchProba32 = (U32)(32768 * matchProba);
2015-02-10 17:15:20 +00:00
size_t pos = prefixSize;
2015-11-20 11:00:25 +00:00
U32 prevOffset = 1;
2015-01-24 00:58:16 +00:00
2015-07-08 01:26:17 +00:00
/* special case : sparse content */
2016-02-02 13:36:49 +00:00
while (matchProba >= 1.0) {
size_t size0 = RDG_rand(seedPtr) & 3;
2015-07-05 00:23:52 +00:00
size0 = (size_t)1 << (16 + size0 * 2);
size0 += RDG_rand(seedPtr) & (size0-1); /* because size0 is power of 2*/
2016-02-02 13:36:49 +00:00
if (buffSize < pos + size0) {
memset(buffPtr+pos, 0, buffSize-pos);
return;
}
memset(buffPtr+pos, 0, size0);
pos += size0;
buffPtr[pos-1] = RDG_genChar(seedPtr, ldt);
continue;
}
2015-01-24 12:31:55 +00:00
/* init */
if (pos==0) buffPtr[0] = RDG_genChar(seedPtr, ldt), pos=1;
2015-02-10 17:15:20 +00:00
/* Generate compressible data */
2016-02-02 13:36:49 +00:00
while (pos < buffSize) {
2015-01-24 00:58:16 +00:00
/* Select : Literal (char) or Match (within 32K) */
if (RDG_rand15Bits(seedPtr) < matchProba32) {
2015-02-10 17:15:20 +00:00
/* Copy (within 32K) */
U32 const length = RDG_randLength(seedPtr) + 4;
2016-05-18 15:26:23 +00:00
U32 const d = (U32) MIN(pos + length , buffSize);
U32 const repeatOffset = (RDG_rand(seedPtr) & 15) == 2;
U32 const randOffset = RDG_rand15Bits(seedPtr) + 1;
2016-05-18 15:26:23 +00:00
U32 const offset = repeatOffset ? prevOffset : (U32) MIN(randOffset , pos);
2016-05-18 15:18:48 +00:00
size_t match = pos - offset;
while (pos < d) { buffPtr[pos++] = buffPtr[match++]; /* correctly manages overlaps */ }
2016-05-18 15:18:48 +00:00
prevOffset = offset;
2016-02-02 13:36:49 +00:00
} else {
2015-01-24 00:58:16 +00:00
/* Literal (noise) */
U32 const length = RDG_randLength(seedPtr);
2016-05-18 15:26:23 +00:00
U32 const d = (U32) MIN(pos + length, buffSize);
while (pos < d) { buffPtr[pos++] = RDG_genChar(seedPtr, ldt); }
2016-02-02 13:36:49 +00:00
} }
2015-02-10 17:15:20 +00:00
}
void RDG_genBuffer(void* buffer, size_t size, double matchProba, double litProba, unsigned seed)
{
fix confusion between unsigned <-> U32 as suggested in #1441. generally U32 and unsigned are the same thing, except when they are not ... case : 32-bit compilation for MIPS (uint32_t == unsigned long) A vast majority of transformation consists in transforming U32 into unsigned. In rare cases, it's the other way around (typically for internal code, such as seeds). Among a few issues this patches solves : - some parameters were declared with type `unsigned` in *.h, but with type `U32` in their implementation *.c . - some parameters have type unsigned*, but the caller user a pointer to U32 instead. These fixes are useful. However, the bulk of changes is about %u formating, which requires unsigned type, but generally receives U32 values instead, often just for brevity (U32 is shorter than unsigned). These changes are generally minor, or even annoying. As a consequence, the amount of code changed is larger than I would expect for such a patch. Testing is also a pain : it requires manually modifying `mem.h`, in order to lie about `U32` and force it to be an `unsigned long` typically. On a 64-bit system, this will break the equivalence unsigned == U32. Unfortunately, it will also break a few static_assert(), controlling structure sizes. So it also requires modifying `debug.h` to make `static_assert()` a noop. And then reverting these changes. So it's inconvenient, and as a consequence, this property is currently not checked during CI tests. Therefore, these problems can emerge again in the future. I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests. It's another restriction for coding, adding more frustration during merge tests, since most platforms don't need this distinction (hence contributor will not see it), and while this can matter in theory, the number of platforms impacted seems minimal. Thoughts ?
2018-12-22 00:19:44 +00:00
U32 seed32 = seed;
2016-05-18 15:18:48 +00:00
BYTE ldt[LTSIZE];
2016-07-13 15:38:39 +00:00
memset(ldt, '0', sizeof(ldt)); /* yes, character '0', this is intentional */
2016-05-18 15:18:48 +00:00
if (litProba<=0.0) litProba = matchProba / 4.5;
RDG_fillLiteralDistrib(ldt, (fixedPoint_24_8)(litProba * 256 + 0.001));
fix confusion between unsigned <-> U32 as suggested in #1441. generally U32 and unsigned are the same thing, except when they are not ... case : 32-bit compilation for MIPS (uint32_t == unsigned long) A vast majority of transformation consists in transforming U32 into unsigned. In rare cases, it's the other way around (typically for internal code, such as seeds). Among a few issues this patches solves : - some parameters were declared with type `unsigned` in *.h, but with type `U32` in their implementation *.c . - some parameters have type unsigned*, but the caller user a pointer to U32 instead. These fixes are useful. However, the bulk of changes is about %u formating, which requires unsigned type, but generally receives U32 values instead, often just for brevity (U32 is shorter than unsigned). These changes are generally minor, or even annoying. As a consequence, the amount of code changed is larger than I would expect for such a patch. Testing is also a pain : it requires manually modifying `mem.h`, in order to lie about `U32` and force it to be an `unsigned long` typically. On a 64-bit system, this will break the equivalence unsigned == U32. Unfortunately, it will also break a few static_assert(), controlling structure sizes. So it also requires modifying `debug.h` to make `static_assert()` a noop. And then reverting these changes. So it's inconvenient, and as a consequence, this property is currently not checked during CI tests. Therefore, these problems can emerge again in the future. I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests. It's another restriction for coding, adding more frustration during merge tests, since most platforms don't need this distinction (hence contributor will not see it), and while this can matter in theory, the number of platforms impacted seems minimal. Thoughts ?
2018-12-22 00:19:44 +00:00
RDG_genBlock(buffer, size, 0, matchProba, ldt, &seed32);
2015-02-10 17:15:20 +00:00
}
void RDG_genStdout(unsigned long long size, double matchProba, double litProba, unsigned seed)
2015-02-10 17:15:20 +00:00
{
fix confusion between unsigned <-> U32 as suggested in #1441. generally U32 and unsigned are the same thing, except when they are not ... case : 32-bit compilation for MIPS (uint32_t == unsigned long) A vast majority of transformation consists in transforming U32 into unsigned. In rare cases, it's the other way around (typically for internal code, such as seeds). Among a few issues this patches solves : - some parameters were declared with type `unsigned` in *.h, but with type `U32` in their implementation *.c . - some parameters have type unsigned*, but the caller user a pointer to U32 instead. These fixes are useful. However, the bulk of changes is about %u formating, which requires unsigned type, but generally receives U32 values instead, often just for brevity (U32 is shorter than unsigned). These changes are generally minor, or even annoying. As a consequence, the amount of code changed is larger than I would expect for such a patch. Testing is also a pain : it requires manually modifying `mem.h`, in order to lie about `U32` and force it to be an `unsigned long` typically. On a 64-bit system, this will break the equivalence unsigned == U32. Unfortunately, it will also break a few static_assert(), controlling structure sizes. So it also requires modifying `debug.h` to make `static_assert()` a noop. And then reverting these changes. So it's inconvenient, and as a consequence, this property is currently not checked during CI tests. Therefore, these problems can emerge again in the future. I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests. It's another restriction for coding, adding more frustration during merge tests, since most platforms don't need this distinction (hence contributor will not see it), and while this can matter in theory, the number of platforms impacted seems minimal. Thoughts ?
2018-12-22 00:19:44 +00:00
U32 seed32 = seed;
2016-05-18 15:18:48 +00:00
size_t const stdBlockSize = 128 KB;
size_t const stdDictSize = 32 KB;
BYTE* const buff = (BYTE*)malloc(stdDictSize + stdBlockSize);
2015-02-10 17:15:20 +00:00
U64 total = 0;
2016-07-02 09:14:30 +00:00
BYTE ldt[LTSIZE]; /* literals distribution table */
2015-02-10 17:15:20 +00:00
/* init */
2016-09-15 15:02:06 +00:00
if (buff==NULL) { perror("datagen"); exit(1); }
2016-04-10 23:20:14 +00:00
if (litProba<=0.0) litProba = matchProba / 4.5;
2016-07-13 15:38:39 +00:00
memset(ldt, '0', sizeof(ldt)); /* yes, character '0', this is intentional */
RDG_fillLiteralDistrib(ldt, (fixedPoint_24_8)(litProba * 256 + 0.001));
2015-02-10 17:15:20 +00:00
SET_BINARY_MODE(stdout);
2015-07-08 01:26:17 +00:00
/* Generate initial dict */
fix confusion between unsigned <-> U32 as suggested in #1441. generally U32 and unsigned are the same thing, except when they are not ... case : 32-bit compilation for MIPS (uint32_t == unsigned long) A vast majority of transformation consists in transforming U32 into unsigned. In rare cases, it's the other way around (typically for internal code, such as seeds). Among a few issues this patches solves : - some parameters were declared with type `unsigned` in *.h, but with type `U32` in their implementation *.c . - some parameters have type unsigned*, but the caller user a pointer to U32 instead. These fixes are useful. However, the bulk of changes is about %u formating, which requires unsigned type, but generally receives U32 values instead, often just for brevity (U32 is shorter than unsigned). These changes are generally minor, or even annoying. As a consequence, the amount of code changed is larger than I would expect for such a patch. Testing is also a pain : it requires manually modifying `mem.h`, in order to lie about `U32` and force it to be an `unsigned long` typically. On a 64-bit system, this will break the equivalence unsigned == U32. Unfortunately, it will also break a few static_assert(), controlling structure sizes. So it also requires modifying `debug.h` to make `static_assert()` a noop. And then reverting these changes. So it's inconvenient, and as a consequence, this property is currently not checked during CI tests. Therefore, these problems can emerge again in the future. I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests. It's another restriction for coding, adding more frustration during merge tests, since most platforms don't need this distinction (hence contributor will not see it), and while this can matter in theory, the number of platforms impacted seems minimal. Thoughts ?
2018-12-22 00:19:44 +00:00
RDG_genBlock(buff, stdDictSize, 0, matchProba, ldt, &seed32);
2015-01-24 00:58:16 +00:00
/* Generate compressible data */
2016-02-02 13:36:49 +00:00
while (total < size) {
2016-05-18 15:18:48 +00:00
size_t const genBlockSize = (size_t) (MIN (stdBlockSize, size-total));
fix confusion between unsigned <-> U32 as suggested in #1441. generally U32 and unsigned are the same thing, except when they are not ... case : 32-bit compilation for MIPS (uint32_t == unsigned long) A vast majority of transformation consists in transforming U32 into unsigned. In rare cases, it's the other way around (typically for internal code, such as seeds). Among a few issues this patches solves : - some parameters were declared with type `unsigned` in *.h, but with type `U32` in their implementation *.c . - some parameters have type unsigned*, but the caller user a pointer to U32 instead. These fixes are useful. However, the bulk of changes is about %u formating, which requires unsigned type, but generally receives U32 values instead, often just for brevity (U32 is shorter than unsigned). These changes are generally minor, or even annoying. As a consequence, the amount of code changed is larger than I would expect for such a patch. Testing is also a pain : it requires manually modifying `mem.h`, in order to lie about `U32` and force it to be an `unsigned long` typically. On a 64-bit system, this will break the equivalence unsigned == U32. Unfortunately, it will also break a few static_assert(), controlling structure sizes. So it also requires modifying `debug.h` to make `static_assert()` a noop. And then reverting these changes. So it's inconvenient, and as a consequence, this property is currently not checked during CI tests. Therefore, these problems can emerge again in the future. I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests. It's another restriction for coding, adding more frustration during merge tests, since most platforms don't need this distinction (hence contributor will not see it), and while this can matter in theory, the number of platforms impacted seems minimal. Thoughts ?
2018-12-22 00:19:44 +00:00
RDG_genBlock(buff, stdDictSize+stdBlockSize, stdDictSize, matchProba, ldt, &seed32);
2015-01-24 00:58:16 +00:00
total += genBlockSize;
2016-04-10 23:12:32 +00:00
{ size_t const unused = fwrite(buff, 1, genBlockSize, stdout); (void)unused; }
2015-02-10 17:15:20 +00:00
/* update dict */
2016-05-18 15:18:48 +00:00
memcpy(buff, buff + stdBlockSize, stdDictSize);
2015-01-24 00:58:16 +00:00
}
2015-07-08 01:26:17 +00:00
2016-02-02 13:36:49 +00:00
/* cleanup */
2015-07-08 01:26:17 +00:00
free(buff);
2015-01-24 00:58:16 +00:00
}