* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
-#include <glib.h>
#include "qemu/processor.h"
#include "qemu/atomic.h"
#include "qemu/qht.h"
#include "qemu/rcu.h"
-#include "exec/tb-hash-xx.h"
+#include "qemu/xxhash.h"
struct thread_stats {
size_t rd;
static double resize_rate; /* 0.0 to 1.0 */
static unsigned int n_rz_threads = 1;
static QemuThread *rz_threads;
+static bool precompute_hash;
static double update_rate; /* 0.0 to 1.0 */
static uint64_t update_threshold;
" -n = number of threads\n"
"\n"
" -o = offset at which keys start\n"
+ " -p = precompute hashes\n"
"\n"
" -g = set -s,-k,-K,-l,-r to the same value\n"
" -s = initial size hint\n"
exit(-1);
}
-static bool is_equal(const void *obj, const void *userp)
+static bool is_equal(const void *ap, const void *bp)
{
- const long *a = obj;
- const long *b = userp;
+ const long *a = ap;
+ const long *b = bp;
return *a == *b;
}
-static inline uint32_t h(unsigned long v)
+static uint32_t h(unsigned long v)
{
- return tb_hash_func5(v, 0, 0);
+ return qemu_xxhash2(v);
}
+static uint32_t hval(unsigned long v)
+{
+ return v;
+}
+
+static uint32_t (*hfunc)(unsigned long v) = h;
+
/*
* From: https://en.wikipedia.org/wiki/Xorshift
* This is faster than rand_r(), and gives us a wider range (RAND_MAX is only
bool read;
p = &keys[info->r & (lookup_range - 1)];
- hash = h(*p);
- read = qht_lookup(&ht, is_equal, p, hash);
+ hash = hfunc(*p);
+ read = qht_lookup(&ht, p, hash);
if (read) {
stats->rd++;
} else {
}
} else {
p = &keys[info->r & (update_range - 1)];
- hash = h(*p);
+ hash = hfunc(*p);
if (info->write_op) {
bool written = false;
- if (qht_lookup(&ht, is_equal, p, hash) == NULL) {
- written = qht_insert(&ht, p, hash);
+ if (qht_lookup(&ht, p, hash) == NULL) {
+ written = qht_insert(&ht, p, hash, NULL);
}
if (written) {
stats->in++;
} else {
bool removed = false;
- if (qht_lookup(&ht, is_equal, p, hash)) {
+ if (qht_lookup(&ht, p, hash)) {
removed = qht_remove(&ht, p, hash);
}
if (removed) {
rcu_register_thread();
atomic_inc(&n_ready_threads);
- while (!atomic_mb_read(&test_start)) {
+ while (!atomic_read(&test_start)) {
cpu_relax();
}
/* avoid allocating memory later by allocating all the keys now */
keys = g_malloc(sizeof(*keys) * n);
for (i = 0; i < n; i++) {
- keys[i] = populate_offset + i;
+ long val = populate_offset + i;
+
+ keys[i] = precompute_hash ? h(val) : hval(val);
}
/* some sanity checks */
}
/* initialize the hash table */
- qht_init(&ht, qht_n_elems, qht_mode);
+ qht_init(&ht, is_equal, qht_n_elems, qht_mode);
assert(init_size <= init_range);
pr_params();
r = xorshift64star(r);
p = &keys[r & (init_range - 1)];
- hash = h(*p);
- if (qht_insert(&ht, p, hash)) {
+ hash = hfunc(*p);
+ if (qht_insert(&ht, p, hash, NULL)) {
break;
}
retries++;
static void run_test(void)
{
- unsigned int remaining;
int i;
while (atomic_read(&n_ready_threads) != n_rw_threads + n_rz_threads) {
cpu_relax();
}
- atomic_mb_set(&test_start, true);
- do {
- remaining = sleep(duration);
- } while (remaining);
- atomic_mb_set(&test_stop, true);
+
+ atomic_set(&test_start, true);
+ g_usleep(duration * G_USEC_PER_SEC);
+ atomic_set(&test_stop, true);
for (i = 0; i < n_rw_threads; i++) {
qemu_thread_join(&rw_threads[i]);
int c;
for (;;) {
- c = getopt(argc, argv, "d:D:g:k:K:l:hn:N:o:r:Rs:S:u:");
+ c = getopt(argc, argv, "d:D:g:k:K:l:hn:N:o:pr:Rs:S:u:");
if (c < 0) {
break;
}
case 'o':
populate_offset = atol(optarg);
break;
+ case 'p':
+ precompute_hash = true;
+ hfunc = hval;
+ break;
case 'r':
update_range = pow2ceil(atol(optarg));
break;