modify build setup
[c11concurrency-benchmarks.git] / silo / benchmarks / bid.cc
1 #include <iostream>
2 #include <sstream>
3 #include <vector>
4 #include <utility>
5 #include <string>
6
7 #include <stdlib.h>
8 #include <unistd.h>
9
10 #include "../macros.h"
11 #include "../varkey.h"
12 #include "../thread.h"
13 #include "../util.h"
14 #include "../spinbarrier.h"
15
16 #include "../record/encoder.h"
17 #include "bench.h"
18
19 using namespace std;
20 using namespace util;
21
22 static size_t nusers;
23 static size_t nproducts;
24 static const float pricefactor = 10000.0; // bids range from [0, 10000.0)
25
26 #define BIDUSER_REC_KEY_FIELDS(x, y) \
27   x(uint32_t,uid)
28 #define BIDUSER_REC_VALUE_FIELDS(x, y) \
29   x(uint32_t,bid)
30 DO_STRUCT(biduser_rec, BIDUSER_REC_KEY_FIELDS, BIDUSER_REC_VALUE_FIELDS)
31
32 #define BID_REC_KEY_FIELDS(x, y) \
33   x(uint32_t,uid) \
34   y(uint32_t,bid)
35 #define BID_REC_VALUE_FIELDS(x, y) \
36   x(uint32_t,pid) \
37   y(float,amount)
38 DO_STRUCT(bid_rec, BID_REC_KEY_FIELDS, BID_REC_VALUE_FIELDS)
39
40 #define BIDMAX_REC_KEY_FIELDS(x, y) \
41   x(uint32_t,pid)
42 #define BIDMAX_REC_VALUE_FIELDS(x, y) \
43   x(float,amount)
44 DO_STRUCT(bidmax_rec, BIDMAX_REC_KEY_FIELDS, BIDMAX_REC_VALUE_FIELDS)
45
46 class bid_worker : public bench_worker {
47 public:
48   bid_worker(
49       unsigned int worker_id,
50       unsigned long seed, abstract_db *db,
51       const map<string, abstract_ordered_index *> &open_tables,
52       spin_barrier *barrier_a, spin_barrier *barrier_b)
53     : bench_worker(worker_id, false, seed, db,
54                    open_tables, barrier_a, barrier_b),
55       bidusertbl(open_tables.at("biduser")),
56       bidtbl(open_tables.at("bid")),
57       bidmaxtbl(open_tables.at("bidmax"))
58   {
59   }
60
61   txn_result
62   txn_bid()
63   {
64     void *txn = db->new_txn(txn_flags, arena, txn_buf());
65     try {
66       // pick user at random
67       biduser_rec::key biduser_key(r.next() % nusers);
68       ALWAYS_ASSERT(bidusertbl->get(txn, Encode(obj_k0, biduser_key), obj_v0));
69       biduser_rec::value biduser_value_temp;
70       const biduser_rec::value *biduser_value = Decode(obj_v0, biduser_value_temp);
71
72       // update the user's bid
73       const uint32_t bid = biduser_value->bid;
74       biduser_value_temp.bid++;
75       bidusertbl->put(txn, Encode(str(), biduser_key), Encode(str(), biduser_value_temp));
76
77       // insert the new bid
78       const bid_rec::key bid_key(biduser_key.uid, bid);
79       const bid_rec::value bid_value(r.next() % nproducts, r.next_uniform() * pricefactor);
80       bidtbl->insert(txn, Encode(str(), bid_key), Encode(str(), bid_value));
81
82       // update the max value if necessary
83       const bidmax_rec::key bidmax_key(bid_value.pid);
84       ALWAYS_ASSERT(bidmaxtbl->get(txn, Encode(obj_k0, bidmax_key), obj_v0));
85       bidmax_rec::value bidmax_value_temp;
86       const bidmax_rec::value *bidmax_value = Decode(obj_v0, bidmax_value_temp);
87
88       if (bid_value.amount > bidmax_value->amount) {
89         bidmax_value_temp.amount = bid_value.amount;
90         bidmaxtbl->put(txn, Encode(str(), bidmax_key), Encode(str(), bidmax_value_temp));
91       }
92
93       if (likely(db->commit_txn(txn)))
94         return txn_result(true, 0);
95     } catch (abstract_db::abstract_abort_exception &ex) {
96       db->abort_txn(txn);
97     }
98     return txn_result(false, 0);
99   }
100
101   static txn_result
102   TxnBid(bench_worker *w)
103   {
104     return static_cast<bid_worker *>(w)->txn_bid();
105   }
106
107   virtual workload_desc_vec
108   get_workload() const
109   {
110     workload_desc_vec w;
111     w.push_back(workload_desc("Bid", 1.0, TxnBid));
112     return w;
113   }
114
115 private:
116   inline ALWAYS_INLINE string &
117   str()
118   {
119     return *arena.next();
120   }
121
122   abstract_ordered_index *bidusertbl;
123   abstract_ordered_index *bidtbl;
124   abstract_ordered_index *bidmaxtbl;
125
126   // scratch buffer space
127   string obj_k0;
128   string obj_v0;
129
130 };
131
132 class bid_loader : public bench_loader {
133 public:
134   bid_loader(unsigned long seed,
135              abstract_db *db,
136              const map<string, abstract_ordered_index *> &open_tables)
137     : bench_loader(seed, db, open_tables)
138   {}
139
140 protected:
141   virtual void
142   load()
143   {
144     abstract_ordered_index *bidusertbl = open_tables.at("biduser");
145     abstract_ordered_index *bidmaxtbl = open_tables.at("bidmax");
146     try {
147       // load
148       const size_t batchsize = (db->txn_max_batch_size() == -1) ?
149         10000 : db->txn_max_batch_size();
150       ALWAYS_ASSERT(batchsize > 0);
151
152       {
153         const size_t nbatches = nusers / batchsize;
154         if (nbatches == 0) {
155           void *txn = db->new_txn(txn_flags, arena, txn_buf());
156           for (size_t j = 0; j < nusers; j++) {
157             const biduser_rec::key key(j);
158             const biduser_rec::value value(0);
159             string buf0;
160             bidusertbl->insert(txn, Encode(key), Encode(buf0, value));
161           }
162           if (verbose)
163             cerr << "batch 1/1 done" << endl;
164           ALWAYS_ASSERT(db->commit_txn(txn));
165         } else {
166           for (size_t i = 0; i < nbatches; i++) {
167             size_t keyend = (i == nbatches - 1) ? nusers : (i + 1) * batchsize;
168             void *txn = db->new_txn(txn_flags, arena, txn_buf());
169             for (size_t j = i * batchsize; j < keyend; j++) {
170               const biduser_rec::key key(j);
171               const biduser_rec::value value(0);
172               string buf0;
173               bidusertbl->insert(txn, Encode(key), Encode(buf0, value));
174             }
175             if (verbose)
176               cerr << "batch " << (i + 1) << "/" << nbatches << " done" << endl;
177             ALWAYS_ASSERT(db->commit_txn(txn));
178           }
179         }
180         if (verbose)
181           cerr << "[INFO] finished loading BIDUSER table" << endl;
182       }
183
184       {
185         const size_t nbatches = nproducts / batchsize;
186         if (nbatches == 0) {
187           void *txn = db->new_txn(txn_flags, arena, txn_buf());
188           for (size_t j = 0; j < nproducts; j++) {
189             const bidmax_rec::key key(j);
190             const bidmax_rec::value value(0.0);
191             string buf0;
192             bidmaxtbl->insert(txn, Encode(key), Encode(buf0, value));
193           }
194           if (verbose)
195             cerr << "batch 1/1 done" << endl;
196           ALWAYS_ASSERT(db->commit_txn(txn));
197         } else {
198           for (size_t i = 0; i < nbatches; i++) {
199             size_t keyend = (i == nbatches - 1) ? nproducts : (i + 1) * batchsize;
200             void *txn = db->new_txn(txn_flags, arena, txn_buf());
201             for (size_t j = i * batchsize; j < keyend; j++) {
202               const bidmax_rec::key key(j);
203               const bidmax_rec::value value(0.0);
204               string buf0;
205               bidmaxtbl->insert(txn, Encode(key), Encode(buf0, value));
206             }
207             if (verbose)
208               cerr << "batch " << (i + 1) << "/" << nbatches << " done" << endl;
209             ALWAYS_ASSERT(db->commit_txn(txn));
210           }
211         }
212         if (verbose)
213           cerr << "[INFO] finished loading BIDMAX table" << endl;
214       }
215
216     } catch (abstract_db::abstract_abort_exception &ex) {
217       // shouldn't abort on loading!
218       ALWAYS_ASSERT(false);
219     }
220
221   }
222 };
223
224 class bid_bench_runner : public bench_runner {
225 public:
226   bid_bench_runner(abstract_db *db)
227     : bench_runner(db)
228   {
229     open_tables["biduser"] = db->open_index("biduser", sizeof(biduser_rec));
230     open_tables["bid"] = db->open_index("bid", sizeof(bid_rec));
231     open_tables["bidmax"] = db->open_index("bidmax", sizeof(bidmax_rec));
232   }
233
234 protected:
235   virtual vector<bench_loader *>
236   make_loaders()
237   {
238     vector<bench_loader *> ret;
239     ret.push_back(new bid_loader(0, db, open_tables));
240     return ret;
241   }
242
243   virtual vector<bench_worker *>
244   make_workers()
245   {
246     fast_random r(36578943);
247     vector<bench_worker *> ret;
248     for (size_t i = 0; i < nthreads; i++)
249       ret.push_back(
250         new bid_worker(
251           i, r.next(), db, open_tables,
252           &barrier_a, &barrier_b));
253     return ret;
254   }
255 };
256
257 void
258 bid_do_test(abstract_db *db, int argc, char **argv)
259 {
260   nusers = size_t(scale_factor * 1000.0);
261   nproducts = size_t(scale_factor * 1000.0);
262   ALWAYS_ASSERT(nusers > 0);
263   ALWAYS_ASSERT(nproducts > 0);
264   bid_bench_runner r(db);
265   r.run();
266 }