benchmark silo added
[c11concurrency-benchmarks.git] / silo / benchmarks / masstree / kvtest.cc
diff --git a/silo/benchmarks/masstree/kvtest.cc b/silo/benchmarks/masstree/kvtest.cc
new file mode 100644 (file)
index 0000000..f14f688
--- /dev/null
@@ -0,0 +1,179 @@
+#include <iostream>
+#include <vector>
+
+#include <unistd.h>
+
+#include "../../btree_choice.h"
+#include "../../thread.h"
+#include "../../spinbarrier.h"
+#include "../../varkey.h"
+#include "kvrandom.hh"
+
+using namespace std;
+using namespace util;
+
+struct quick_istr {
+private:
+  char buf_[32];
+  char *bbuf_;
+public:
+  inline quick_istr()
+  {
+    set(0);
+  }
+
+  inline quick_istr(unsigned long x, int minlen = 0)
+  {
+    set(x, minlen);
+  }
+
+  inline void
+  set(unsigned long x, int minlen = 0)
+  {
+    bbuf_ = buf_ + sizeof(buf_) - 1;
+    do {
+      *--bbuf_ = (x % 10) + '0';
+      x /= 10;
+    } while (--minlen > 0 || x != 0);
+  }
+
+  inline const char *
+  c_str()
+  {
+    buf_[sizeof(buf_) - 1] = 0;
+    return bbuf_;
+  }
+
+  inline const char *
+  data() const
+  {
+    return bbuf_;
+  }
+
+  inline size_t
+  size() const
+  {
+    return (buf_ + sizeof(buf_) - 1) - bbuf_;
+  }
+
+  inline varkey
+  key() const
+  {
+    return varkey((const uint8_t *) bbuf_, size());
+  }
+};
+
+template <typename T>
+class kvtest_worker : public ndb_thread {
+public:
+  kvtest_worker(btree &btr,
+                spin_barrier &b,
+                unsigned int id,
+                const volatile bool *phases)
+    : ndb_thread(false, string("kvtest-worker")),
+      btr(&btr), b(&b), id(id), phases(phases) {}
+
+  virtual void
+  run()
+  {
+    b->count_down();
+    b->wait_for();
+    T()(*btr, id, phases);
+  }
+
+private:
+  btree *btr;
+  spin_barrier *b;
+  unsigned int id;
+  const volatile bool *phases;
+};
+
+template <typename T>
+class kvtest_runner {
+public:
+  kvtest_runner(unsigned int nthreads)
+    : nthreads(nthreads) {}
+
+  void
+  go()
+  {
+    btree btr;
+    spin_barrier barrier(nthreads);
+    volatile bool phases[T::NPhases] = {0};
+    vector<kvtest_worker<T> *> workers;
+    for (unsigned int i = 0; i < nthreads; i++)
+      workers.push_back(new kvtest_worker<T>(btr, barrier, i, phases));
+    for (unsigned int i = 0; i < nthreads; i++)
+      workers[i]->start();
+    for (unsigned int i = 0; i < T::NPhases; i++) {
+      sleep(T::PhaseRuntimes[i]);
+      phases[i] = 1;
+      __sync_synchronize();
+    }
+    for (unsigned int i = 0; i < nthreads; i++) {
+      workers[i]->join();
+      delete workers[i];
+    }
+  }
+
+public:
+  unsigned int nthreads;
+};
+
+struct kvtest_rw1 {
+  static const size_t NPhases = 2;
+  static const unsigned long PhaseRuntimes[NPhases];
+
+  typedef kvrandom_lcg_nr rand_type;
+
+  void
+  operator()(btree &btr, unsigned int id, const volatile bool *phases) const
+  {
+    const int seed = 31949 + id % 48;
+    rand_type r(seed);
+    timer t;
+    unsigned n;
+    for (n = 0; !phases[0]; ++n) {
+      const int32_t x = (int32_t) r.next();
+      const quick_istr key(x), value(x + 1);
+      btree::value_type v = (btree::value_type) malloc(value.size());
+      NDB_MEMCPY(v, value.data(), value.size());
+      btr.insert(key.key(), v, 0, 0);
+    }
+    const double put_ms = t.lap_ms();
+    int32_t *a = (int32_t *) malloc(sizeof(int32_t) * n);
+    r.reset(seed);
+    for (unsigned i = 0; i < n; i++)
+      a[i] = (int32_t) r.next();
+    for (unsigned i = 0; i < n; ++i)
+      swap(a[i], a[r.next() % n]);
+
+    t.lap();
+    unsigned g;
+    for (g = 0; g < n && !phases[1]; ++g) {
+      const quick_istr key(a[g]), value(a[g] + 1);
+      btree::value_type v = 0;
+      ALWAYS_ASSERT(btr.search(key.key(), v));
+      ALWAYS_ASSERT(memcmp(value.data(), v, value.size()) == 0);
+    }
+    const double get_ms = t.lap_ms();
+
+    cout << "puts: " << n << ", rate: " << (double(n) / (put_ms / 1000.0)) << " ops/sec/core" << endl;
+    cout << "gets: " << g << ", rate: " << (double(g) / (get_ms / 1000.0)) << " ops/sec/core" << endl;
+
+    // XXX(stephentu): free btree values
+  }
+};
+
+const unsigned long kvtest_rw1::PhaseRuntimes[NPhases] = { 10, 10 }; // seconds
+
+int
+main(int argc, char **argv)
+{
+  ALWAYS_ASSERT(argc == 2);
+  int nthreads = atoi(argv[1]);
+  ALWAYS_ASSERT(nthreads > 0);
+  kvtest_runner<kvtest_rw1> r(nthreads);
+  r.go();
+  return 0;
+}