Created
April 4, 2016 11:49
-
-
Save cruppstahl/dd98144e52ceac2e1df06df1fe7b852b to your computer and use it in GitHub Desktop.
Benchmark for https://upscaledb.com
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <vector> | |
#include <string> | |
#include <algorithm> | |
#include <unistd.h> | |
#include <db.h> | |
#include <leveldb/slice.h> | |
#include <leveldb/cache.h> | |
#include <leveldb/db.h> | |
#include <ups/upscaledb.h> | |
#include <ups/upscaledb_uqi.h> | |
#include "timer.h" | |
// stub for including upscaledb w/o compression | |
#ifndef UPS_PARAM_KEY_COMPRESSION | |
# define UPS_PARAM_KEY_COMPRESSION 0 | |
#endif | |
enum { | |
// default cache size is 4 mb for all databases | |
kCachesize = 4 * 1024 * 1024, | |
// Number of keys for the uint32 test | |
kNumberOfKeys = 50 * 1000 * 1000, | |
// Number of keys for the bin16 test | |
kThreeMillion = 3 * 1000 * 1000, | |
// Number of runs per test | |
kRunsPerTest = 1, | |
// Record size for the bin16 test | |
kRecordSize = 16, | |
}; | |
static int | |
compare_uint32(DB *db, const DBT *dbt1, const DBT *dbt2) | |
{ | |
uint32_t l = *(uint32_t *)dbt1->data; | |
uint32_t r = *(uint32_t *)dbt2->data; | |
if (l < r) return (-1); | |
if (r < l) return (+1); | |
return 0; | |
} | |
typedef std::vector<uint32_t> ivec; | |
static uint64_t | |
ups_write_int32(const ivec &kvec, const ivec &rvec) | |
{ | |
ups_env_t *env; | |
ups_db_t *db; | |
ups_parameter_t env_params[] = { | |
{UPS_PARAM_CACHE_SIZE, kCachesize}, | |
{0, 0} | |
}; | |
ups_parameter_t db_params[] = { | |
{UPS_PARAM_KEY_TYPE, UPS_TYPE_UINT32}, | |
{UPS_PARAM_RECORD_TYPE, UPS_TYPE_UINT32}, | |
{0, 0} | |
}; | |
const char *filename = "benchmark_int32.hdb"; | |
ups_status_t st = ups_env_create(&env, filename, 0, 0, env_params); | |
if (st) { | |
printf("ups_env_create failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
st = ups_env_create_db(env, &db, 1, 0, db_params); | |
if (st) { | |
printf("ups_env_create_db failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
WallClockTimer timer; | |
ivec::const_iterator kit = kvec.begin(); | |
ivec::const_iterator rit = rvec.begin(); | |
for (; kit != kvec.end(); kit++, rit++) { | |
uint32_t kv = *kit; | |
ups_key_t key = ups_make_key(&kv, sizeof(kv)); | |
uint32_t rv = *rit; | |
ups_record_t rec = ups_make_record(&rv, sizeof(rv)); | |
st = ups_db_insert(db, 0, &key, &rec, 0); | |
if (st) { | |
printf("ups_db_insert failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
} | |
uint64_t elapsed = timer.elapsed(); | |
st = ups_env_close(env, UPS_AUTO_CLEANUP); | |
if (st) { | |
printf("ups_env_close failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
return elapsed; | |
} | |
static uint64_t | |
ups_read_int32(const ivec &kvec, const ivec &rvec) | |
{ | |
ups_env_t *env; | |
ups_db_t *db; | |
ups_parameter_t env_params[] = { | |
{UPS_PARAM_CACHE_SIZE, kCachesize}, | |
{0, 0} | |
}; | |
const char *filename = "benchmark_int32.hdb"; | |
ups_status_t st = ups_env_open(&env, filename, 0, env_params); | |
if (st) { | |
printf("ups_env_open failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
st = ups_env_open_db(env, &db, 1, 0, 0); | |
if (st) { | |
printf("ups_env_open_db failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
WallClockTimer timer; | |
ivec::const_iterator kit = kvec.begin(); | |
ivec::const_iterator rit = rvec.begin(); | |
for (; kit != kvec.end(); kit++, rit++) { | |
uint32_t kv = *kit; | |
ups_key_t key = ups_make_key(&kv, sizeof(kv)); | |
uint32_t rv = *rit; | |
ups_record_t rec = {0}; | |
st = ups_db_find(db, 0, &key, &rec, 0); | |
if (st) { | |
printf("ups_db_find failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
if (rv != *(uint32_t *)rec.data) { | |
printf("ups_db_find returned bad value\n"); | |
exit(-1); | |
} | |
} | |
uint64_t elapsed = timer.elapsed(); | |
st = ups_env_close(env, UPS_AUTO_CLEANUP); | |
if (st) { | |
printf("ups_env_close failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
return elapsed; | |
} | |
static uint64_t | |
ups_max_int32() | |
{ | |
ups_env_t *env; | |
ups_db_t *db; | |
ups_parameter_t env_params[] = { | |
{UPS_PARAM_CACHE_SIZE, kCachesize}, | |
{0, 0} | |
}; | |
const char *filename = "benchmark_int32.hdb"; | |
ups_status_t st = ups_env_open(&env, filename, 0, env_params); | |
if (st) { | |
printf("ups_env_open failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
st = ups_env_open_db(env, &db, 1, 0, 0); | |
if (st) { | |
printf("ups_env_open_db failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
WallClockTimer timer; | |
uqi_result_t *result = 0; | |
st = uqi_select(env, "MAX($record) FROM DATABASE 1", &result); | |
if (st) { | |
printf("uqi_select failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
ups_record_t record = {0}; | |
uqi_result_get_record(result, 0, &record); | |
if (*(uint32_t *)record.data != kNumberOfKeys - 1) { | |
printf("uqi_select unexpected result %u\n", *(uint32_t *)record.data); | |
//exit(-1); | |
} | |
uqi_result_close(result); | |
uint64_t elapsed = timer.elapsed(); | |
st = ups_env_close(env, UPS_AUTO_CLEANUP); | |
if (st) { | |
printf("ups_env_close failed: %s\n", ups_strerror(st)); | |
exit(-1); | |
} | |
return elapsed; | |
} | |
static uint64_t | |
bdb_write_int32(const ivec &kvec, const ivec &rvec) | |
{ | |
DB *db; | |
int st = db_create(&db, 0, 0); | |
if (st) { | |
printf("db_create failed: %d\n", st); | |
exit(-1); | |
} | |
st = db->set_cachesize(db, 0, kCachesize, 1); | |
if (st) { | |
printf("db->set_cachesize failed: %d\n", st); | |
exit(-1); | |
} | |
st = db->set_bt_compare(db, compare_uint32); | |
if (st) { | |
printf("db->set_bt_compare failed: %d\n", st); | |
exit(-1); | |
} | |
unlink("benchmark_int32.bdb"); | |
st = db->open(db, 0, "benchmark_int32.bdb", 0, DB_BTREE, DB_CREATE, 0644); | |
if (st) { | |
printf("db->open failed: %d\n", st); | |
exit(-1); | |
} | |
WallClockTimer timer; | |
ivec::const_iterator kit = kvec.begin(); | |
ivec::const_iterator rit = rvec.begin(); | |
for (; kit != kvec.end(); kit++, rit++) { | |
uint32_t kv = *kit; | |
DBT key, rec; | |
memset(&key, 0, sizeof(key)); | |
memset(&rec, 0, sizeof(rec)); | |
key.data = &kv; | |
key.size = sizeof(kv); | |
uint32_t rv = *rit; | |
rec.data = &rv; | |
rec.size = sizeof(rv); | |
st = db->put(db, 0, &key, &rec, 0); | |
if (st) { | |
printf("db->put failed: %d\n", st); | |
exit(-1); | |
} | |
} | |
uint64_t elapsed = timer.elapsed(); | |
st = db->close(db, 0); | |
if (st) { | |
printf("db->close failed: %d\n", st); | |
exit(-1); | |
} | |
return elapsed; | |
} | |
static uint64_t | |
bdb_read_int32(const ivec &kvec, const ivec &rvec) | |
{ | |
DB *db; | |
int st = db_create(&db, 0, 0); | |
if (st) { | |
printf("db_create failed: %d\n", st); | |
exit(-1); | |
} | |
st = db->set_cachesize(db, 0, kCachesize, 1); | |
if (st) { | |
printf("db->set_cachesize failed: %d\n", st); | |
exit(-1); | |
} | |
st = db->set_bt_compare(db, compare_uint32); | |
if (st) { | |
printf("db->set_bt_compare failed: %d\n", st); | |
exit(-1); | |
} | |
st = db->open(db, 0, "benchmark_int32.bdb", 0, DB_BTREE, 0, 0); | |
if (st) { | |
printf("db->open failed: %d\n", st); | |
exit(-1); | |
} | |
WallClockTimer timer; | |
ivec::const_iterator kit = kvec.begin(); | |
ivec::const_iterator rit = rvec.begin(); | |
for (; kit != kvec.end(); kit++, rit++) { | |
uint32_t kv = *kit; | |
DBT key, rec; | |
memset(&key, 0, sizeof(key)); | |
memset(&rec, 0, sizeof(rec)); | |
key.data = &kv; | |
key.size = sizeof(kv); | |
uint32_t rv = *rit; | |
st = db->get(db, 0, &key, &rec, 0); | |
if (st) { | |
printf("db->get failed: %d\n", st); | |
exit(-1); | |
} | |
if (rv != *(uint32_t *)rec.data) { | |
printf("db->get returned bad value\n"); | |
exit(-1); | |
} | |
} | |
uint64_t elapsed = timer.elapsed(); | |
st = db->close(db, 0); | |
if (st) { | |
printf("db->close failed: %d\n", st); | |
exit(-1); | |
} | |
return elapsed; | |
} | |
static uint64_t | |
bdb_max_int32() | |
{ | |
DB *db; | |
DBC *dbc; | |
int st = db_create(&db, 0, 0); | |
if (st) { | |
printf("db_create failed: %d\n", st); | |
exit(-1); | |
} | |
st = db->set_cachesize(db, 0, kCachesize, 1); | |
if (st) { | |
printf("db->set_cachesize failed: %d\n", st); | |
exit(-1); | |
} | |
st = db->set_bt_compare(db, compare_uint32); | |
if (st) { | |
printf("db->set_bt_compare failed: %d\n", st); | |
exit(-1); | |
} | |
st = db->open(db, 0, "benchmark_int32.bdb", 0, DB_BTREE, 0, 0); | |
if (st) { | |
printf("db->open failed: %d\n", st); | |
exit(-1); | |
} | |
st = db->cursor(db, 0, &dbc, 0); | |
if (st) { | |
printf("db->cursor failed: %d\n", st); | |
exit(-1); | |
} | |
WallClockTimer timer; | |
uint64_t max = 0; | |
while (true) { | |
DBT key, rec; | |
memset(&key, 0, sizeof(key)); | |
memset(&rec, 0, sizeof(rec)); | |
st = dbc->c_get(dbc, &key, &rec, DB_NEXT); | |
if (st) | |
break; | |
uint32_t v = *(uint32_t *)rec.data; | |
if (v > max) | |
max = v; | |
} | |
if (max != kNumberOfKeys - 1) { | |
printf("bdb_max unexpected result %lu\n", max); | |
//exit(-1); | |
} | |
uint64_t elapsed = timer.elapsed(); | |
st = db->close(db, 0); | |
if (st) { | |
printf("db->close failed: %d\n", st); | |
exit(-1); | |
} | |
return elapsed; | |
} | |
static uint64_t | |
lev_write_int32(const ivec &kvec, const ivec &rvec) | |
{ | |
leveldb::DB *db; | |
leveldb::Options options; | |
options.create_if_missing = true; | |
options.block_cache = leveldb::NewLRUCache(kCachesize); | |
options.compression = leveldb::kNoCompression; | |
system("rm -rf benchmark_int32.ldb"); | |
leveldb::Status st = leveldb::DB::Open(options, "benchmark_int32.ldb", &db); | |
if (!st.ok()) { | |
printf("leveldb::DB::Open failed: %s\n", st.ToString().c_str()); | |
exit(-1); | |
} | |
WallClockTimer timer; | |
leveldb::WriteOptions writeOptions; | |
ivec::const_iterator kit = kvec.begin(); | |
ivec::const_iterator rit = rvec.begin(); | |
for (; kit != kvec.end(); kit++, rit++) { | |
uint32_t kv = *kit; | |
uint32_t rv = *rit; | |
st = db->Put(writeOptions, | |
leveldb::Slice((const char *)&kv, sizeof(kv)), | |
leveldb::Slice((const char *)&rv, sizeof(rv))); | |
if (!st.ok()) { | |
printf("db->Put failed: %s\n", st.ToString().c_str()); | |
exit(-1); | |
} | |
} | |
uint64_t elapsed = timer.elapsed(); | |
// Compact the file to get an exact file size | |
db->CompactRange(NULL, NULL); | |
delete db; | |
delete options.block_cache; | |
return elapsed; | |
} | |
static uint64_t | |
lev_read_int32(const ivec &kvec, const ivec &rvec) | |
{ | |
leveldb::DB *db; | |
leveldb::Options options; | |
options.create_if_missing = false; | |
options.block_cache = leveldb::NewLRUCache(kCachesize); | |
options.compression = leveldb::kNoCompression; | |
leveldb::Status st = leveldb::DB::Open(options, "benchmark_int32.ldb", &db); | |
if (!st.ok()) { | |
printf("leveldb::DB::Open failed: %s\n", st.ToString().c_str()); | |
exit(-1); | |
} | |
WallClockTimer timer; | |
leveldb::ReadOptions readOptions; | |
ivec::const_iterator kit = kvec.begin(); | |
ivec::const_iterator rit = rvec.begin(); | |
for (; kit != kvec.end(); kit++, rit++) { | |
uint32_t kv = *kit; | |
uint32_t rv = *rit; | |
std::string value; | |
st = db->Get(readOptions, | |
leveldb::Slice((const char *)&kv, sizeof(kv)), | |
&value); | |
if (!st.ok()) { | |
printf("db->Get failed: %s\n", st.ToString().c_str()); | |
exit(-1); | |
} | |
if (*(uint32_t *)value.data() != rv) { | |
printf("db->Get returned bad value\n"); | |
exit(-1); | |
} | |
} | |
uint64_t elapsed = timer.elapsed(); | |
delete db; | |
delete options.block_cache; | |
return elapsed; | |
} | |
static uint64_t | |
lev_max_int32() | |
{ | |
leveldb::DB *db; | |
leveldb::Options options; | |
options.create_if_missing = false; | |
options.block_cache = leveldb::NewLRUCache(kCachesize); | |
options.compression = leveldb::kNoCompression; | |
leveldb::Status st = leveldb::DB::Open(options, "benchmark_int32.ldb", &db); | |
if (!st.ok()) { | |
printf("leveldb::DB::Open failed: %s\n", st.ToString().c_str()); | |
exit(-1); | |
} | |
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions()); | |
WallClockTimer timer; | |
uint64_t max = 0; | |
for (it->SeekToFirst(); it->Valid(); it->Next()) { | |
uint32_t v = *(uint32_t *)it->value().data(); | |
if (v > max) | |
max = v; | |
} | |
if (max != kNumberOfKeys - 1) { | |
printf("ldb_max unexpected result: %lu\n", max); | |
//exit(-1); | |
} | |
uint64_t elapsed = timer.elapsed(); | |
delete it; | |
delete db; | |
delete options.block_cache; | |
return elapsed; | |
} | |
int | |
main() | |
{ | |
uint64_t elapsed; | |
std::vector<uint32_t> uint32; | |
for (uint32_t i = 0; i < kNumberOfKeys; i++) | |
uint32.push_back(i); | |
std::vector<uint32_t> randuint32 = uint32; | |
std::random_shuffle(randuint32.begin(), randuint32.end()); | |
printf("upscaledb write (%u keys)\n", kNumberOfKeys); | |
for (int r = 0; r < kRunsPerTest; r++) { | |
elapsed = ups_write_int32(uint32, randuint32); | |
printf(" %d: %lu microsec\n", r + 1, elapsed); | |
} | |
printf("upscaledb read\n"); | |
for (int r = 0; r < kRunsPerTest; r++) { | |
elapsed = ups_read_int32(uint32, randuint32); | |
printf(" %d: %lu microsec\n", r + 1, elapsed); | |
} | |
printf("upscaledb max\n"); | |
for (int r = 0; r < kRunsPerTest; r++) { | |
elapsed = ups_max_int32(); | |
printf(" %d: %lu microsec\n", r + 1, elapsed); | |
} | |
printf("berkeleydb write (%u keys)\n", kNumberOfKeys); | |
for (int r = 0; r < kRunsPerTest; r++) { | |
elapsed = bdb_write_int32(uint32, randuint32); | |
printf(" %d: %lu microsec\n", r + 1, elapsed); | |
} | |
printf("berkeleydb read\n"); | |
for (int r = 0; r < kRunsPerTest; r++) { | |
elapsed = bdb_read_int32(uint32, randuint32); | |
printf(" %d: %lu microsec\n", r + 1, elapsed); | |
} | |
printf("berkeleydb max\n"); | |
for (int r = 0; r < kRunsPerTest; r++) { | |
elapsed = bdb_max_int32(); | |
printf(" %d: %lu microsec\n", r + 1, elapsed); | |
} | |
printf("leveldb write (%u keys)\n", kNumberOfKeys); | |
for (int r = 0; r < kRunsPerTest; r++) { | |
elapsed = lev_write_int32(uint32, randuint32); | |
printf(" %d: %lu microsec\n", r + 1, elapsed); | |
} | |
printf("leveldb read\n"); | |
for (int r = 0; r < kRunsPerTest; r++) { | |
elapsed = lev_read_int32(uint32, randuint32); | |
printf(" %d: %lu microsec\n", r + 1, elapsed); | |
} | |
printf("leveldb max\n"); | |
for (int r = 0; r < kRunsPerTest; r++) { | |
elapsed = lev_max_int32(); | |
printf(" %d: %lu microsec\n", r + 1, elapsed); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
UPSCALEDB=/home/ruppc/prj/upscaledb | |
INCDIR=-I$(UPSCALEDB)/include | |
LIBDIR=-L$(UPSCALEDB)/src/.libs | |
LIBS=-lleveldb -ldb -lboost_system -lboost_thread -lcrypto -lpthread -lsnappy -lz -ltcmalloc_minimal -lprotobuf -ldl | |
CC=g++ -std=c++11 -g -O0 | |
all: | |
$(CC) benchmark.cc -o benchmark \ | |
$(UPSCALEDB)/src/.libs/libupscaledb.a \ | |
$(INCDIR) $(LIBDIR) $(LIBS) | |
clean: | |
rm -rf *.o benchmark *.hdb *.bdb | |
rm -rf *.ldb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef TIMER_H | |
#define TIMER_H | |
#include <stdint.h> | |
#include <chrono> | |
struct WallClockTimer { | |
typedef std::chrono::high_resolution_clock clock; | |
std::chrono::time_point<clock> t1; | |
WallClockTimer() { | |
reset(); | |
} | |
void reset() { | |
t1 = clock::now(); | |
} | |
uint64_t elapsed() { | |
std::chrono::microseconds delta = std::chrono::duration_cast< | |
std::chrono::microseconds>(clock::now() - t1); | |
return delta.count(); | |
} | |
}; | |
#endif /* TIMER_H */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment