benchmark silo added
[c11concurrency-benchmarks.git] / silo / new-benchmarks / dbtest.cc
1 #include <iostream>
2 #include <fstream>
3 #include <sstream>
4 #include <vector>
5 #include <utility>
6 #include <string>
7 #include <set>
8
9 #include <getopt.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <sys/sysinfo.h>
13
14 #include "../allocator.h"
15 #include "../stats_server.h"
16 #include "../btree_choice.h"
17 #include "bench.h"
18
19 using namespace std;
20 using namespace util;
21
22 static vector<string>
23 split_ws(const string &s)
24 {
25   vector<string> r;
26   istringstream iss(s);
27   copy(istream_iterator<string>(iss),
28        istream_iterator<string>(),
29        back_inserter<vector<string>>(r));
30   return r;
31 }
32
33 static size_t
34 parse_memory_spec(const string &s)
35 {
36   string x(s);
37   size_t mult = 1;
38   if (x.back() == 'G') {
39     mult = static_cast<size_t>(1) << 30;
40     x.pop_back();
41   } else if (x.back() == 'M') {
42     mult = static_cast<size_t>(1) << 20;
43     x.pop_back();
44   } else if (x.back() == 'K') {
45     mult = static_cast<size_t>(1) << 10;
46     x.pop_back();
47   }
48   return strtoul(x.c_str(), nullptr, 10) * mult;
49 }
50
51 int
52 main(int argc, char **argv)
53 {
54   void (*test_fn)(const string &, const persistconfig &, int, char **) = NULL;
55   string bench_type = "ycsb";
56   string db_type = "ndb-proto2";
57   char *curdir = get_current_dir_name();
58   string basedir = curdir;
59   string bench_opts;
60   size_t numa_memory = 0;
61   free(curdir);
62   int saw_run_spec = 0;
63   persistconfig cfg;
64   string stats_server_sockfile;
65   while (1) {
66     static struct option long_options[] =
67     {
68       {"verbose"                    , no_argument       , &verbose                   , 1}   ,
69       {"parallel-loading"           , no_argument       , &enable_parallel_loading   , 1}   ,
70       {"pin-cpus"                   , no_argument       , &pin_cpus                  , 1}   ,
71       {"slow-exit"                  , no_argument       , &slow_exit                 , 1}   ,
72       {"retry-aborted-transactions" , no_argument       , &retry_aborted_transaction , 1}   ,
73       {"backoff-aborted-transactions" , no_argument     , &backoff_aborted_transaction , 1}   ,
74       {"bench"                      , required_argument , 0                          , 'b'} ,
75       {"scale-factor"               , required_argument , 0                          , 's'} ,
76       {"num-threads"                , required_argument , 0                          , 't'} ,
77       {"db-type"                    , required_argument , 0                          , 'd'} ,
78       {"basedir"                    , required_argument , 0                          , 'B'} ,
79       {"txn-flags"                  , required_argument , 0                          , 'f'} ,
80       {"runtime"                    , required_argument , 0                          , 'r'} ,
81       {"ops-per-worker"             , required_argument , 0                          , 'n'} ,
82       {"bench-opts"                 , required_argument , 0                          , 'o'} ,
83       {"numa-memory"                , required_argument , 0                          , 'm'} , // implies --pin-cpus
84       {"logfile"                    , required_argument , 0                          , 'l'} ,
85       {"assignment"                 , required_argument , 0                          , 'a'} ,
86       {"log-nofsync"                , no_argument       , &cfg.nofsync_              , 1}   ,
87       {"log-compress"               , no_argument       , &cfg.do_compress_          , 1}   ,
88       {"log-fake-writes"            , no_argument       , &cfg.fake_writes_          , 1}   ,
89       {"disable-gc"                 , no_argument       , &cfg.disable_gc_           , 1}   ,
90       {"disable-snapshots"          , no_argument       , &cfg.disable_snapshots_    , 1}   ,
91       {"stats-server-sockfile"      , required_argument , 0                          , 'x'} ,
92       {"no-reset-counters"          , no_argument       , &no_reset_counters         , 1}   ,
93       {0, 0, 0, 0}
94     };
95     int option_index = 0;
96     int c = getopt_long(argc, argv, "b:s:t:d:B:f:r:n:o:m:l:a:x:", long_options, &option_index);
97     if (c == -1)
98       break;
99
100     switch (c) {
101     case 0:
102       if (long_options[option_index].flag != 0)
103         break;
104       abort();
105       break;
106
107     case 'b':
108       bench_type = optarg;
109       break;
110
111     case 's':
112       scale_factor = strtod(optarg, NULL);
113       ALWAYS_ASSERT(scale_factor > 0.0);
114       break;
115
116     case 't':
117       nthreads = strtoul(optarg, NULL, 10);
118       ALWAYS_ASSERT(nthreads > 0);
119       break;
120
121     case 'd':
122       db_type = optarg;
123       break;
124
125     case 'B':
126       basedir = optarg;
127       break;
128
129     case 'f':
130       txn_flags = strtoul(optarg, NULL, 10);
131       break;
132
133     case 'r':
134       ALWAYS_ASSERT(!saw_run_spec);
135       saw_run_spec = 1;
136       runtime = strtoul(optarg, NULL, 10);
137       ALWAYS_ASSERT(runtime > 0);
138       run_mode = RUNMODE_TIME;
139       break;
140
141     case 'n':
142       ALWAYS_ASSERT(!saw_run_spec);
143       saw_run_spec = 1;
144       ops_per_worker = strtoul(optarg, NULL, 10);
145       ALWAYS_ASSERT(ops_per_worker > 0);
146       run_mode = RUNMODE_OPS;
147
148     case 'o':
149       bench_opts = optarg;
150       break;
151
152     case 'm':
153       {
154         pin_cpus = 1;
155         const size_t m = parse_memory_spec(optarg);
156         ALWAYS_ASSERT(m > 0);
157         numa_memory = m;
158       }
159       break;
160
161     case 'l':
162       cfg.logfiles_.emplace_back(optarg);
163       break;
164
165     case 'a':
166       cfg.assignments_.emplace_back(
167           ParseCSVString<unsigned, RangeAwareParser<unsigned>>(optarg));
168       break;
169
170     case 'x':
171       stats_server_sockfile = optarg;
172       break;
173
174     case '?':
175       /* getopt_long already printed an error message. */
176       exit(1);
177
178     default:
179       abort();
180     }
181   }
182
183   if (bench_type == "tpcc")
184     test_fn = tpcc_do_test;
185   else
186     ALWAYS_ASSERT(false);
187
188   if (cfg.do_compress_ && cfg.logfiles_.empty()) {
189     cerr << "[ERROR] --log-compress specified without logging enabled" << endl;
190     return 1;
191   }
192
193   if (cfg.fake_writes_ && cfg.logfiles_.empty()) {
194     cerr << "[ERROR] --log-fake-writes specified without logging enabled" << endl;
195     return 1;
196   }
197
198   if (cfg.nofsync_ && cfg.logfiles_.empty()) {
199     cerr << "[ERROR] --log-nofsync specified without logging enabled" << endl;
200     return 1;
201   }
202
203   if (cfg.fake_writes_ && cfg.nofsync_) {
204     cerr << "[WARNING] --log-nofsync has no effect with --log-fake-writes enabled" << endl;
205   }
206
207 #ifndef ENABLE_EVENT_COUNTERS
208   if (!stats_server_sockfile.empty()) {
209     cerr << "[WARNING] --stats-server-sockfile with no event counters enabled is useless" << endl;
210   }
211 #endif
212
213   // initialize the numa allocator
214   if (numa_memory > 0) {
215     const size_t maxpercpu = iceil(
216         numa_memory / nthreads, ::allocator::GetHugepageSize());
217     numa_memory = maxpercpu * nthreads;
218     ::allocator::Initialize(nthreads, maxpercpu);
219   }
220
221   const set<string> can_persist({"ndb-proto2"});
222   if (!cfg.logfiles_.empty() && !can_persist.count(db_type)) {
223     cerr << "[ERROR] benchmark " << db_type
224          << " does not have persistence implemented" << endl;
225     return 1;
226   }
227
228 #ifdef PROTO2_CAN_DISABLE_GC
229   const set<string> has_gc({"ndb-proto1", "ndb-proto2"});
230   if (cfg.disable_gc_ && !has_gc.count(db_type)) {
231     cerr << "[ERROR] benchmark " << db_type
232          << " does not have gc to disable" << endl;
233     return 1;
234   }
235 #else
236   if (cfg.disable_gc_) {
237     cerr << "[ERROR] macro PROTO2_CAN_DISABLE_GC was not set, cannot disable gc" << endl;
238     return 1;
239   }
240 #endif
241
242 #ifdef PROTO2_CAN_DISABLE_SNAPSHOTS
243   const set<string> has_snapshots({"ndb-proto2"});
244   if (cfg.disable_snapshots_ && !has_snapshots.count(db_type)) {
245     cerr << "[ERROR] benchmark " << db_type
246          << " does not have snapshots to disable" << endl;
247     return 1;
248   }
249 #else
250   if (cfg.disable_snapshots_) {
251     cerr << "[ERROR] macro PROTO2_CAN_DISABLE_SNAPSHOTS was not set, cannot disable snapshots" << endl;
252     return 1;
253   }
254 #endif
255 #ifdef CHECK_INVARIANTS
256   cerr << "WARNING: invariant checking is enabled - should disable for benchmark" << endl;
257 #ifdef PARANOID_CHECKING
258   cerr << "  *** Paranoid checking is enabled ***" << endl;
259 #endif
260 #endif
261
262   if (verbose) {
263     const unsigned long ncpus = coreid::num_cpus_online();
264     cerr << "Database Benchmark:"                           << endl;
265     cerr << "  pid: " << getpid()                           << endl;
266     cerr << "settings:"                                     << endl;
267     cerr << "  par-loading : " << enable_parallel_loading   << endl;
268     cerr << "  pin-cpus    : " << pin_cpus                  << endl;
269     cerr << "  slow-exit   : " << slow_exit                 << endl;
270     cerr << "  retry-txns  : " << retry_aborted_transaction << endl;
271     cerr << "  backoff-txns: " << backoff_aborted_transaction << endl;
272     cerr << "  bench       : " << bench_type                << endl;
273     cerr << "  scale       : " << scale_factor              << endl;
274     cerr << "  num-cpus    : " << ncpus                     << endl;
275     cerr << "  num-threads : " << nthreads                  << endl;
276     cerr << "  db-type     : " << db_type                   << endl;
277     cerr << "  basedir     : " << basedir                   << endl;
278     cerr << "  txn-flags   : " << hexify(txn_flags)         << endl;
279     if (run_mode == RUNMODE_TIME)
280       cerr << "  runtime     : " << runtime                 << endl;
281     else
282       cerr << "  ops/worker  : " << ops_per_worker          << endl;
283 #ifdef USE_VARINT_ENCODING
284     cerr << "  var-encode  : yes"                           << endl;
285 #else
286     cerr << "  var-encode  : no"                            << endl;
287 #endif
288
289 #ifdef USE_JEMALLOC
290     cerr << "  allocator   : jemalloc"                      << endl;
291 #elif defined USE_TCMALLOC
292     cerr << "  allocator   : tcmalloc"                      << endl;
293 #elif defined USE_FLOW
294     cerr << "  allocator   : flow"                          << endl;
295 #else
296     cerr << "  allocator   : libc"                          << endl;
297 #endif
298     if (numa_memory > 0) {
299       cerr << "  numa-memory : " << numa_memory             << endl;
300     } else {
301       cerr << "  numa-memory : disabled"                    << endl;
302     }
303     cerr << "  logfiles : " << cfg.logfiles_                << endl;
304     cerr << "  assignments : " << cfg.assignments_          << endl;
305     cerr << "  disable-gc : " << cfg.disable_gc_            << endl;
306     cerr << "  disable-snapshots : " << cfg.disable_snapshots_ << endl;
307     cerr << "  stats-server-sockfile: " << stats_server_sockfile << endl;
308
309     cerr << "system properties:" << endl;
310     cerr << "  btree_internal_node_size: " << concurrent_btree::InternalNodeSize() << endl;
311     cerr << "  btree_leaf_node_size    : " << concurrent_btree::LeafNodeSize() << endl;
312
313 #ifdef TUPLE_PREFETCH
314     cerr << "  tuple_prefetch          : yes" << endl;
315 #else
316     cerr << "  tuple_prefetch          : no" << endl;
317 #endif
318
319 #ifdef BTREE_NODE_PREFETCH
320     cerr << "  btree_node_prefetch     : yes" << endl;
321 #else
322     cerr << "  btree_node_prefetch     : no" << endl;
323 #endif
324
325   }
326
327   if (!stats_server_sockfile.empty()) {
328     stats_server *srvr = new stats_server(stats_server_sockfile);
329     thread(&stats_server::serve_forever, srvr).detach();
330   }
331
332   vector<string> bench_toks = split_ws(bench_opts);
333   int argc = 1 + bench_toks.size();
334   char *argv[argc];
335   argv[0] = (char *) bench_type.c_str();
336   for (size_t i = 1; i <= bench_toks.size(); i++)
337     argv[i] = (char *) bench_toks[i - 1].c_str();
338   test_fn(db_type, cfg, argc, argv);
339   return 0;
340 }