Files
email-tracker/external/duckdb/third_party/tpce-tool/main/EGenValidate.cpp
2025-10-24 19:21:19 -05:00

324 lines
10 KiB
C++

/*
* Legal Notice
*
* This document and associated source code (the "Work") is a part of a
* benchmark specification maintained by the TPC.
*
* The TPC reserves all right, title, and interest to the Work as provided
* under U.S. and international laws, including without limitation all patent
* and trademark rights therein.
*
* No Warranty
*
* 1.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE INFORMATION
* CONTAINED HEREIN IS PROVIDED "AS IS" AND WITH ALL FAULTS, AND THE
* AUTHORS AND DEVELOPERS OF THE WORK HEREBY DISCLAIM ALL OTHER
* WARRANTIES AND CONDITIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
* INCLUDING, BUT NOT LIMITED TO, ANY (IF ANY) IMPLIED WARRANTIES,
* DUTIES OR CONDITIONS OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR
* PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OF
* WORKMANLIKE EFFORT, OF LACK OF VIRUSES, AND OF LACK OF NEGLIGENCE.
* ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT,
* QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT
* WITH REGARD TO THE WORK.
* 1.2 IN NO EVENT WILL ANY AUTHOR OR DEVELOPER OF THE WORK BE LIABLE TO
* ANY OTHER PARTY FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO THE
* COST OF PROCURING SUBSTITUTE GOODS OR SERVICES, LOST PROFITS, LOSS
* OF USE, LOSS OF DATA, OR ANY INCIDENTAL, CONSEQUENTIAL, DIRECT,
* INDIRECT, OR SPECIAL DAMAGES WHETHER UNDER CONTRACT, TORT, WARRANTY,
* OR OTHERWISE, ARISING IN ANY WAY OUT OF THIS OR ANY OTHER AGREEMENT
* RELATING TO THE WORK, WHETHER OR NOT SUCH AUTHOR OR DEVELOPER HAD
* ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.
*
* Contributors
* - Christopher Chan-Nui
*/
/*
* - 0.3 - Tue Oct 3 23:39:48 CDT 2006
* Extracted BucketSimulator class
* Extracted string parsing and format functions
* Re-vamped to use new threading
*
* - 0.2 - Mon Sep 11 09:06:35 CDT 2006
* Incorporated Matthew Emmerton's suggestions:
* Fixed calculation of simorders (was off by 60)
* Base GlobalLock on CSyncLock
*
* - 0.1 - Fri Sep 8 14:26:00 CDT 2006
* Initial release
*/
#include "utilities/threading.h"
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <cmath>
#include <cstdlib>
#include "main/EGenLoader_stdafx.h"
#include "utilities/DateTime.h"
#include "main/progressmeter.h"
#include "main/bucketsimulator.h"
#include "main/strutil.h"
using TPCE::int64totimestr;
using TPCE::strtodbl;
using TPCE::strtoint64;
using TPCE::timestrtoint64;
using TPCE::CCustomerSelection;
using TPCE::CRandom;
using TPCE::eCustomerTier;
using TPCE::iDefaultLoadUnitSize;
using TPCE::RNGSEED;
using std::cout;
using std::endl;
// Helper class to contain the run configuration options
class BucketSimOptions {
public:
int verbose;
int helplevel;
RNGSEED base_seed;
TIdent cust_count;
double tpse;
bool use_stddev;
double stddev;
INT64 run_length;
UINT sim_count;
UINT sim_first;
UINT num_threads;
UINT interval_time;
// Calculate the number orders for this simulation
INT64 calc_simorders() {
return static_cast<INT64>(tpse * static_cast<double>(run_length));
}
BucketSimOptions()
: verbose(0), helplevel(0), base_seed(TPCE::RNGSeedBaseTxnInputGenerator), cust_count(0), tpse(10),
use_stddev(false), stddev(0), run_length(7200), sim_count(10000), sim_first(0), num_threads(1),
interval_time(10) {
}
};
// Usage message
void usage(const char *progname, BucketSimOptions &options, bool usage_error = true) {
cout << "Usage: " << progname << " [options] stddev custcount [TPS-E] [runtime]" << endl
<< " -h This help message (-hh for more options)" << endl
<< " -v Increase verbosity" << endl
<< " -c num Number of customers to simulate (" << options.cust_count << ")" << endl
<< " -r runtime Runtime to simulate (" << options.run_length << ")" << endl
<< " -e tpsE tpsE to simulate (" << options.tpse << ")" << endl
<< " -s stddev Standard Deviation to check against (none)" << endl
<< " -t threads Number of threads to use (" << options.num_threads << ")" << endl;
if (options.helplevel > 1) {
cout << " -S seed Base Seed for random number generation (" << options.base_seed << ")" << endl
<< " -n num Number of simulations to perform (" << options.sim_count << ")" << endl
<< " -i num Initial simulation number to start with (" << options.sim_first << ")" << endl
<< " -u num Progress report interval (" << options.interval_time << ")" << endl;
}
exit(usage_error ? ERROR_BAD_OPTION : 0);
}
// Parse command line, put discovered values into the options parameter
void parseCommandLine(int argc, const char *argv[], BucketSimOptions &options) {
char flag = '-';
try {
bool tpse_set = false;
options.tpse = 0;
int argnum;
for (argnum = 1; argnum < argc; ++argnum) {
const char *ptr = argv[argnum];
if (*ptr++ != '-') {
break;
}
while (*ptr) {
flag = *ptr++;
// Prefetch an "argument" for the option in case it is needed
// later
bool use_arg = true;
int arg_advance = 0;
const char *arg = ptr;
// If the argument is not bundled with the options' switch we
// use the next argument.
if (*ptr == '\0') {
arg_advance = 1;
arg = argv[argnum + 1];
if (arg == NULL) {
// If there wasn't an argument pretend it was just an
// empty string
arg = "";
}
}
switch (flag) {
case 'v':
use_arg = false;
options.verbose += 1;
break;
case '?':
case 'h':
use_arg = false;
options.helplevel += 1;
break;
case 'S':
options.base_seed = (RNGSEED)strtoint64(arg);
break;
case 'c':
options.cust_count = strtoint64(arg);
break;
case 'n':
options.sim_count = static_cast<UINT>(strtoint64(arg));
break;
case 'i':
options.sim_first = static_cast<UINT>(strtoint64(arg));
break;
case 'r':
options.run_length = timestrtoint64(arg);
break;
case 'e':
tpse_set = true;
options.tpse = strtodbl(arg);
break;
case 't':
options.num_threads = static_cast<UINT>(strtoint64(arg));
break;
case 's':
options.use_stddev = true;
options.stddev = strtodbl(arg);
break;
case 'u':
options.interval_time = static_cast<UINT>(timestrtoint64(arg));
options.verbose += 1;
break;
default:
std::ostringstream strm;
throw std::runtime_error(std::string("Unknown option"));
}
// If we used an argument we need to consume it
if (use_arg) {
argnum += arg_advance;
break;
}
}
}
// After all the switches are processed we consume the rest of the
// command line as positional options
if (argnum < argc) {
options.use_stddev = true;
options.stddev = strtodbl(argv[argnum++]);
}
if (argnum < argc) {
flag = 'c';
options.cust_count = strtoint64(argv[argnum++]);
}
if (argnum < argc) {
flag = 't';
tpse_set = true;
options.tpse = strtodbl(argv[argnum++]);
}
if (argnum < argc) {
flag = 'r';
options.run_length = static_cast<UINT>(timestrtoint64(argv[argnum++]));
}
if (argnum < argc) {
cout << "Too many command line arguments!" << endl;
usage(argv[0], options);
}
if (!tpse_set) {
options.tpse = options.cust_count / 500.0; // 500 is scale factor
}
// If no customers were specified that probably means the user
// didn't know how to invoke us.
if (options.helplevel || options.cust_count == 0 || !options.use_stddev) {
usage(argv[0], options, false);
}
} catch (std::exception &e) {
cout << "Error parsing command line option '" << flag << "': " << e.what() << endl;
usage(argv[0], options);
exit(ERROR_BAD_OPTION);
}
}
int main(int argc, const char *argv[]) {
try {
TPCE::CDateTime start_time;
BucketSimOptions options;
std::vector<TPCE::Thread<TPCE::BucketSimulator> *> threads;
// Output EGen version
TPCE::PrintEGenVersion();
parseCommandLine(argc, argv, options);
TPCE::BucketProgress progress(options.stddev, options.sim_count, options.verbose);
progress.set_display_interval(options.interval_time);
// Start up simulation threads
unsigned int sim_idx = 0;
unsigned int sims_per_thread = options.sim_count / options.num_threads + 1;
while (sim_idx < options.sim_count) {
// Last thread only processes however many are left over
if (sims_per_thread > options.sim_count - sim_idx) {
sims_per_thread = options.sim_count - sim_idx;
}
TPCE::Thread<TPCE::BucketSimulator> *thr =
new TPCE::Thread<TPCE::BucketSimulator>(std::unique_ptr<TPCE::BucketSimulator>(
new TPCE::BucketSimulator(options.sim_first + sim_idx, sims_per_thread, options.cust_count,
options.calc_simorders(), options.base_seed, progress)));
;
thr->start();
threads.push_back(thr);
sim_idx += sims_per_thread;
}
// Wait for all threads and find maximum standard deviation
while (!threads.empty()) {
TPCE::Thread<TPCE::BucketSimulator> *thr = threads.back();
threads.pop_back();
thr->stop();
delete thr;
}
TPCE::CDateTime now;
cout << "Maximum Standard Deviation = " << progress.max_stddev() << endl;
cout << "Requested Standard Deviation = " << options.stddev << endl;
cout << "Customer Count = " << options.cust_count << endl;
cout << "Iteration Count = " << options.sim_count << endl;
cout << "Iteration Start = " << options.sim_first << endl;
cout << "Iterations Completed = " << progress.current() << endl;
cout << "Base Seed = " << options.base_seed << endl;
cout << "Simulation Duration = " << options.run_length << endl;
cout << "tpsE = " << options.tpse << endl;
cout << "Simulation Duration = " << int64totimestr(now.DiffInMilliSeconds(start_time) / 1000) << endl;
cout << "Simulation completed at = " << now.ToStr(11) << endl;
cout << endl;
// Test against supplied standard deviation
if (progress.max_stddev() < options.stddev) {
cout << "Failed!" << endl;
exit(4); // Need a constant for this
} else {
cout << "Passed!" << endl;
}
// Successful run, exit nicely
return 0;
} catch (std::exception &e) {
cout << "Caught exception: " << e.what() << endl;
} catch (...) {
cout << "Caught unknown exception" << endl;
}
// Failed run make sure we exit with an error
exit(1);
}