12 #include <sys/sysinfo.h>
14 #include "../allocator.h"
15 #include "../stats_server.h"
17 #include "bdb_wrapper.h"
18 #include "ndb_wrapper.h"
19 #include "ndb_wrapper_impl.h"
20 #include "kvdb_wrapper.h"
21 #include "kvdb_wrapper_impl.h"
23 #include "mysql_wrapper.h"
30 split_ws(const string &s)
34 copy(istream_iterator<string>(iss),
35 istream_iterator<string>(),
36 back_inserter<vector<string>>(r));
41 parse_memory_spec(const string &s)
45 if (x.back() == 'G') {
46 mult = static_cast<size_t>(1) << 30;
48 } else if (x.back() == 'M') {
49 mult = static_cast<size_t>(1) << 20;
51 } else if (x.back() == 'K') {
52 mult = static_cast<size_t>(1) << 10;
55 return strtoul(x.c_str(), nullptr, 10) * mult;
59 main(int argc, char **argv)
61 abstract_db *db = NULL;
62 void (*test_fn)(abstract_db *, int argc, char **argv) = NULL;
63 string bench_type = "ycsb";
64 string db_type = "ndb-proto2";
65 char *curdir = get_current_dir_name();
66 string basedir = curdir;
68 size_t numa_memory = 0;
75 int disable_snapshots = 0;
76 vector<string> logfiles;
77 vector<vector<unsigned>> assignments;
78 string stats_server_sockfile;
80 static struct option long_options[] =
82 {"verbose" , no_argument , &verbose , 1} ,
83 {"parallel-loading" , no_argument , &enable_parallel_loading , 1} ,
84 {"pin-cpus" , no_argument , &pin_cpus , 1} ,
85 {"slow-exit" , no_argument , &slow_exit , 1} ,
86 {"retry-aborted-transactions" , no_argument , &retry_aborted_transaction , 1} ,
87 {"backoff-aborted-transactions" , no_argument , &backoff_aborted_transaction , 1} ,
88 {"bench" , required_argument , 0 , 'b'} ,
89 {"scale-factor" , required_argument , 0 , 's'} ,
90 {"num-threads" , required_argument , 0 , 't'} ,
91 {"db-type" , required_argument , 0 , 'd'} ,
92 {"basedir" , required_argument , 0 , 'B'} ,
93 {"txn-flags" , required_argument , 0 , 'f'} ,
94 {"runtime" , required_argument , 0 , 'r'} ,
95 {"ops-per-worker" , required_argument , 0 , 'n'} ,
96 {"bench-opts" , required_argument , 0 , 'o'} ,
97 {"numa-memory" , required_argument , 0 , 'm'} , // implies --pin-cpus
98 {"logfile" , required_argument , 0 , 'l'} ,
99 {"assignment" , required_argument , 0 , 'a'} ,
100 {"log-nofsync" , no_argument , &nofsync , 1} ,
101 {"log-compress" , no_argument , &do_compress , 1} ,
102 {"log-fake-writes" , no_argument , &fake_writes , 1} ,
103 {"disable-gc" , no_argument , &disable_gc , 1} ,
104 {"disable-snapshots" , no_argument , &disable_snapshots , 1} ,
105 {"stats-server-sockfile" , required_argument , 0 , 'x'} ,
106 {"no-reset-counters" , no_argument , &no_reset_counters , 1} ,
109 int option_index = 0;
110 int c = getopt_long(argc, argv, "b:s:t:d:B:f:r:n:o:m:l:a:x:", long_options, &option_index);
116 if (long_options[option_index].flag != 0)
126 scale_factor = strtod(optarg, NULL);
127 ALWAYS_ASSERT(scale_factor > 0.0);
131 nthreads = strtoul(optarg, NULL, 10);
132 ALWAYS_ASSERT(nthreads > 0);
144 txn_flags = strtoul(optarg, NULL, 10);
148 ALWAYS_ASSERT(!saw_run_spec);
150 runtime = strtoul(optarg, NULL, 10);
151 ALWAYS_ASSERT(runtime > 0);
152 run_mode = RUNMODE_TIME;
156 ALWAYS_ASSERT(!saw_run_spec);
158 ops_per_worker = strtoul(optarg, NULL, 10);
159 ALWAYS_ASSERT(ops_per_worker > 0);
160 run_mode = RUNMODE_OPS;
169 const size_t m = parse_memory_spec(optarg);
170 ALWAYS_ASSERT(m > 0);
176 logfiles.emplace_back(optarg);
180 assignments.emplace_back(
181 ParseCSVString<unsigned, RangeAwareParser<unsigned>>(optarg));
185 stats_server_sockfile = optarg;
189 /* getopt_long already printed an error message. */
197 if (bench_type == "ycsb")
198 test_fn = ycsb_do_test;
199 else if (bench_type == "tpcc")
200 test_fn = tpcc_do_test;
201 else if (bench_type == "queue")
202 test_fn = queue_do_test;
203 else if (bench_type == "encstress")
204 test_fn = encstress_do_test;
205 else if (bench_type == "bid")
206 test_fn = bid_do_test;
208 ALWAYS_ASSERT(false);
210 if (do_compress && logfiles.empty()) {
211 cerr << "[ERROR] --log-compress specified without logging enabled" << endl;
215 if (fake_writes && logfiles.empty()) {
216 cerr << "[ERROR] --log-fake-writes specified without logging enabled" << endl;
220 if (nofsync && logfiles.empty()) {
221 cerr << "[ERROR] --log-nofsync specified without logging enabled" << endl;
225 if (fake_writes && nofsync) {
226 cerr << "[WARNING] --log-nofsync has no effect with --log-fake-writes enabled" << endl;
229 #ifndef ENABLE_EVENT_COUNTERS
230 if (!stats_server_sockfile.empty()) {
231 cerr << "[WARNING] --stats-server-sockfile with no event counters enabled is useless" << endl;
235 // initialize the numa allocator
236 if (numa_memory > 0) {
237 const size_t maxpercpu = util::iceil(
238 numa_memory / nthreads, ::allocator::GetHugepageSize());
239 numa_memory = maxpercpu * nthreads;
240 ::allocator::Initialize(nthreads, maxpercpu);
243 const set<string> can_persist({"ndb-proto2"});
244 if (!logfiles.empty() && !can_persist.count(db_type)) {
245 cerr << "[ERROR] benchmark " << db_type
246 << " does not have persistence implemented" << endl;
250 #ifdef PROTO2_CAN_DISABLE_GC
251 const set<string> has_gc({"ndb-proto1", "ndb-proto2"});
252 if (disable_gc && !has_gc.count(db_type)) {
253 cerr << "[ERROR] benchmark " << db_type
254 << " does not have gc to disable" << endl;
259 cerr << "[ERROR] macro PROTO2_CAN_DISABLE_GC was not set, cannot disable gc" << endl;
264 #ifdef PROTO2_CAN_DISABLE_SNAPSHOTS
265 const set<string> has_snapshots({"ndb-proto2"});
266 if (disable_snapshots && !has_snapshots.count(db_type)) {
267 cerr << "[ERROR] benchmark " << db_type
268 << " does not have snapshots to disable" << endl;
272 if (disable_snapshots) {
273 cerr << "[ERROR] macro PROTO2_CAN_DISABLE_SNAPSHOTS was not set, cannot disable snapshots" << endl;
278 if (db_type == "bdb") {
279 const string cmd = "rm -rf " + basedir + "/db/*";
280 // XXX(stephentu): laziness
281 int ret UNUSED = system(cmd.c_str());
282 db = new bdb_wrapper("db", bench_type + ".db");
283 } else if (db_type == "ndb-proto1") {
284 // XXX: hacky simulation of proto1
285 db = new ndb_wrapper<transaction_proto2>(
286 logfiles, assignments, !nofsync, do_compress, fake_writes);
287 transaction_proto2_static::set_hack_status(true);
288 ALWAYS_ASSERT(transaction_proto2_static::get_hack_status());
289 #ifdef PROTO2_CAN_DISABLE_GC
291 transaction_proto2_static::InitGC();
293 } else if (db_type == "ndb-proto2") {
294 db = new ndb_wrapper<transaction_proto2>(
295 logfiles, assignments, !nofsync, do_compress, fake_writes);
296 ALWAYS_ASSERT(!transaction_proto2_static::get_hack_status());
297 #ifdef PROTO2_CAN_DISABLE_GC
299 transaction_proto2_static::InitGC();
301 #ifdef PROTO2_CAN_DISABLE_SNAPSHOTS
302 if (disable_snapshots)
303 transaction_proto2_static::DisableSnapshots();
305 } else if (db_type == "kvdb") {
306 db = new kvdb_wrapper<true>;
307 } else if (db_type == "kvdb-st") {
308 db = new kvdb_wrapper<false>;
310 } else if (db_type == "mysql") {
311 string dbdir = basedir + "/mysql-db";
312 db = new mysql_wrapper(dbdir, bench_type);
315 ALWAYS_ASSERT(false);
318 cerr << "WARNING: benchmark built in DEBUG mode!!!" << endl;
321 #ifdef CHECK_INVARIANTS
322 cerr << "WARNING: invariant checking is enabled - should disable for benchmark" << endl;
323 #ifdef PARANOID_CHECKING
324 cerr << " *** Paranoid checking is enabled ***" << endl;
329 const unsigned long ncpus = coreid::num_cpus_online();
330 cerr << "Database Benchmark:" << endl;
331 cerr << " pid: " << getpid() << endl;
332 cerr << "settings:" << endl;
333 cerr << " par-loading : " << enable_parallel_loading << endl;
334 cerr << " pin-cpus : " << pin_cpus << endl;
335 cerr << " slow-exit : " << slow_exit << endl;
336 cerr << " retry-txns : " << retry_aborted_transaction << endl;
337 cerr << " backoff-txns: " << backoff_aborted_transaction << endl;
338 cerr << " bench : " << bench_type << endl;
339 cerr << " scale : " << scale_factor << endl;
340 cerr << " num-cpus : " << ncpus << endl;
341 cerr << " num-threads : " << nthreads << endl;
342 cerr << " db-type : " << db_type << endl;
343 cerr << " basedir : " << basedir << endl;
344 cerr << " txn-flags : " << hexify(txn_flags) << endl;
345 if (run_mode == RUNMODE_TIME)
346 cerr << " runtime : " << runtime << endl;
348 cerr << " ops/worker : " << ops_per_worker << endl;
349 #ifdef USE_VARINT_ENCODING
350 cerr << " var-encode : yes" << endl;
352 cerr << " var-encode : no" << endl;
356 cerr << " allocator : jemalloc" << endl;
357 #elif defined USE_TCMALLOC
358 cerr << " allocator : tcmalloc" << endl;
359 #elif defined USE_FLOW
360 cerr << " allocator : flow" << endl;
362 cerr << " allocator : libc" << endl;
364 if (numa_memory > 0) {
365 cerr << " numa-memory : " << numa_memory << endl;
367 cerr << " numa-memory : disabled" << endl;
369 cerr << " logfiles : " << logfiles << endl;
370 cerr << " assignments : " << assignments << endl;
371 cerr << " disable-gc : " << disable_gc << endl;
372 cerr << " disable-snapshots : " << disable_snapshots << endl;
373 cerr << " stats-server-sockfile: " << stats_server_sockfile << endl;
375 cerr << "system properties:" << endl;
376 cerr << " btree_internal_node_size: " << concurrent_btree::InternalNodeSize() << endl;
377 cerr << " btree_leaf_node_size : " << concurrent_btree::LeafNodeSize() << endl;
379 #ifdef TUPLE_PREFETCH
380 cerr << " tuple_prefetch : yes" << endl;
382 cerr << " tuple_prefetch : no" << endl;
385 #ifdef BTREE_NODE_PREFETCH
386 cerr << " btree_node_prefetch : yes" << endl;
388 cerr << " btree_node_prefetch : no" << endl;
393 if (!stats_server_sockfile.empty()) {
394 stats_server *srvr = new stats_server(stats_server_sockfile);
395 thread(&stats_server::serve_forever, srvr).detach();
398 vector<string> bench_toks = split_ws(bench_opts);
399 int argc = 1 + bench_toks.size();
401 argv[0] = (char *) bench_type.c_str();
402 for (size_t i = 1; i <= bench_toks.size(); i++)
403 argv[i] = (char *) bench_toks[i - 1].c_str();
404 test_fn(db, argc, argv);