1
0
Fork 0

On invalid parameters, print short help message

This commit is contained in:
Joris van Rantwijk 2022-07-03 09:29:27 +02:00
parent 2e8dae2245
commit 5c24788b09
2 changed files with 47 additions and 22 deletions

View File

@ -149,8 +149,8 @@ public:
// N = log(1 - U/V) / log(1 - 1/V) // N = log(1 - U/V) / log(1 - 1/V)
// //
if (info_per_record >= 128) { if (info_per_record >= 128) {
// The number of records is so big that we can just pretend // There are so many different records that we can just
// that every key will produce a different record. // pretend that every key will produce a different record.
} else { } else {
double v = exp(info_per_record * M_LN2); double v = exp(info_per_record * M_LN2);
@ -182,7 +182,7 @@ public:
// Determine the number of random bits for which the // Determine the number of random bits for which the
// expected number of unique keys matches our target. // expected number of unique keys matches our target.
// First scan in steps of 1 bit. // Coarse scan in steps of 1 bit.
unsigned int need_bits = 2; unsigned int need_bits = 2;
while (need_bits < 127) { while (need_bits < 127) {
double expected_unique = double expected_unique =
@ -223,19 +223,22 @@ public:
void generate_record(unsigned char * record, Xoroshiro128plus& rng) void generate_record(unsigned char * record, Xoroshiro128plus& rng)
{ {
if (m_make_duplicates) { if (m_make_duplicates) {
// We have a budget of fewer than 128 random bits per record. // We want a specific fraction of duplicate records.
// Create a random seed value of that many bits. // Instead of drawing a random record from a uniform distribution
// Then use it to initialize a secondary random number generator. // of all possible records, we draw a random key from a limited
// Then use that generator to generate the actual record. // set, then map that key to a record.
// During the first call, generate a salt for the secondary // During the first call, generate a salt for the mapping from
// random number generator. Without this salt, every run // key to record. Without this salt, repeated runs would sample
// would sample from the same subset of records. // from the same subset of records even when using different
// random seeds.
if (!m_salt_initialized) { if (!m_salt_initialized) {
m_salt = rng.next(); m_salt = rng.next();
m_salt_initialized = true; m_salt_initialized = true;
} }
// Draw a random key with the chosen number of bits.
// Apply a threshold to draw a "fractional" number of bits.
uint64_t s0 = 0, s1 = 0; uint64_t s0 = 0, s1 = 0;
unsigned int need_bits = m_bits_per_record; unsigned int need_bits = m_bits_per_record;
if (need_bits > 64) { if (need_bits > 64) {
@ -246,16 +249,20 @@ public:
s1 = rng.next(); s1 = rng.next();
} while (s1 > m_highbit_threshold); } while (s1 > m_highbit_threshold);
s1 >>= (64 - need_bits); s1 >>= (64 - need_bits);
// Mix salt into the key.
s0 ^= m_salt; s0 ^= m_salt;
// Create secondary random number generator. // Use the key to initialize a secondary random number generator.
Xoroshiro128plus rng2(s0, s1); Xoroshiro128plus rng2(s0, s1);
rng2.next(); rng2.next();
rng2.next(); rng2.next();
// Use it to generate a record. // Use secondary generator to map the key to a record.
generate_uniform_record(record, rng2); generate_uniform_record(record, rng2);
} else { } else {
// Uniform distribution of records. // Uniform distribution of records.
generate_uniform_record(record, rng); generate_uniform_record(record, rng);
} }
@ -402,11 +409,22 @@ void usage()
} }
void usage_short()
{
fprintf(stderr, "Run 'recgen --help' for usage instructions.\n");
}
} // anonymous namespace } // anonymous namespace
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
const struct option longopts[] = {
{ "help", 0, nullptr, 'h' },
{ nullptr, 0, nullptr, 0 }
};
double duplicate_fraction = 0.0; double duplicate_fraction = 0.0;
unsigned long long num_records = 0; unsigned long long num_records = 0;
unsigned long record_size = 0; unsigned long record_size = 0;
@ -414,7 +432,8 @@ int main(int argc, char **argv)
unsigned long long seed = 1; unsigned long long seed = 1;
int opt; int opt;
while ((opt = getopt(argc, argv, "ad:n:s:S:")) != -1) { while ((opt = getopt_long(argc, argv, "ad:n:s:S:h", longopts, nullptr))
!= -1) {
char *endptr; char *endptr;
switch (opt) { switch (opt) {
case 'a': case 'a':
@ -467,32 +486,32 @@ int main(int argc, char **argv)
usage(); usage();
return EXIT_SUCCESS; return EXIT_SUCCESS;
default: default:
usage(); usage_short();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
if (num_records == 0) { if (num_records == 0) {
fprintf(stderr, "ERROR: Missing required parameter -n\n"); fprintf(stderr, "ERROR: Missing required parameter -n\n");
usage(); usage_short();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (record_size == 0) { if (record_size == 0) {
fprintf(stderr, "ERROR: Missing required parameter -s\n"); fprintf(stderr, "ERROR: Missing required parameter -s\n");
usage(); usage_short();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (argc < optind + 1) { if (argc < optind + 1) {
fprintf(stderr, fprintf(stderr,
"ERROR: Output file name must be specified\n"); "ERROR: Output file name must be specified\n");
usage(); usage_short();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (argc > optind + 1) { if (argc > optind + 1) {
fprintf(stderr, "ERROR: Unexpected command-line parameters\n"); fprintf(stderr, "ERROR: Unexpected command-line parameters\n");
usage(); usage_short();
return EXIT_FAILURE; return EXIT_FAILURE;
} }

View File

@ -2581,6 +2581,12 @@ void usage()
} }
void usage_short()
{
fprintf(stderr, "Run 'sortbin --help' for usage instructions.\n");
}
} // anonymous namespace } // anonymous namespace
@ -2663,27 +2669,27 @@ int main(int argc, char **argv)
usage(); usage();
return EXIT_SUCCESS; return EXIT_SUCCESS;
default: default:
usage(); usage_short();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
if (ctx.record_size < 1) { if (ctx.record_size < 1) {
fprintf(stderr, "ERROR: Missing required parameter --size\n"); fprintf(stderr, "ERROR: Missing required parameter --size\n");
usage(); usage_short();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (argc < optind + 2) { if (argc < optind + 2) {
fprintf(stderr, fprintf(stderr,
"ERROR: Input and output file names must be specified\n"); "ERROR: Input and output file names must be specified\n");
usage(); usage_short();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (argc > optind + 2) { if (argc > optind + 2) {
fprintf(stderr, "ERROR: Unexpected command-line parameters\n"); fprintf(stderr, "ERROR: Unexpected command-line parameters\n");
usage(); usage_short();
return EXIT_FAILURE; return EXIT_FAILURE;
} }