benchmark silo added
[c11concurrency-benchmarks.git] / silo / benchmarks / masstree / kvtest.cc
1 #include <iostream>
2 #include <vector>
3
4 #include <unistd.h>
5
6 #include "../../btree_choice.h"
7 #include "../../thread.h"
8 #include "../../spinbarrier.h"
9 #include "../../varkey.h"
10 #include "kvrandom.hh"
11
12 using namespace std;
13 using namespace util;
14
15 struct quick_istr {
16 private:
17   char buf_[32];
18   char *bbuf_;
19 public:
20   inline quick_istr()
21   {
22     set(0);
23   }
24
25   inline quick_istr(unsigned long x, int minlen = 0)
26   {
27     set(x, minlen);
28   }
29
30   inline void
31   set(unsigned long x, int minlen = 0)
32   {
33     bbuf_ = buf_ + sizeof(buf_) - 1;
34     do {
35       *--bbuf_ = (x % 10) + '0';
36       x /= 10;
37     } while (--minlen > 0 || x != 0);
38   }
39
40   inline const char *
41   c_str()
42   {
43     buf_[sizeof(buf_) - 1] = 0;
44     return bbuf_;
45   }
46
47   inline const char *
48   data() const
49   {
50     return bbuf_;
51   }
52
53   inline size_t
54   size() const
55   {
56     return (buf_ + sizeof(buf_) - 1) - bbuf_;
57   }
58
59   inline varkey
60   key() const
61   {
62     return varkey((const uint8_t *) bbuf_, size());
63   }
64 };
65
66 template <typename T>
67 class kvtest_worker : public ndb_thread {
68 public:
69   kvtest_worker(btree &btr,
70                 spin_barrier &b,
71                 unsigned int id,
72                 const volatile bool *phases)
73     : ndb_thread(false, string("kvtest-worker")),
74       btr(&btr), b(&b), id(id), phases(phases) {}
75
76   virtual void
77   run()
78   {
79     b->count_down();
80     b->wait_for();
81     T()(*btr, id, phases);
82   }
83
84 private:
85   btree *btr;
86   spin_barrier *b;
87   unsigned int id;
88   const volatile bool *phases;
89 };
90
91 template <typename T>
92 class kvtest_runner {
93 public:
94   kvtest_runner(unsigned int nthreads)
95     : nthreads(nthreads) {}
96
97   void
98   go()
99   {
100     btree btr;
101     spin_barrier barrier(nthreads);
102     volatile bool phases[T::NPhases] = {0};
103     vector<kvtest_worker<T> *> workers;
104     for (unsigned int i = 0; i < nthreads; i++)
105       workers.push_back(new kvtest_worker<T>(btr, barrier, i, phases));
106     for (unsigned int i = 0; i < nthreads; i++)
107       workers[i]->start();
108     for (unsigned int i = 0; i < T::NPhases; i++) {
109       sleep(T::PhaseRuntimes[i]);
110       phases[i] = 1;
111       __sync_synchronize();
112     }
113     for (unsigned int i = 0; i < nthreads; i++) {
114       workers[i]->join();
115       delete workers[i];
116     }
117   }
118
119 public:
120   unsigned int nthreads;
121 };
122
123 struct kvtest_rw1 {
124   static const size_t NPhases = 2;
125   static const unsigned long PhaseRuntimes[NPhases];
126
127   typedef kvrandom_lcg_nr rand_type;
128
129   void
130   operator()(btree &btr, unsigned int id, const volatile bool *phases) const
131   {
132     const int seed = 31949 + id % 48;
133     rand_type r(seed);
134     timer t;
135     unsigned n;
136     for (n = 0; !phases[0]; ++n) {
137       const int32_t x = (int32_t) r.next();
138       const quick_istr key(x), value(x + 1);
139       btree::value_type v = (btree::value_type) malloc(value.size());
140       NDB_MEMCPY(v, value.data(), value.size());
141       btr.insert(key.key(), v, 0, 0);
142     }
143     const double put_ms = t.lap_ms();
144     int32_t *a = (int32_t *) malloc(sizeof(int32_t) * n);
145     r.reset(seed);
146     for (unsigned i = 0; i < n; i++)
147       a[i] = (int32_t) r.next();
148     for (unsigned i = 0; i < n; ++i)
149       swap(a[i], a[r.next() % n]);
150
151     t.lap();
152     unsigned g;
153     for (g = 0; g < n && !phases[1]; ++g) {
154       const quick_istr key(a[g]), value(a[g] + 1);
155       btree::value_type v = 0;
156       ALWAYS_ASSERT(btr.search(key.key(), v));
157       ALWAYS_ASSERT(memcmp(value.data(), v, value.size()) == 0);
158     }
159     const double get_ms = t.lap_ms();
160
161     cout << "puts: " << n << ", rate: " << (double(n) / (put_ms / 1000.0)) << " ops/sec/core" << endl;
162     cout << "gets: " << g << ", rate: " << (double(g) / (get_ms / 1000.0)) << " ops/sec/core" << endl;
163
164     // XXX(stephentu): free btree values
165   }
166 };
167
168 const unsigned long kvtest_rw1::PhaseRuntimes[NPhases] = { 10, 10 }; // seconds
169
170 int
171 main(int argc, char **argv)
172 {
173   ALWAYS_ASSERT(argc == 2);
174   int nthreads = atoi(argv[1]);
175   ALWAYS_ASSERT(nthreads > 0);
176   kvtest_runner<kvtest_rw1> r(nthreads);
177   r.go();
178   return 0;
179 }