Commit 51a56b52 authored by Rusty Russell's avatar Rusty Russell

Merge branch 'tdb2'

parents 451d97ad a42bba8e
......@@ -2,7 +2,7 @@ LDLIBS:=../../tdb.o ../../tally.o
CFLAGS:=-I../../.. -Wall -O3 #-g -pg
LDFLAGS:=-L../../..
default: replay_trace tdbtorture tdbdump tdbtool starvation mktdb
default: replay_trace tdbtorture tdbdump tdbtool starvation mktdb speed
benchmark: replay_trace
@trap "rm -f /tmp/trace.$$$$" 0; for f in benchmarks/*.rz; do if runzip -k $$f -o /tmp/trace.$$$$ && echo -n "$$f": && ./replay_trace --quiet -n 5 replay.tdb /tmp/trace.$$$$ && rm /tmp/trace.$$$$; then rm -f /tmp/trace.$$$$; else exit 1; fi; done
......@@ -30,4 +30,4 @@ check: replay_trace
@sed 's/\(^[0-9]* traverse\) .*/\1fn/' < $^ > $@
clean:
rm -f replay_trace tdbtorture tdbdump tdbtool *.o
rm -f replay_trace tdbtorture tdbdump tdbtool speed *.o
/* Simple speed test for TDB */
#include <err.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ccan/tdb/tdb.h>
/* Nanoseconds per operation */
static size_t normalize(const struct timeval *start,
const struct timeval *stop,
unsigned int num)
{
struct timeval diff;
timersub(stop, start, &diff);
/* Floating point is more accurate here. */
return (double)(diff.tv_sec * 1000000 + diff.tv_usec)
/ num * 1000;
}
static size_t file_size(void)
{
struct stat st;
if (stat("/tmp/speed.tdb", &st) != 0)
return -1;
return st.st_size;
}
static int count_record(struct tdb_context *tdb,
TDB_DATA key, TDB_DATA data, void *p)
{
int *total = p;
*total += *(int *)data.dptr;
return 0;
}
int main(int argc, char *argv[])
{
unsigned int i, j, num = 1000, stage = 0, stopat = -1;
int flags = TDB_DEFAULT;
TDB_DATA key, data;
struct tdb_context *tdb;
struct timeval start, stop;
bool transaction = false;
if (argv[1] && strcmp(argv[1], "--internal") == 0) {
flags = TDB_INTERNAL;
argc--;
argv++;
}
if (argv[1] && strcmp(argv[1], "--transaction") == 0) {
transaction = true;
argc--;
argv++;
}
tdb = tdb_open("/tmp/speed.tdb", 100003, flags, O_RDWR|O_CREAT|O_TRUNC,
0600);
if (!tdb)
err(1, "Opening /tmp/speed.tdb");
key.dptr = (void *)&i;
key.dsize = sizeof(i);
data = key;
if (argv[1]) {
num = atoi(argv[1]);
argv++;
argc--;
}
if (argv[1]) {
stopat = atoi(argv[1]);
argv++;
argc--;
}
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
/* Add 1000 records. */
printf("Adding %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (i = 0; i < num; i++)
if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
errx(1, "Inserting key %u in tdb: %s",
i, tdb_errorstr(tdb));
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
/* Finding 1000 records. */
printf("Finding %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (i = 0; i < num; i++) {
int *dptr;
dptr = (int *)tdb_fetch(tdb, key).dptr;
if (!dptr || *dptr != i)
errx(1, "Fetching key %u in tdb gave %u",
i, dptr ? *dptr : -1);
}
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
/* Missing 1000 records. */
printf("Missing %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (i = num; i < num*2; i++) {
int *dptr;
dptr = (int *)tdb_fetch(tdb, key).dptr;
if (dptr)
errx(1, "Fetching key %u in tdb gave %u", i, *dptr);
}
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
/* Traverse 1000 records. */
printf("Traversing %u records: ", num); fflush(stdout);
i = 0;
gettimeofday(&start, NULL);
if (tdb_traverse(tdb, count_record, &i) != num)
errx(1, "Traverse returned wrong number of records");
if (i != (num - 1) * (num / 2))
errx(1, "Traverse tallied to %u", i);
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
/* Delete 1000 records (not in order). */
printf("Deleting %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (j = 0; j < num; j++) {
i = (j + 100003) % num;
if (tdb_delete(tdb, key) != 0)
errx(1, "Deleting key %u in tdb: %s",
i, tdb_errorstr(tdb));
}
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
/* Re-add 1000 records (not in order). */
printf("Re-adding %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (j = 0; j < num; j++) {
i = (j + 100003) % num;
if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
errx(1, "Inserting key %u in tdb: %s",
i, tdb_errorstr(tdb));
}
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
/* Append 1000 records. */
printf("Appending %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (i = 0; i < num; i++)
if (tdb_append(tdb, key, data) != 0)
errx(1, "Appending key %u in tdb: %s",
i, tdb_errorstr(tdb));
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
if (++stage == stopat)
exit(0);
if (transaction && tdb_transaction_start(tdb))
errx(1, "starting transaction: %s", tdb_errorstr(tdb));
/* Churn 1000 records: not in order! */
printf("Churning %u records: ", num); fflush(stdout);
gettimeofday(&start, NULL);
for (j = 0; j < num; j++) {
i = (j + 1000019) % num;
if (tdb_delete(tdb, key) != 0)
errx(1, "Deleting key %u in tdb: %s",
i, tdb_errorstr(tdb));
i += num;
if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
errx(1, "Inserting key %u in tdb: %s",
i, tdb_errorstr(tdb));
}
gettimeofday(&stop, NULL);
if (transaction && tdb_transaction_commit(tdb))
errx(1, "committing transaction: %s", tdb_errorstr(tdb));
printf(" %zu ns (%zu bytes)\n",
normalize(&start, &stop, num), file_size());
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
No preview for this file type
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -37,33 +37,43 @@ static int count_hash(struct tdb_context *tdb,
static bool summarize(struct tdb_context *tdb,
struct tally *hashes,
struct tally *flists,
struct tally *ftables,
struct tally *free,
struct tally *keys,
struct tally *data,
struct tally *extra,
struct tally *uncoal,
struct tally *buckets)
struct tally *buckets,
struct tally *chains)
{
tdb_off_t off;
tdb_len_t len;
tdb_len_t unc = 0;
for (off = sizeof(struct tdb_header); off < tdb->map_size; off += len) {
union {
const union {
struct tdb_used_record u;
struct tdb_free_record f;
} pad, *p;
p = tdb_get(tdb, off, &pad, sizeof(pad));
struct tdb_recovery_record r;
} *p;
/* We might not be able to get the whole thing. */
p = tdb_access_read(tdb, off, sizeof(p->f), true);
if (!p)
return false;
if (rec_magic(&p->u) != TDB_MAGIC) {
len = p->f.data_len;
if (p->r.magic == TDB_RECOVERY_INVALID_MAGIC
|| p->r.magic == TDB_RECOVERY_MAGIC) {
if (unc) {
tally_add(uncoal, unc);
unc = 0;
}
len = sizeof(p->r) + p->r.max_len;
} else if (frec_magic(&p->f) == TDB_FREE_MAGIC) {
len = frec_len(&p->f);
tally_add(free, len);
tally_add(buckets, size_to_bucket(len));
len += sizeof(p->u);
unc++;
} else {
} else if (rec_magic(&p->u) == TDB_USED_MAGIC) {
if (unc) {
tally_add(uncoal, unc);
unc = 0;
......@@ -73,25 +83,35 @@ static bool summarize(struct tdb_context *tdb,
+ rec_data_length(&p->u)
+ rec_extra_padding(&p->u);
/* FIXME: Use different magic for hashes, flists. */
if (!rec_key_length(&p->u) && rec_hash(&p->u) < 2) {
if (rec_hash(&p->u) == 0) {
int count = count_hash(tdb,
off + sizeof(p->u),
TDB_SUBLEVEL_HASH_BITS);
if (count == -1)
return false;
tally_add(hashes, count);
} else {
tally_add(flists,
rec_data_length(&p->u));
}
} else {
tally_add(keys, rec_key_length(&p->u));
tally_add(data, rec_data_length(&p->u));
}
tally_add(keys, rec_key_length(&p->u));
tally_add(data, rec_data_length(&p->u));
tally_add(extra, rec_extra_padding(&p->u));
} else if (rec_magic(&p->u) == TDB_HTABLE_MAGIC) {
int count = count_hash(tdb,
off + sizeof(p->u),
TDB_SUBLEVEL_HASH_BITS);
if (count == -1)
return false;
tally_add(hashes, count);
tally_add(extra, rec_extra_padding(&p->u));
len = sizeof(p->u)
+ rec_data_length(&p->u)
+ rec_extra_padding(&p->u);
} else if (rec_magic(&p->u) == TDB_FTABLE_MAGIC) {
len = sizeof(p->u)
+ rec_data_length(&p->u)
+ rec_extra_padding(&p->u);
tally_add(ftables, rec_data_length(&p->u));
tally_add(extra, rec_extra_padding(&p->u));
} else if (rec_magic(&p->u) == TDB_CHAIN_MAGIC) {
len = sizeof(p->u)
+ rec_data_length(&p->u)
+ rec_extra_padding(&p->u);
tally_add(chains, 1);
tally_add(extra, rec_extra_padding(&p->u));
}
} else
len = dead_space(tdb, off);
tdb_access_release(tdb, p);
}
if (unc)
tally_add(uncoal, unc);
......@@ -110,6 +130,7 @@ static bool summarize(struct tdb_context *tdb,
"Smallest/average/largest uncoalesced runs: %zu/%zu/%zu\n%s" \
"Number of free lists: %zu\n%s" \
"Toplevel hash used: %u of %u\n" \
"Number of chains: %zu\n" \
"Number of subhashes: %zu\n" \
"Smallest/average/largest subhash entries: %zu/%zu/%zu\n%s" \
"Percentage keys/data/padding/free/rechdrs/freehdrs/hashes: %.0f/%.0f/%.0f/%.0f/%.0f/%.0f/%.0f\n"
......@@ -127,8 +148,8 @@ static bool summarize(struct tdb_context *tdb,
char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags)
{
tdb_len_t len;
struct tally *flists, *hashes, *freet, *keys, *data, *extra, *uncoal,
*buckets;
struct tally *ftables, *hashes, *freet, *keys, *data, *extra, *uncoal,
*buckets, *chains;
char *hashesg, *freeg, *keysg, *datag, *extrag, *uncoalg, *bucketsg;
char *ret = NULL;
......@@ -143,7 +164,7 @@ char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags)
}
/* Start stats off empty. */
flists = tally_new(HISTO_HEIGHT);
ftables = tally_new(HISTO_HEIGHT);
hashes = tally_new(HISTO_HEIGHT);
freet = tally_new(HISTO_HEIGHT);
keys = tally_new(HISTO_HEIGHT);
......@@ -151,14 +172,16 @@ char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags)
extra = tally_new(HISTO_HEIGHT);
uncoal = tally_new(HISTO_HEIGHT);
buckets = tally_new(HISTO_HEIGHT);
if (!flists || !hashes || !freet || !keys || !data || !extra
|| !uncoal || !buckets) {
tdb->ecode = TDB_ERR_OOM;
chains = tally_new(HISTO_HEIGHT);
if (!ftables || !hashes || !freet || !keys || !data || !extra
|| !uncoal || !buckets || !chains) {
tdb_logerr(tdb, TDB_ERR_OOM, TDB_DEBUG_ERROR,
"tdb_summary: failed to allocate tally structures");
goto unlock;
}
if (!summarize(tdb, hashes, flists, freet, keys, data, extra, uncoal,
buckets))
if (!summarize(tdb, hashes, ftables, freet, keys, data, extra, uncoal,
buckets, chains))
goto unlock;
if (flags & TDB_SUMMARY_HISTOGRAMS) {
......@@ -206,6 +229,7 @@ char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags)
count_hash(tdb, offsetof(struct tdb_header, hashtable),
TDB_TOPLEVEL_HASH_BITS),
1 << TDB_TOPLEVEL_HASH_BITS,
tally_num(chains),
tally_num(hashes),
tally_min(hashes), tally_mean(hashes), tally_max(hashes),
hashesg ? hashesg : "",
......@@ -215,11 +239,12 @@ char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags)
tally_total(freet, NULL) * 100.0 / tdb->map_size,
(tally_num(keys) + tally_num(freet) + tally_num(hashes))
* sizeof(struct tdb_used_record) * 100.0 / tdb->map_size,
tally_num(flists) * sizeof(struct tdb_freelist)
tally_num(ftables) * sizeof(struct tdb_freetable)
* 100.0 / tdb->map_size,
(tally_num(hashes)
* (sizeof(tdb_off_t) << TDB_SUBLEVEL_HASH_BITS)
+ (sizeof(tdb_off_t) << TDB_TOPLEVEL_HASH_BITS))
+ (sizeof(tdb_off_t) << TDB_TOPLEVEL_HASH_BITS)
+ sizeof(struct tdb_chain) * tally_num(chains))
* 100.0 / tdb->map_size);
unlock:
......@@ -237,6 +262,8 @@ unlock:
free(data);
free(extra);
free(uncoal);
free(ftables);
free(chains);
tdb_allrecord_unlock(tdb, F_RDLCK);
tdb_unlock_expand(tdb, F_RDLCK);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -11,7 +11,7 @@ extern union tdb_attribute tap_log_attr;
void tap_log_fn(struct tdb_context *tdb,
enum tdb_debug_level level, void *priv,
const char *fmt, ...);
const char *message);
static inline bool data_equal(struct tdb_data a, struct tdb_data b)
{
......
This diff is collapsed.
This diff is collapsed.
......@@ -65,7 +65,8 @@ int main(int argc, char *argv[])
/* FIXME: Check lock length */
/* Allocate a new record. */
new_off = alloc(tdb, key.dsize, dbuf.dsize, h.h, false);
new_off = alloc(tdb, key.dsize, dbuf.dsize, h.h,
TDB_USED_MAGIC, false);
ok1(new_off != TDB_OFF_ERR);
/* We should be able to add it now. */
......@@ -225,7 +226,8 @@ int main(int argc, char *argv[])
/* We should be able to add it now. */
/* Allocate a new record. */
new_off = alloc(tdb, key.dsize, dbuf.dsize, h.h, false);
new_off = alloc(tdb, key.dsize, dbuf.dsize, h.h,
TDB_USED_MAGIC, false);
ok1(new_off != TDB_OFF_ERR);
ok1(add_to_hash(tdb, &h, new_off) == 0);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment