/* * 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 #include #include #include #include #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(tpse * static_cast(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(strtoint64(arg)); break; case 'i': options.sim_first = static_cast(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(strtoint64(arg)); break; case 's': options.use_stddev = true; options.stddev = strtodbl(arg); break; case 'u': options.interval_time = static_cast(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(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 *> 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 *thr = new TPCE::Thread(std::unique_ptr( 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 *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); }