2 * Eddie Kohler, Yandong Mao, Robert Morris
3 * Copyright (c) 2012-2013 President and Fellows of Harvard College
4 * Copyright (c) 2012-2013 Massachusetts Institute of Technology
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, subject to the conditions
9 * listed in the Masstree LICENSE file. These conditions include: you must
10 * preserve this copyright notice, and you cannot mention the copyright
11 * holders in advertising related to the Software without their permission.
12 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
13 * notice is a summary of the Masstree LICENSE file; the license in that file
27 extern int kvtest_first_seed;
28 // Templated KV tests, so we can run them either client/server or linked with
32 inline Json& kvtest_set_time(Json& result, const lcdf::String& base, N n, double delta_t)
36 result.set(base + "_per_sec", n / delta_t);
41 inline Json kvtest_set_time(const Json& result, const lcdf::String& base, N n, double delta_t) {
43 kvtest_set_time(x, base, n, delta_t);
48 void kvtest_sync_rw1_seed(C &client, int seed)
50 client.rand.reset(seed);
51 double tp0 = client.now();
53 for (n = 0; !client.timeout(0) && n <= client.limit(); ++n) {
54 int32_t x = (int32_t) client.rand.next();
55 client.put_sync(x, x + 1);
58 double tp1 = client.now();
61 client.notice("now getting\n");
62 int32_t *a = (int32_t *) malloc(sizeof(int32_t) * n);
64 client.rand.reset(seed);
65 for (unsigned i = 0; i < n; ++i)
66 a[i] = (int32_t) client.rand.next();
67 for (unsigned i = 0; i < n; ++i)
68 std::swap(a[i], a[client.rand.next() % n]);
70 double tg0 = client.now();
72 for (g = 0; g < n && !client.timeout(1); ++g)
73 client.get_check_sync(a[g], a[g] + 1);
75 double tg1 = client.now();
78 kvtest_set_time(result, "puts", n, tp1 - tp0);
79 kvtest_set_time(result, "gets", g, tg1 - tg0);
80 kvtest_set_time(result, "ops", n + g, (tp1 - tp0) + (tg1 - tg0));
81 client.report(result);
86 void kvtest_sync_rw1(C &client)
88 kvtest_sync_rw1_seed(client, kvtest_first_seed + client.id() % 48);
92 unsigned kvtest_rw1puts_seed(C& client, int seed) {
93 client.rand.reset(seed);
94 double tp0 = client.now();
96 for (n = 0; !client.timeout(0) && n <= client.limit(); ++n) {
97 int32_t x = (int32_t) client.rand.next();
101 double tp1 = client.now();
104 client.report(kvtest_set_time(Json(), "puts", n, tp1 - tp0));
108 // do a bunch of inserts to distinct keys, then check that they all showed up.
109 // sometimes overwrites, but only w/ same value.
110 // different clients might use same key sometimes.
111 template <typename C>
112 void kvtest_rw1_seed(C &client, int seed)
114 unsigned n = kvtest_rw1puts_seed(client, seed);
116 client.notice("now getting\n");
117 int32_t *a = (int32_t *) malloc(sizeof(int32_t) * n);
119 client.rand.reset(seed);
120 for (unsigned i = 0; i < n; ++i)
121 a[i] = (int32_t) client.rand.next();
122 for (unsigned i = 0; i < n; ++i)
123 std::swap(a[i], a[client.rand.next() % n]);
125 double tg0 = client.now();
129 for(g = 0; g+BATCH < n && !client.timeout(1); g += BATCH){
130 long key[BATCH], expected[BATCH];
131 for(int i = 0; i < BATCH; i++){
133 expected[i] = a[g+i] + 1;
135 client.many_get_check(BATCH, key, expected);
138 for (g = 0; g < n && !client.timeout(1); ++g)
139 client.get_check(a[g], a[g] + 1);
142 double tg1 = client.now();
144 Json result = client.report(Json());
145 kvtest_set_time(result, "gets", g, tg1 - tg0);
146 double delta_puts = n / result["puts_per_sec"].as_d();
147 kvtest_set_time(result, "ops", n + g, delta_puts + (tg1 - tg0));
148 client.report(result);
152 template <typename C>
153 void kvtest_rw1puts(C &client)
155 kvtest_rw1puts_seed(client, kvtest_first_seed + client.id() % 48);
158 template <typename C>
159 void kvtest_rw1(C &client)
161 kvtest_rw1_seed(client, kvtest_first_seed + client.id() % 48);
164 // do a bunch of inserts to distinct keys, then check that they all showed up.
165 // sometimes overwrites, but only w/ same value.
166 // different clients might use same key sometimes.
167 template <typename C>
168 void kvtest_rw1long_seed(C &client, int seed)
170 const char * const formats[] = {
171 "user%u", "machine%u", "opening%u", "fartparade%u"
175 client.rand.reset(seed);
176 double tp0 = client.now();
178 for (n = 0; !client.timeout(0) && n <= client.limit(); ++n) {
179 unsigned fmt = client.rand.next();
180 int32_t x = (int32_t) client.rand.next();
181 client.put(Str::snprintf(buf, sizeof(buf), formats[fmt % 4], x), x + 1);
184 double tp1 = client.now();
187 client.notice("now getting\n");
188 int32_t *a = (int32_t *) malloc(sizeof(int32_t) * n * 2);
190 client.rand.reset(seed);
191 for (unsigned i = 0; i < n * 2; ++i)
192 a[i] = (int32_t) client.rand.next();
193 for (unsigned i = 0; i < n; ++i) {
194 unsigned x = client.rand.next() % n;
195 std::swap(a[2 * i], a[2 * x]);
196 std::swap(a[2 * i + 1], a[2 * x + 1]);
199 double tg0 = client.now();
201 for (g = 0; g < n && !client.timeout(1); ++g) {
202 unsigned fmt = a[2 * g];
203 int32_t x = (int32_t) a[2 * g + 1];
204 client.get_check(Str::snprintf(buf, sizeof(buf), formats[fmt % 4], x), x + 1);
207 double tg1 = client.now();
209 Json result = Json();
210 kvtest_set_time(result, "puts", n, tp1 - tp0);
211 kvtest_set_time(result, "gets", g, tg1 - tg0);
212 kvtest_set_time(result, "ops", n + g, (tp1 - tp0) + (tg1 - tg0));
213 client.report(result);
217 template <typename C>
218 void kvtest_rw1long(C &client)
220 kvtest_rw1long_seed(client, kvtest_first_seed + client.id() % 48);
223 // interleave inserts and gets for random keys.
224 template <typename C>
225 void kvtest_rw2_seed(C &client, int seed, double getfrac)
227 client.rand.reset(seed);
228 const unsigned c = 2654435761U;
229 const unsigned offset = client.rand.next();
231 double t0 = client.now();
232 uint64_t puts = 0, gets = 0;
233 int getfrac65536 = (int) (getfrac * 65536 + 0.5);
234 while (!client.timeout(0) && (puts + gets) <= client.limit()) {
235 if (puts == 0 || (client.rand.next() % 65536) >= getfrac65536) {
237 unsigned x = (offset + puts) * c;
238 client.put(x, x + 1);
242 unsigned x = (offset + (client.rand.next() % puts)) * c;
243 client.get_check(x, x + 1);
248 double t1 = client.now();
250 Json result = Json().set("puts", puts).set("gets", gets);
251 kvtest_set_time(result, "ops", puts + gets, t1 - t0);
252 client.report(result);
255 template <typename C>
256 void kvtest_rw2(C &client)
258 kvtest_rw2_seed(client, kvtest_first_seed + client.id() % 48, 0.5);
261 template <typename C>
262 void kvtest_rw2g90(C &client)
264 kvtest_rw2_seed(client, kvtest_first_seed + client.id() % 48, 0.9);
267 template <typename C>
268 void kvtest_rw2g98(C &client)
270 kvtest_rw2_seed(client, kvtest_first_seed + client.id() % 48, 0.98);
273 // interleave inserts and gets for random keys.
274 template <typename C>
275 void kvtest_rw2fixed_seed(C &client, int seed, double getfrac)
277 client.rand.reset(seed);
278 const unsigned c = 2654435761U;
279 const unsigned offset = client.rand.next();
281 double t0 = client.now();
282 uint64_t puts = 0, gets = 0;
283 int getfrac65536 = (int) (getfrac * 65536 + 0.5);
284 while (!client.timeout(0) && (puts + gets) <= client.limit()) {
285 if (puts == 0 || (client.rand.next() % 65536) >= getfrac65536) {
287 unsigned x = (offset + puts) * c;
289 client.put(x, x + 1);
293 unsigned x = (offset + (client.rand.next() % puts)) * c;
295 client.get_check(x, x + 1);
300 double t1 = client.now();
302 Json result = Json().set("puts", puts).set("gets", gets);
303 kvtest_set_time(result, "ops", puts + gets, t1 - t0);
304 client.report(result);
307 template <typename C>
308 void kvtest_rw2fixed(C &client)
310 kvtest_rw2fixed_seed(client, kvtest_first_seed + client.id() % 48, 0.5);
313 template <typename C>
314 void kvtest_rw2fixedg90(C &client)
316 kvtest_rw2fixed_seed(client, kvtest_first_seed + client.id() % 48, 0.9);
319 template <typename C>
320 void kvtest_rw2fixedg98(C &client)
322 kvtest_rw2fixed_seed(client, kvtest_first_seed + client.id() % 48, 0.98);
325 // do a bunch of inserts to sequentially increasing keys,
326 // then check that they all showed up.
327 // different clients might use same key sometimes.
328 template <typename C>
329 void kvtest_rw3(C &client)
331 double t0 = client.now();
333 for (n = 0; !client.timeout(0) && n <= client.limit(); ++n)
334 client.put_key8(n, n + 1);
338 client.notice("now getting\n");
340 double t1 = client.now();
341 for (unsigned i = 0; i < n; ++i)
342 client.get_check_key8(i, i + 1);
345 double t2 = client.now();
347 Json result = Json();
348 kvtest_set_time(result, "puts", n, t1 - t0);
349 kvtest_set_time(result, "gets", n, t2 - t1);
350 kvtest_set_time(result, "ops", n + n, t2 - t0);
351 client.report(result);
354 // do a bunch of inserts to sequentially decreasing keys,
355 // then check that they all showed up.
356 // different clients might use same key sometimes.
357 template <typename C>
358 void kvtest_rw4(C &client)
360 const int top = 2147483647;
362 double t0 = client.now();
364 for (n = 0; !client.timeout(0) && n <= client.limit(); ++n)
365 client.put_key8(top - n, n + 1);
369 client.notice("now getting\n");
371 double t1 = client.now();
372 for (unsigned i = 0; i < n; ++i)
373 client.get_check_key8(top - i, i + 1);
376 double t2 = client.now();
378 Json result = Json();
379 kvtest_set_time(result, "puts", n, t1 - t0);
380 kvtest_set_time(result, "gets", n, t2 - t1);
381 kvtest_set_time(result, "ops", n + n, t2 - t0);
382 client.report(result);
385 // do a bunch of inserts to sequentially decreasing 8B keys,
386 // then check that they all showed up.
387 // different clients might use same key sometimes.
388 template <typename C>
389 void kvtest_rw4fixed(C &client)
391 const int top = 99999999;
393 double t0 = client.now();
395 for (n = 0; !client.timeout(0) && n <= client.limit(); ++n)
396 client.put_key8(top - n, n + 1);
400 client.notice("now getting\n");
402 double t1 = client.now();
403 for (unsigned i = 0; i < n; ++i)
404 client.get_check_key8(top - i, i + 1);
407 double t2 = client.now();
409 Json result = Json();
410 kvtest_set_time(result, "puts", n, t1 - t0);
411 kvtest_set_time(result, "gets", n, t2 - t1);
412 kvtest_set_time(result, "ops", n + n, t2 - t0);
413 client.report(result);
416 // update the same small set of keys over and over,
417 // to uncover concurrent update bugs in the server.
418 template <typename C>
419 void kvtest_same_seed(C &client, int seed)
421 client.rand.reset(seed);
423 double t0 = client.now();
425 for (n = 0; !client.timeout(0) && n <= client.limit(); ++n) {
426 unsigned x = client.rand.next() % 10;
427 client.put(x, x + 1);
430 double t1 = client.now();
432 Json result = Json();
433 kvtest_set_time(result, "puts", n, t1 - t0);
434 client.report(result);
437 template <typename C>
438 void kvtest_same(C &client)
440 kvtest_same_seed(client, kvtest_first_seed + client.id() % 48);
443 // update the same small set of keys over and over, with interspersed gets.
444 template <typename C>
445 void kvtest_rwsmall_seed(C &client, int nkeys, int seed)
447 client.rand.reset(seed);
449 double t0 = client.now();
451 for (n = 0; !client.timeout(0) && n <= client.limit(); ++n) {
452 unsigned x = client.rand.next() % (8 * nkeys);
456 client.put(x >> 3, n);
459 double t1 = client.now();
461 Json result = Json();
462 kvtest_set_time(result, "ops", n, t1 - t0);
463 client.report(result);
466 template <typename C>
467 void kvtest_rwsmall24(C &client)
469 kvtest_rwsmall_seed(client, 24, kvtest_first_seed + client.id() % 48);
472 // update the same small set of keys over and over, with interspersed gets.
473 // but ensure that the keys are all on different cache lines.
474 template <typename C>
475 void kvtest_rwsep_seed(C &client, int nkeys, int clientid, int seed)
477 for (int n = clientid * (32 + nkeys); n < (clientid + 1) * (32 + nkeys); ++n)
478 client.put(1000000 + n, n);
480 client.rand.reset(seed);
482 double t0 = client.now();
484 for (n = 0; !client.timeout(0) && n <= client.limit(); ++n) {
485 unsigned x = client.rand.next() % (8 * nkeys);
487 client.get(1000000 + clientid * (32 + nkeys) + (x >> 3));
489 client.put(1000000 + clientid * (32 + nkeys) + (x >> 3), n);
492 double t1 = client.now();
494 Json result = Json();
495 kvtest_set_time(result, "ops", n, t1 - t0);
496 client.report(result);
499 template <typename C>
500 void kvtest_rwsep24(C &client)
502 kvtest_rwsep_seed(client, 24, client.id(), kvtest_first_seed + client.id() % 48);
505 // Same as rw1, except that the keys are no more than 8 bytes
506 template <typename C>
507 void kvtest_rw1fixed_seed(C &client, int seed)
509 client.rand.reset(seed);
510 double tp0 = client.now();
512 for (n = 0; !client.timeout(0) && n <= client.limit(); ++n) {
513 int32_t x = (int32_t) client.rand.next();
515 client.put(x, x + 1);
518 double tp1 = client.now();
521 client.notice("now getting\n");
522 int32_t *a = (int32_t *) malloc(sizeof(int32_t) * n);
524 client.rand.reset(seed);
525 for (unsigned i = 0; i < n; ++i) {
526 a[i] = (int32_t) client.rand.next();
529 for (unsigned i = 0; i < n; ++i)
530 std::swap(a[i], a[client.rand.next() % n]);
532 double tg0 = client.now();
536 for(g = 0; g+BATCH < n && !client.timeout(1); g += BATCH){
537 long key[BATCH], expected[BATCH];
538 for(int i = 0; i < BATCH; i++){
540 expected[i] = a[g+i] + 1;
542 client.many_get_check(BATCH, key, expected);
545 for (g = 0; g < n && !client.timeout(1); ++g)
546 client.get_check(a[g], a[g] + 1);
549 double tg1 = client.now();
551 Json result = Json();
552 kvtest_set_time(result, "puts", n, tp1 - tp0);
553 kvtest_set_time(result, "gets", g, tg1 - tg0);
554 kvtest_set_time(result, "ops", n + g, (tp1 - tp0) + (tg1 - tg0));
555 client.report(result);
559 template <typename C>
560 void kvtest_rw1fixed(C &client)
562 kvtest_rw1fixed_seed(client, kvtest_first_seed + client.id() % 48);
565 // Same as rw1, except that keys are 16-bytes (prefixed with "0"s)
566 template <typename C>
567 void kvtest_rw16_seed(C &client, int seed)
569 client.rand.reset(seed);
570 double tp0 = client.now();
574 for (n = 0; !client.timeout(0); ++n) {
575 int32_t x = (int32_t) client.rand.next();
576 sprintf(key, "%016d", x);
577 sprintf(val, "%016d", x + 1);
578 client.put(key, val);
581 double tp1 = client.now();
584 client.notice("now getting\n");
585 int32_t *a = (int32_t *) malloc(sizeof(int32_t) * n);
587 client.rand.reset(seed);
588 for (int i = 0; i < n; ++i)
589 a[i] = (int32_t) client.rand.next();
590 for (int i = 0; i < n; ++i)
591 std::swap(a[i], a[client.rand.next() % n]);
593 double tg0 = client.now();
595 for (g = 0; g < n && !client.timeout(1); ++g) {
596 sprintf(key, "%016d", a[g]);
597 sprintf(val, "%016d", a[g] + 1);
598 client.get_check(key, val);
601 double tg1 = client.now();
603 Json result = Json();
604 kvtest_set_time(result, "puts", n, tp1 - tp0);
605 kvtest_set_time(result, "gets", g, tg1 - tg0);
606 kvtest_set_time(result, "ops", n + g, (tp1 - tp0) + (tg1 - tg0));
607 client.report(result);
611 template <typename C>
612 void kvtest_rw16(C &client)
614 kvtest_rw16_seed(client, kvtest_first_seed + client.id() % 48);
618 // A writer and a deleter; the deleter chases the writer
619 template <typename C>
620 void kvtest_wd1(unsigned initial_pos, int incr, C &client)
622 incr = std::max(incr, client.nthreads() / 2);
623 unsigned pos = initial_pos + ((client.id() / 2) % incr);
625 Json result = Json();
627 double t0 = client.now();
628 if (client.id() % 2) {
629 while (!client.get_sync(pos + 16 * incr))
631 while (!client.timeout(0)) {
633 if (client.remove_sync(pos))
635 if ((n % (1 << 16)) == 0)
636 client.rcu_quiesce();
638 result.set("removepos", pos);
640 while (!client.timeout(0)) {
642 client.put(pos, pos + 1);
644 if ((n % (1 << 16)) == 0)
645 client.rcu_quiesce();
647 result.set("putpos", pos);
650 double t1 = client.now();
652 kvtest_set_time(result, "ops", n, t1 - t0);
653 client.report(result);
656 template <typename C>
657 void kvtest_wd1_check(unsigned initial_pos, int incr, C &client)
659 incr = std::max(incr, client.nthreads() / 2);
660 unsigned pos = initial_pos + ((client.id() / 2) % incr);
662 Json result = Json();
664 double t0 = client.now();
665 if (client.id() % 2 == 0) {
666 unsigned max_remove = -1, min_post_remove = -1, max_post_remove = -1;
668 bool found_putpos = false;
669 constexpr int nbatch = 20;
671 char gottenbuf[nbatch * 16];
672 for (int i = 0; i < nbatch; ++i)
673 gotten[i].s = &gottenbuf[i * 16];
675 while (!client.timeout(0)
676 && (!found_putpos || pos < max_post_remove + 100000)) {
677 for (int i = 0; i < nbatch; ++i) {
679 client.get(pos + i * incr, &gotten[i]);
682 for (int i = 0; i < nbatch; ++i) {
684 if (min_post_remove == unsigned(-1))
685 min_post_remove = max_post_remove = pos;
686 else if (!found_putpos)
687 max_post_remove = pos;
688 else if (++bugs == 1)
689 fprintf(stderr, "%u: present unexpectedly\n", pos);
691 if (min_post_remove == unsigned(-1))
700 result.set("removepos", max_remove + incr);
701 result.set("putpos", max_post_remove + incr);
703 result.set("buggykeys", bugs);
706 double t1 = client.now();
708 kvtest_set_time(result, "ops", n, t1 - t0);
709 client.report(result);
712 template <typename C>
713 void kvtest_wd2(C &client)
715 char sbuf[32], kbuf[32], next_kbuf[32];
717 const int p_remove = 1000, p_put2 = 10000, p_remove2 = 20000;
721 client.put(Str("n"), client.nthreads());
722 always_assert(client.nthreads() > 1);
724 // set up status keys
725 snprintf(sbuf, sizeof(sbuf), "s%03d", client.id());
726 for (int i = 0; i < sep; ++i) {
728 client.put(Str(sbuf, 5), Str());
730 client.put(Str(sbuf, 4), xstr.string());
733 snprintf(kbuf, sizeof(kbuf), "k%03d", client.id());
734 for (int i = 0; i < sep; ++i) {
736 client.put(Str(kbuf, 5), Str());
738 client.put(Str(kbuf, 4), Str());
740 snprintf(next_kbuf, sizeof(next_kbuf), "k%03d", (client.id() + 1) % client.nthreads());
743 double t0 = client.now();
746 while (!client.timeout(0)) {
748 client.put(Str(kbuf, 4), xstr.string(), &put_status);
749 if ((client.rand.next() % 65536) < p_remove)
750 client.remove(Str(next_kbuf, 4));
752 int rand = client.rand.next() % 65536;
754 for (int i = sep - 1; i >= 0; --i) {
755 next_kbuf[4] = 'A' + i;
756 client.put(Str(next_kbuf, 5), Str());
758 } else if (rand < p_remove2) {
759 for (int i = sep - 1; i >= 0; --i) {
760 next_kbuf[4] = 'A' + i;
761 client.remove(Str(next_kbuf, 5));
769 if (put_status == Inserted) {
772 client.put(Str(sbuf, 4), xstr.string());
775 double t1 = client.now();
778 kvtest_set_time(result, "rounds", nrounds, t1 - t0);
779 client.report(result);
782 template <typename C>
783 void kvtest_wd2_check(C &client)
785 if (client.id() != 0)
789 client.get(Str("n"), &n);
791 always_assert(n > 1);
795 for (int i = 0; i < n; ++i) {
797 snprintf(buf, sizeof(buf), "k%03d", i);
798 client.get(Str(buf, 4), &k);
799 snprintf(buf, sizeof(buf), "s%03d", i);
800 client.get(Str(buf, 4), &s);
802 if (!(s >= 0 && (s == k || s == k + 1 || k == -1)))
803 fprintf(stderr, "problem: s%03d=%d vs. k%03d=%d\n",
805 result.set("thread" + String(i), Json().push_back(s).push_back(k));
808 client.report(result);
811 // Create a range of keys [initial_pos, initial_pos + n)
812 // where key k == initial_pos + i has value (n - 1 - i).
814 template <typename C>
815 void kvtest_tri1(unsigned initial_pos, int incr, C &client)
817 incr = std::max(incr, client.nthreads());
819 Json result = Json();
821 double t0 = client.now();
822 for (unsigned x = 0; x < client.limit(); ++x)
823 for (unsigned y = 0, z = x; y <= x; ++y, --z, ++n)
824 client.put(initial_pos + y * incr, z);
826 double t1 = client.now();
828 kvtest_set_time(result, "puts", n, t1 - t0);
829 kvtest_set_time(result, "ops", n, t1 - t0);
830 client.report(result);
833 template <typename C>
834 void kvtest_tri1_check(unsigned initial_pos, int incr, C &client)
836 incr = std::max(incr, client.nthreads());
838 Json result = Json();
840 double t0 = client.now();
841 for (unsigned x = 0; x < client.limit(); ++x, ++n)
842 client.get_check(initial_pos + x * incr, client.limit() - 1 - x);
844 double t1 = client.now();
846 kvtest_set_time(result, "gets", n, t1 - t0);
847 kvtest_set_time(result, "ops", n, t1 - t0);
848 client.report(result);
852 #define PALMN 128000000
853 enum { PalmBatch = 8192 / 24 };
854 #define PALM_DEBUG 1 // use get_check in palmb, which force palm::get
855 // to touch the cachline of the value
856 template <typename C>
857 void kvtest_palma(C &client)
859 Json result = Json();
860 double t0 = client.now();
861 for (int i = 0; i < PALMN; i++) {
866 double t1 = client.now();
867 kvtest_set_time(result, "ops", PALMN, t1 - t0);
868 client.report(result);
871 inline int compare_int(const void *a, const void *b)
873 return compare(*(uint64_t *)a, *(uint64_t *)b);
876 template <typename C>
877 void kvtest_palmb_seed(C &client, int seed)
879 Json result = Json();
880 client.rand.reset(seed);
881 double t0 = client.now();
884 uint64_t a[PalmBatch];
885 for (n = 0; !client.timeout(0); ++n) {
886 uint64_t x = (uint64_t) client.rand.next();
889 if (nquery == PalmBatch) {
890 qsort(a, PalmBatch, sizeof(a[0]), compare_int);
891 for (int j = 0; j < PalmBatch && !client.timeout(0); j++) {
893 uint64_t v = a[j] + 1;
894 client.get_check(a[j], v);
903 double t1 = client.now();
904 kvtest_set_time(result, "ops", n, t1 - t0);
905 client.report(result);
908 template <typename C>
909 void kvtest_palmb(C &client)
911 kvtest_palmb_seed(client, kvtest_first_seed + client.id() % 48);
914 template <typename C>
915 void kvtest_ycsbk_seed(C &client, int seed)
917 client.rand.reset(seed);
918 double tp0 = client.now();
920 char key[512], val[512];
921 for (n = 0; !client.timeout(0) && n < 1000000; ++n) {
924 for (int i = 0; i < 18; i++, p++)
925 key[p] = '0' + (client.rand.next() % 10);
927 int32_t v = (int32_t) client.rand.next();
928 sprintf(val, "%d", v);
929 client.put(Str(key, strlen(key)), Str(val, strlen(val)));
932 double tp1 = client.now();
935 client.notice("now getting\n");
936 client.rand.reset(seed);
937 double tg0 = client.now();
939 for (g = 0; g < n && !client.timeout(1); ++g) {
942 for (int i = 0; i < 18; i++, p++)
943 key[p] = '0' + (client.rand.next() % 10);
945 int32_t v = (int32_t) client.rand.next();
946 sprintf(val, "%d", v);
947 client.get_check(Str(key, strlen(key)), Str(val, strlen(val)));
950 double tg1 = client.now();
952 Json result = Json();
953 kvtest_set_time(result, "puts", n, tp1 - tp0);
954 kvtest_set_time(result, "gets", g, tg1 - tg0);
955 kvtest_set_time(result, "ops", n + g, (tp1 - tp0) + (tg1 - tg0));
956 client.report(result);
959 template <typename C>
960 void kvtest_ycsbk(C &client)
962 kvtest_ycsbk_seed(client, kvtest_first_seed + client.id() % 48);
965 template <typename C>
967 kvtest_bdb(C &client)
969 enum { nrec = 500000, keylen = 8, datalen = 32 };
970 char key[keylen + 1];
971 char val[datalen + 1];
972 memset(val, '^', sizeof(val));
976 for (int n = 0; n < nrec; n++) {
977 for (int i = 0; i < keylen; i++)
978 key[i] = 'a' + random() % 26;
979 client.put(key, val);
986 for (n = 0; n < 10000000; n++) {
987 for (int i = 0; i < keylen; i++)
988 key[i] = 'a' + random() % 26;
989 client.get_check(key, val);
994 Json result = Json();
995 kvtest_set_time(result, "ops", n, t1 - t0);
996 client.report(result);
999 enum { NLongParts = 16 };
1001 template <typename C>
1003 kvtest_long_init(C &client)
1005 assert(client.id() < NLongParts);
1006 int seed = kvtest_first_seed + client.id();
1007 client.rand.reset(seed);
1008 const int keylen = client.keylen();
1009 const int prefixLen = client.prefixLen();
1010 const char minkltr = client.minkeyletter();
1011 const char maxkltr = client.maxkeyletter();
1012 assert(prefixLen < keylen);
1013 const uint32_t nkeysPerPart = client.nkeys() / NLongParts;
1014 char key[512], val[512];
1016 memset(key, '^', prefixLen);
1019 for(n = 0; n < nkeysPerPart; ++n){
1020 for (int i = prefixLen; i < keylen; i++)
1021 key[i] = minkltr + client.rand.next() % (maxkltr - minkltr + 1);
1023 memcpy(val, key + keylen - 8, 8);
1024 client.put(key, val);
1030 Json result = Json();
1031 kvtest_set_time(result, "puts", n, t1 - t0);
1032 client.report(result);
1035 template <typename C>
1037 kvtest_long_go(C &client)
1039 const int keylen = client.keylen();
1040 const int prefixLen = client.prefixLen();
1041 assert(prefixLen < keylen);
1042 const uint32_t nKeysPerPart = client.nkeys() / NLongParts;
1043 const char minkltr = client.minkeyletter();
1044 const char maxkltr = client.maxkeyletter();
1045 char key[512], val[512];
1046 memset(key, '^', prefixLen);
1050 int cur_cid = client.id() % NLongParts;
1051 while (!client.timeout(0)) {
1052 client.rand.reset(kvtest_first_seed + cur_cid);
1054 for(op = 0; !client.timeout(0) && op < nKeysPerPart; op++){
1055 for (int i = prefixLen; i < keylen; i++)
1056 key[i] = minkltr + client.rand.next() % (maxkltr - minkltr + 1);
1057 memcpy(val, key + keylen - 8, 8);
1059 if (client.rand.next() % 100 < client.getratio())
1060 client.get_check(key, val);
1062 client.put(key, val);
1064 cur_cid = (cur_cid + 1) % NLongParts;
1070 Json result = Json();
1071 kvtest_set_time(result, "ops", n, t1 - t0);
1072 client.report(result);
1075 template <typename C>
1077 kvtest_wscale(C &client)
1080 client.rand.reset(kvtest_first_seed + client.id() % 48);
1082 for(n = 0; !client.timeout(0); n++){
1083 long x = client.rand.next();
1084 client.put(x, x + 1);
1088 Json result = Json();
1089 kvtest_set_time(result, "puts", n, t1 -t0);
1090 client.report(result);
1093 template <typename C>
1095 kvtest_ruscale_init(C &client)
1098 client.rand.reset(kvtest_first_seed + client.id() % 48);
1099 const int ruscale_partsz = client.ruscale_partsz();
1100 const int firstkey = ruscale_partsz * client.ruscale_init_part_no();
1101 // Insert in random order
1102 int *keys = (int *) malloc(sizeof(int) * ruscale_partsz);
1103 always_assert(keys);
1104 for(int i = 0; i < ruscale_partsz; i++)
1105 keys[i] = i + firstkey;
1106 for(int i = 0; i < ruscale_partsz; i++)
1107 std::swap(keys[i], keys[client.rand.next() % ruscale_partsz]);
1108 for(int i = 0; i < ruscale_partsz; i++){
1110 client.put(x, x + 1);
1114 Json result = Json();
1115 kvtest_set_time(result, "puts", ruscale_partsz, t1 - t0);
1116 client.report(result);
1120 template <typename C>
1122 kvtest_rscale(C &client)
1124 client.rand.reset(kvtest_first_seed + client.id() % 48);
1125 const long nseqkeys = client.nseqkeys();
1128 for(n = 0; !client.timeout(0); n++){
1129 long x = client.rand.next() % nseqkeys;
1130 client.get_check(x, x + 1);
1134 Json result = Json();
1135 kvtest_set_time(result, "gets", n, t1 - t0);
1136 client.report(result);
1139 template <typename C>
1141 kvtest_uscale(C &client)
1143 client.rand.reset(kvtest_first_seed + client.id());
1144 const long nseqkeys = client.nseqkeys();
1147 for(n = 0; !client.timeout(0); n++){
1148 long x = client.rand.next() % nseqkeys;
1149 client.put(x, x + 1);
1153 Json result = Json();
1154 kvtest_set_time(result, "puts", n, t1 - t0);
1155 client.report(result);
1158 template <typename C>
1159 void kvtest_udp1_seed(C &client, int seed)
1161 client.rand.reset(seed);
1162 double tp0 = client.now();
1164 for (n = 0; !client.timeout(0); ++n)
1167 double tp1 = client.now();
1170 client.notice("now getting\n");
1171 int32_t *a = (int32_t *) malloc(sizeof(int32_t) * n);
1173 client.rand.reset(seed);
1174 for (unsigned i = 0; i < n; ++i)
1175 a[i] = (int32_t) client.rand.next();
1176 for (unsigned i = 0; i < n; ++i)
1177 std::swap(a[i], a[client.rand.next() % n]);
1179 double tg0 = client.now();
1181 for (g = 0; !client.timeout(1); ++g)
1182 client.get_check(0, 1);
1184 double tg1 = client.now();
1186 Json result = Json();
1187 kvtest_set_time(result, "puts", n, tp1 - tp0);
1188 kvtest_set_time(result, "gets", g, tg1 - tg0);
1189 kvtest_set_time(result, "ops", n + g, (tp1 - tp0) + (tg1 - tg0));
1190 client.report(result);
1194 template <typename C>
1195 void kvtest_udp1(C &client)
1197 kvtest_udp1_seed(client, kvtest_first_seed + client.id() % 48);
1200 // do four million of inserts to distinct keys.
1201 // sometimes overwrites, but only w/ same value.
1202 // different clients might use same key sometimes.
1203 template <typename C>
1204 void kvtest_w1_seed(C &client, int seed)
1207 if (client.limit() == ~(uint64_t) 0)
1210 n = std::min(client.limit(), (uint64_t) INT_MAX);
1211 client.rand.reset(seed);
1214 for (int i = 0; i < n; i++) {
1215 long x = client.rand.next();
1216 client.put_key10(x, x + 1);
1221 Json result = Json().set("total", (long) (n / (t1 - t0)))
1223 .set("puts_per_sec", n / (t1 - t0));
1224 client.report(result);
1227 // do four million gets.
1228 // in a random order.
1229 // if we get in the same order that w1 put, performance is
1230 // about 15% better for b-tree.
1231 template <typename C>
1232 void kvtest_r1_seed(C &client, int seed)
1235 if (client.limit() == ~(uint64_t) 0)
1238 n = std::min(client.limit(), (uint64_t) INT_MAX);
1239 long *a = (long *) malloc(sizeof(long) * n);
1242 client.rand.reset(seed);
1243 for (int i = 0; i < n; i++)
1244 a[i] = client.rand.next();
1245 for (int i = 0; i < n; i++) {
1246 int i1 = client.rand.next() % n;
1253 for (int i = 0; i < n; i++)
1254 client.get_check_key10(a[i], a[i] + 1);
1258 Json result = Json().set("total", (long) (n / (t1 - t0)))
1260 .set("gets_per_sec", n / (t1 - t0));
1261 client.report(result);
1264 // do four million of inserts to distinct keys.
1265 // sometimes overwrites, but only w/ same value.
1266 // different clients might use same key sometimes.
1267 template <typename C>
1268 void kvtest_wcol1at(C &client, int col, int seed, long maxkeys)
1271 if (client.limit() == ~(uint64_t) 0)
1274 n = std::min(client.limit(), (uint64_t) INT_MAX);
1275 client.rand.reset(seed);
1278 for (int i = 0; i < n; i++) {
1279 long x = client.rand.next() % maxkeys;
1280 client.put_col_key10(x, col, x + 1);
1285 Json result = Json().set("total", (long) (n / (t1 - t0)))
1287 .set("puts_per_sec", n / (t1 - t0));
1288 client.report(result);
1291 // do four million gets.
1292 // in a random order.
1293 // if we get in the same order that w1 put, performance is
1294 // about 15% better for b-tree.
1295 template <typename C>
1296 void kvtest_rcol1at(C &client, int col, int seed, long maxkeys)
1299 if (client.limit() == ~(uint64_t) 0)
1302 n = std::min(client.limit(), (uint64_t) INT_MAX);
1303 long *a = (long *) malloc(sizeof(long) * n);
1306 client.rand.reset(seed);
1307 for (int i = 0; i < n; i++)
1308 a[i] = client.rand.next() % maxkeys;
1309 for (int i = 0; i < n && 0; i++) {
1310 int i1 = client.rand.next() % n;
1317 for (int i = 0; i < n; i++)
1318 client.get_col_check_key10(a[i], col, a[i] + 1);
1322 Json result = Json().set("total", (long) (n / (t1 - t0)))
1324 .set("gets_per_sec", n / (t1 - t0));
1325 client.report(result);
1328 // test scans with parallel inserts
1329 template <typename C>
1330 void kvtest_scan1(C &client, double writer_quiet)
1332 int n, wq65536 = int(writer_quiet * 65536);
1333 if (client.limit() == ~(uint64_t) 0)
1336 n = std::min(client.limit(), (uint64_t) 97655);
1339 if (client.id() % 24 == 0) {
1340 for (int i = 0; i < n; ++i)
1341 client.put_key8(i * 1024, i);
1344 int pos = 0, mypos = 0, scansteps = 0;
1346 std::vector<Str> keys, values;
1348 while (!client.timeout(0) && errj.size() < 1000) {
1350 client.scan_sync(key.string(), 100, keys, values);
1351 if (keys.size() == 0) {
1352 if (mypos < n * 1024)
1353 errj.push_back("missing " + String(mypos) + " through " + String((n - 1) * 1024));
1356 for (size_t i = 0; i < keys.size(); ++i) {
1357 int val = keys[i].to_i();
1359 errj.push_back("unexpected key " + String(keys[i].s, keys[i].len));
1363 errj.push_back("got " + String(keys[i].s, keys[i].len) + ", expected " + String(pos) + " or later");
1365 while (val > mypos) {
1366 errj.push_back("got " + String(keys[i].s, keys[i].len) + ", missing " + String(mypos) + " @" + String(scansteps) + "+" + String(i));
1375 client.rcu_quiesce();
1377 if (errj.size() >= 1000)
1378 errj.push_back("too many errors, giving up");
1379 result.set("ok", errj.empty()).set("scansteps", scansteps);
1381 result.set("errors", errj);
1384 int delta = 1 + (client.id() % 30) * 32, rounds = 0;
1385 while (!client.timeout(0)) {
1386 int first = (client.rand.next() % n) * 1024 + delta;
1387 int rand = client.rand.next() % 65536;
1388 if (rand < wq65536) {
1389 for (int d = 0; d < 31; ++d)
1391 } else if (rounds > 100 && (rand % 2) == 1) {
1392 for (int d = 0; d < 31; ++d)
1393 client.remove_key8(d + first);
1395 for (int d = 0; d < 31; ++d)
1396 client.put_key8(d + first, d + first);
1399 client.rcu_quiesce();
1403 client.report(result);
1406 // test reverse scans with parallel inserts
1407 template <typename C>
1408 void kvtest_rscan1(C &client, double writer_quiet)
1410 int n, wq65536 = int(writer_quiet * 65536);
1411 if (client.limit() == ~(uint64_t) 0)
1414 n = std::min(client.limit(), (uint64_t) 97655);
1417 if (client.id() % 24 == 0) {
1418 for (int i = 1; i <= n; ++i)
1419 client.put_key8(i * 1024, i);
1422 int pos = (n + 1) * 1024, mypos = n * 1024, scansteps = 0;
1424 std::vector<Str> keys, values;
1426 while (!client.timeout(0) && errj.size() < 1000) {
1428 client.rscan_sync(key.string(), 100, keys, values);
1429 if (keys.size() == 0) {
1431 errj.push_back("missing 1024 through " + String(mypos) + " @" + String(scansteps));
1432 pos = (n + 1) * 1024, mypos = n * 1024;
1434 for (size_t i = 0; i < keys.size(); ++i) {
1435 int val = keys[i].to_i();
1437 errj.push_back("unexpected key " + String(keys[i].s, keys[i].len));
1441 errj.push_back("got " + String(keys[i].s, keys[i].len) + ", expected " + String(pos) + " or less");
1443 while (val < mypos) {
1446 last = String(keys[i-1].s, keys[i-1].len);
1448 last = String(key.string().s, key.string().len);
1449 errj.push_back("got " + String(keys[i].s, keys[i].len) + ", missing " + String(mypos) + " @" + String(scansteps) + "+" + String(i) + ", last " + last);
1458 client.rcu_quiesce();
1460 if (errj.size() >= 1000)
1461 errj.push_back("too many errors, giving up");
1462 result.set("ok", errj.empty()).set("scansteps", scansteps);
1464 result.set("errors", errj);
1467 int delta = 1 + (client.id() % 30) * 32, rounds = 0;
1468 while (!client.timeout(0)) {
1469 int first = (client.rand.next() % n + 1) * 1024 + delta;
1470 int rand = client.rand.next() % 65536;
1471 if (rand < wq65536) {
1472 for (int d = 0; d < 31; ++d)
1474 } else if (rounds > 100 && (rand % 2) == 1) {
1475 for (int d = 0; d < 31; ++d)
1476 client.remove_key8(d + first);
1478 for (int d = 0; d < 31; ++d)
1479 client.put_key8(d + first, d + first);
1482 client.rcu_quiesce();
1486 client.report(result);
1489 // test concurrent splits with removes in lower layers
1490 template <typename C>
1491 void kvtest_splitremove1(C &client)
1493 // XXX these parameters depend on masstree constants...
1494 int leaf_width = 15, internode_width = 15;
1495 int num_keys = leaf_width * (internode_width + 1) + 1;
1496 int trigger_key = num_keys - 15;
1500 if (client.id() == 0) {
1502 for (int i = 0; i < num_keys; ++i)
1503 client.put_key16(i + 100, i + 101);
1504 client.rcu_quiesce();
1505 for (int i = trigger_key + 1; i < num_keys + 10; ++i)
1506 client.remove_key16(i + 100);
1507 client.rcu_quiesce();
1508 for (int i = 0; i < leaf_width * internode_width; ++i)
1509 client.put_key16(i, i + 1);
1511 client.put(client.nthreads(), client.nthreads() + 1);
1512 for (int i = 1; i < client.nthreads(); ++i)
1513 client.put(i, i + 1);
1514 for (int i = 1; i < client.nthreads(); ++i) {
1515 while (!client.timeout(0) && client.get_sync(i))
1518 client.remove_key16(trigger_key);
1519 client.remove(client.nthreads());
1520 if (client.timeout(0))
1523 for (int i = 0; i < num_keys; ++i) {
1524 client.remove_key16(i);
1525 client.remove_key16(i + 100);
1527 for (int i = 0; i < 10; ++i)
1528 client.rcu_quiesce();
1533 quick_istr me(client.id()), trigger(trigger_key, 16);
1535 while (!client.timeout(0) && !client.get_sync_key16(trigger_key))
1536 client.rcu_quiesce();
1537 if (client.timeout(0))
1540 for (int i = 0; !client.get_sync(me.string()); ++i) {
1541 if (!client.get_sync(trigger.string()) && !client.timeout(0)) {
1542 if (errj.size() == 100)
1543 errj.push_back("more errors");
1544 else if (errj.size() < 100)
1545 errj.push_back("key " + String(trigger.string()) + " missing after " + String(rounds) + " rounds, counter " + String(i));
1548 client.rcu_quiesce();
1551 while (!client.timeout(0) && !client.get_sync(me.string()))
1552 client.rcu_quiesce();
1553 client.remove(me.string());
1554 while (!client.timeout(0) && client.get_sync(client.nthreads()))
1555 client.rcu_quiesce();
1556 if (client.timeout(0))
1559 for (int i = 0; i < 10; ++i)
1560 client.rcu_quiesce();
1565 result.set("ok", errj.empty()).set("rounds", rounds);
1567 result.set("errors", errj);
1568 client.report(result);
1571 template <typename C>
1572 void kvtest_url_seed(C &client)
1574 if (!client.param("file").is_s()) {
1575 client.report(Json::object("ok", false, "error", "need 'file=URLFILE' parameter"));
1579 std::ifstream infile_url_init(client.param("file").to_s());
1580 std::ifstream infile_url_del_get(client.param("file").to_s());
1583 unsigned count_i = 0;
1584 unsigned count_d = 0;
1585 unsigned count_g = 0;
1587 double t0 = client.now();
1588 while (count_i < client.limit() && infile_url_init.good()) {
1589 //do the following alternately:
1590 //insert 10 urls, then delete 5 inserted urls
1591 for (int i = 0; i != 10 && infile_url_init >> ops >> url; ++i, ++count_i)
1592 client.put(url, 2014);
1593 for (int i = 0; i != 5 && infile_url_del_get >> ops >> url; ++i, ++count_d)
1598 double t1 = client.now();
1599 infile_url_init.close();
1600 client.notice("\ninsert done\n");
1602 //query all the inserted urls
1603 double t2 = client.now();
1604 while (count_d + count_g != count_i && infile_url_del_get >> ops >> url) {
1605 client.get_check(Str(url), 2014);
1609 double t3 = client.now();
1611 // client.notice("Total pool memory: %d\n", client.ti_->poolmem);
1612 // client.notice("Total general memory: %d\n", client.ti_->genmem);
1613 // client.notice("Total MEMORY: %d\n", client.ti_->poolmem + client.ti_->genmem);
1615 Json result = Json::object("puts", count_i, "removes", count_d);
1616 kvtest_set_time(result, "gets", count_g, t3 - t2);
1617 kvtest_set_time(result, "ops", count_i + count_d, t1 - t0);
1618 client.report(result);
1621 template <typename C>
1622 void kvtest_url(C &client)
1624 kvtest_url_seed(client);