A few qp-trie cleanups

Revert refcount debug tracing (commit a8b29f0365), there are better
ways to do it.

Use the dns_qpmethods_t typedef where appropriate.

Some stylistic improvements.
This commit is contained in:
Tony Finch 2023-03-10 15:55:00 +00:00
parent 39f38754e2
commit b3e35fd120
9 changed files with 158 additions and 203 deletions

View file

@ -57,19 +57,18 @@ static struct {
dns_qpkey_t ascii;
} item[256 * 256 / 4];
static uint32_t
static void
fuzz_attach(void *ctx, void *pval, uint32_t ival) {
assert(ctx == NULL);
assert(pval == &item[ival]);
return (item[ival].refcount++);
item[ival].refcount++;
}
static uint32_t
static void
fuzz_detach(void *ctx, void *pval, uint32_t ival) {
assert(ctx == NULL);
assert(pval == &item[ival]);
assert(item[ival].refcount > 0);
return (item[ival].refcount--);
item[ival].refcount--;
}
static size_t
@ -86,7 +85,7 @@ fuzz_triename(void *ctx, char *buf, size_t size) {
strlcpy(buf, "fuzz", size);
}
const struct dns_qpmethods fuzz_methods = {
const dns_qpmethods_t fuzz_methods = {
fuzz_attach,
fuzz_detach,
fuzz_makekey,

View file

@ -109,7 +109,9 @@ typedef struct dns_qpmulti dns_qpmulti_t;
* Read-only parts of a qp-trie.
*
* A `dns_qpreader_t` is the common prefix of the `dns_qpreadable`
* types, containing just the fields neded for the hot path.
* types, containing just the fields neded for the hot path. The
* internals of a `dns_qpreader_t` are private; they are only exposed
* so that callers can allocate a `dns_qpread_t` on the stack.
*
* Ranty aside: annoyingly, C doesn't allow us to use a predeclared
* structure type as an anonymous struct member, so we have to use a
@ -135,6 +137,9 @@ typedef struct dns_qpreader {
* The caller provides space for it on the stack; it can be
* used by only one thread. As well as the `DNS_QPREADER_FIELDS`,
* it contains a thread ID to check for incorrect usage.
*
* The internals of a `dns_qpread_t` are private; they are only
* exposed so that callers can allocate an instance on the stack.
*/
typedef struct dns_qpread {
DNS_QPREADER_FIELDS;
@ -209,9 +214,7 @@ typedef struct dns_qpiter {
* The `attach` and `detach` methods adjust reference counts on value
* objects. They support copy-on-write and safe memory reclamation
* needed for multi-version concurrency. The methods are only called
* when the `dns_qpmulti_t` mutex is held. For tracing purposes, they
* should return the same value as `isc_refcount_increment()` or
* `isc_refcount_decrement()`, respectively
* when the `dns_qpmulti_t` mutex is held.
*
* Note: When a value object reference count is greater than one, the
* object is in use by concurrent readers so it must not be modified. A
@ -230,8 +233,8 @@ typedef struct dns_qpiter {
* readable identifier into `buf` which has max length `size`.
*/
typedef struct dns_qpmethods {
uint32_t (*attach)(void *uctx, void *pval, uint32_t ival);
uint32_t (*detach)(void *uctx, void *pval, uint32_t ival);
void (*attach)(void *uctx, void *pval, uint32_t ival);
void (*detach)(void *uctx, void *pval, uint32_t ival);
size_t (*makekey)(dns_qpkey_t key, void *uctx, void *pval,
uint32_t ival);
void (*triename)(void *uctx, char *buf, size_t size);

View file

@ -482,6 +482,7 @@ static inline qp_ref_t
alloc_twigs(dns_qp_t *qp, qp_weight_t size) {
qp_chunk_t chunk = qp->bump;
qp_cell_t cell = qp->usage[chunk].used;
if (cell + size <= QP_CHUNK_SIZE) {
qp->usage[chunk].used += size;
qp->used_count += size;
@ -843,6 +844,7 @@ compact_recursive(dns_qp_t *qp, qp_node_t *parent) {
qp_weight_t size = branch_twigs_size(parent);
qp_ref_t twigs_ref = branch_twigs_ref(parent);
qp_chunk_t chunk = ref_chunk(twigs_ref);
if (qp->compact_all ||
(chunk != qp->bump && chunk_usage(qp, chunk) < QP_MIN_USED))
{
@ -1027,15 +1029,12 @@ dns_qp_gctime(isc_nanosecs_t *compact_p, isc_nanosecs_t *recycle_p,
static dns_qp_t *
transaction_open(dns_qpmulti_t *multi, dns_qp_t **qptp) {
dns_qp_t *qp;
REQUIRE(QPMULTI_VALID(multi));
REQUIRE(qptp != NULL && *qptp == NULL);
LOCK(&multi->mutex);
qp = &multi->writer;
dns_qp_t *qp = &multi->writer;
INSIST(QP_VALID(qp));
/*
@ -1396,11 +1395,9 @@ dns_qpsnap_destroy(dns_qpmulti_t *multi, dns_qpsnap_t **qpsp) {
void
dns_qp_create(isc_mem_t *mctx, const dns_qpmethods_t *methods, void *uctx,
dns_qp_t **qptp) {
dns_qp_t *qp;
REQUIRE(qptp != NULL && *qptp == NULL);
qp = isc_mem_get(mctx, sizeof(*qp));
dns_qp_t *qp = isc_mem_get(mctx, sizeof(*qp));
QP_INIT(qp, methods, uctx);
isc_mem_attach(mctx, &qp->mctx);
alloc_reset(qp);
@ -1412,12 +1409,9 @@ void
dns_qpmulti_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
const dns_qpmethods_t *methods, void *uctx,
dns_qpmulti_t **qpmp) {
dns_qpmulti_t *multi;
dns_qp_t *qp;
REQUIRE(qpmp != NULL && *qpmp == NULL);
multi = isc_mem_get(mctx, sizeof(*multi));
dns_qpmulti_t *multi = isc_mem_get(mctx, sizeof(*multi));
*multi = (dns_qpmulti_t){
.magic = QPMULTI_MAGIC,
.reader_ref = INVALID_REF,
@ -1432,7 +1426,7 @@ dns_qpmulti_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
* allocates; to ensure dns_qpmulti_write() does too, pretend the
* previous transaction was an update
*/
qp = &multi->writer;
dns_qp_t *qp = &multi->writer;
QP_INIT(qp, methods, uctx);
isc_mem_attach(mctx, &qp->mctx);
qp->transaction_mode = QP_UPDATE;
@ -1460,12 +1454,10 @@ destroy_guts(dns_qp_t *qp) {
void
dns_qp_destroy(dns_qp_t **qptp) {
dns_qp_t *qp;
REQUIRE(qptp != NULL);
REQUIRE(QP_VALID(*qptp));
qp = *qptp;
dns_qp_t *qp = *qptp;
*qptp = NULL;
/* do not try to destroy part of a dns_qpmulti_t */
@ -1478,14 +1470,11 @@ dns_qp_destroy(dns_qp_t **qptp) {
void
dns_qpmulti_destroy(dns_qpmulti_t **qpmp) {
dns_qp_t *qp = NULL;
dns_qpmulti_t *multi = NULL;
REQUIRE(qpmp != NULL);
REQUIRE(QPMULTI_VALID(*qpmp));
multi = *qpmp;
qp = &multi->writer;
dns_qpmulti_t *multi = *qpmp;
dns_qp_t *qp = &multi->writer;
*qpmp = NULL;
REQUIRE(QP_VALID(qp));
@ -1513,7 +1502,7 @@ isc_result_t
dns_qp_insert(dns_qp_t *qp, void *pval, uint32_t ival) {
qp_ref_t new_ref, old_ref;
qp_node_t new_leaf, old_node;
qp_node_t *new_twigs, *old_twigs;
qp_node_t *new_twigs = NULL, *old_twigs = NULL;
qp_shift_t new_bit, old_bit;
qp_weight_t old_size, new_size;
dns_qpkey_t new_key, old_key;
@ -1522,7 +1511,7 @@ dns_qp_insert(dns_qp_t *qp, void *pval, uint32_t ival) {
uint64_t index;
qp_shift_t bit;
qp_weight_t pos;
qp_node_t *n;
qp_node_t *n = NULL;
REQUIRE(QP_VALID(qp));
@ -1639,15 +1628,6 @@ growbranch:
isc_result_t
dns_qp_deletekey(dns_qp_t *qp, const dns_qpkey_t search_key,
size_t search_keylen) {
dns_qpkey_t found_key;
size_t found_keylen;
qp_shift_t bit = 0; /* suppress warning */
qp_weight_t pos, size;
qp_ref_t ref;
qp_node_t *twigs;
qp_node_t *parent;
qp_node_t *n;
REQUIRE(QP_VALID(qp));
REQUIRE(search_keylen < sizeof(dns_qpkey_t));
@ -1655,8 +1635,9 @@ dns_qp_deletekey(dns_qp_t *qp, const dns_qpkey_t search_key,
return (ISC_R_NOTFOUND);
}
parent = NULL;
n = make_root_mutable(qp);
qp_shift_t bit = 0; /* suppress warning */
qp_node_t *parent = NULL;
qp_node_t *n = make_root_mutable(qp);
while (is_branch(n)) {
prefetch_twigs(qp, n);
bit = branch_keybit(n, search_key, search_keylen);
@ -1668,7 +1649,8 @@ dns_qp_deletekey(dns_qp_t *qp, const dns_qpkey_t search_key,
n = branch_twig_ptr(qp, n, bit);
}
found_keylen = leaf_qpkey(qp, n, found_key);
dns_qpkey_t found_key;
size_t found_keylen = leaf_qpkey(qp, n, found_key);
if (qpkey_compare(search_key, search_keylen, found_key, found_keylen) !=
QPKEY_EQUAL)
{
@ -1692,10 +1674,10 @@ dns_qp_deletekey(dns_qp_t *qp, const dns_qpkey_t search_key,
parent = NULL;
INSIST(bit != 0);
size = branch_twigs_size(n);
pos = branch_twig_pos(n, bit);
ref = branch_twigs_ref(n);
twigs = ref_ptr(qp, ref);
qp_weight_t size = branch_twigs_size(n);
qp_weight_t pos = branch_twig_pos(n, bit);
qp_ref_t ref = branch_twigs_ref(n);
qp_node_t *twigs = ref_ptr(qp, ref);
if (size == 2) {
/*
@ -1801,7 +1783,7 @@ dns_qp_getkey(dns_qpreadable_t qpr, const dns_qpkey_t search_key,
dns_qpkey_t found_key;
size_t found_keylen;
qp_shift_t bit;
qp_node_t *n;
qp_node_t *n = NULL;
REQUIRE(QP_VALID(qp));
REQUIRE(pval_r != NULL);
@ -1850,7 +1832,7 @@ dns_qp_findname_parent(dns_qpreadable_t qpr, const dns_name_t *name,
size_t searchlen, foundlen;
size_t offset;
qp_shift_t bit;
qp_node_t *n, *twigs;
qp_node_t *n = NULL, *twigs = NULL;
isc_result_t result;
unsigned int labels = 0;
struct offref {

View file

@ -894,34 +894,6 @@ unpack_reader(dns_qpreader_t *qp, qp_node_t *reader) {
* method invocation helpers
*/
#if 0
#define attach_leaf(qp, n) \
do { \
uint32_t iv = leaf_ival(n); \
void *pv = leaf_pval(n); \
uint32_t r = qp->methods->attach(qp->uctx, pv, iv); \
fprintf(stderr, \
"%s:%u:%s():t%u qp %p node %p leaf %p %u " \
"(%u -> %u)\n", \
__FILE__, __LINE__, __func__, isc_tid(), qp, n, pv, \
iv, r, r + 1); \
} while (0)
#define detach_leaf(qp, n) \
do { \
uint32_t iv = leaf_ival(n); \
void *pv = leaf_pval(n); \
uint32_t r = qp->methods->detach(qp->uctx, pv, iv); \
fprintf(stderr, \
"%s:%u:%s():t%u qp %p node %p leaf %p %u " \
"(%u -> %u)\n", \
__FILE__, __LINE__, __func__, isc_tid(), qp, n, pv, \
iv, r, r - 1); \
} while (0)
#else
static inline void
attach_leaf(dns_qpreadable_t qpr, qp_node_t *n) {
dns_qpreader_t *qp = dns_qpreader(qpr);
@ -934,8 +906,6 @@ detach_leaf(dns_qpreadable_t qpr, qp_node_t *n) {
qp->methods->detach(qp->uctx, leaf_pval(n), leaf_ival(n));
}
#endif
static inline size_t
leaf_qpkey(dns_qpreadable_t qpr, qp_node_t *n, dns_qpkey_t key) {
dns_qpreader_t *qp = dns_qpreader(qpr);

View file

@ -37,11 +37,10 @@ struct {
dns_fixedname_t fixed;
} item[1024 * 1024];
static uint32_t
static void
item_check(void *ctx, void *pval, uint32_t ival) {
UNUSED(ctx);
assert(pval == &item[ival]);
return (1);
}
static size_t
@ -57,7 +56,7 @@ testname(void *ctx, char *buf, size_t size) {
strlcpy(buf, "test", size);
}
const struct dns_qpmethods qpmethods = {
const dns_qpmethods_t qpmethods = {
item_check,
item_check,
item_makekey,
@ -201,7 +200,7 @@ static struct fun {
#define FILE_CHECK(check, msg) \
do { \
if (!(check)) { \
fprintf(stderr, "%s:%zu: %s\n", filename, count, msg); \
fprintf(stderr, "%s:%zu: %s\n", filename, lines, msg); \
exit(1); \
} \
} while (0)
@ -209,6 +208,12 @@ static struct fun {
int
main(int argc, char *argv[]) {
isc_result_t result;
const char *filename = NULL;
char *filetext = NULL;
off_t fileoff;
FILE *fp = NULL;
size_t filesize, lines = 0, wirebytes = 0, labels = 0;
char *pos = NULL, *file_end = NULL;
isc_mem_create(&mctx);
@ -217,18 +222,17 @@ main(int argc, char *argv[]) {
exit(1);
}
const char *filename = argv[1];
off_t fileoff;
filename = argv[1];
result = isc_file_getsize(filename, &fileoff);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "stat(%s): %s\n", filename,
isc_result_totext(result));
exit(1);
}
size_t filesize = (size_t)fileoff;
filesize = (size_t)fileoff;
char *filetext = isc_mem_get(mctx, filesize + 1);
FILE *fp = fopen(filename, "r");
filetext = isc_mem_get(mctx, filesize + 1);
fp = fopen(filename, "r");
if (fp == NULL || fread(filetext, 1, filesize, fp) < filesize) {
fprintf(stderr, "read(%s): %s\n", filename, strerror(errno));
exit(1);
@ -236,29 +240,28 @@ main(int argc, char *argv[]) {
fclose(fp);
filetext[filesize] = '\0';
size_t count = 0;
size_t wirebytes = 0;
size_t labels = 0;
char *pos = filetext;
char *file_end = pos + filesize;
pos = filetext;
file_end = pos + filesize;
while (pos < file_end) {
FILE_CHECK(count < ARRAY_SIZE(item), "too many lines");
char *domain = NULL, *newline = NULL;
size_t len;
FILE_CHECK(lines < ARRAY_SIZE(item), "too many lines");
pos += strspn(pos, "0123456789");
FILE_CHECK(*pos++ == ',', "missing comma");
char *domain = pos;
domain = pos;
pos += strcspn(pos, "\r\n");
FILE_CHECK(*pos != '\0', "missing newline");
char *newline = pos;
newline = pos;
pos += strspn(pos, "\r\n");
size_t len = newline - domain;
len = newline - domain;
item[count].text = domain;
item[lines].text = domain;
domain[len] = '\0';
dns_name_t *name = dns_fixedname_initname(&item[count].fixed);
dns_name_t *name = dns_fixedname_initname(&item[lines].fixed);
isc_buffer_t buffer;
isc_buffer_init(&buffer, domain, len);
isc_buffer_add(&buffer, len);
@ -268,41 +271,35 @@ main(int argc, char *argv[]) {
wirebytes += name->length;
labels += name->labels;
count++;
lines++;
}
printf("names %g MB labels %g MB\n", (double)wirebytes / 1048576.0,
(double)labels / 1048576.0);
size_t lines = count;
for (struct fun *fun = fun_list; fun->name != NULL; fun++) {
isc_time_t t0;
t0 = isc_time_now_hires();
isc_mem_t *mem = NULL;
isc_mem_create(&mem);
void *map = fun->new (mem);
void *map = NULL;
for (count = 0; count < lines; count++) {
result = fun->add(map, count);
isc_mem_create(&mem);
map = fun->new (mem);
isc_time_t t0 = isc_time_now_hires();
for (size_t n = 0; n < lines; n++) {
result = fun->add(map, n);
CHECK(result);
}
fun->sqz(map);
isc_time_t t1;
t1 = isc_time_now_hires();
for (count = 0; count < lines; count++) {
isc_time_t t1 = isc_time_now_hires();
for (size_t n = 0; n < lines; n++) {
void *pval = NULL;
result = fun->get(map, count, &pval);
result = fun->get(map, n, &pval);
CHECK(result);
assert(pval == &item[count]);
assert(pval == &item[n]);
}
isc_time_t t2;
t2 = isc_time_now_hires();
isc_time_t t2 = isc_time_now_hires();
printf("%f sec to load %s\n",
(double)isc_time_microdiff(&t1, &t0) / (1000.0 * 1000.0),
fun->name);

View file

@ -95,19 +95,17 @@ qpkey_from_smallname(dns_qpkey_t key, void *ctx, void *pval, uint32_t ival) {
return (dns_qpkey_fromname(key, &name));
}
static uint32_t
static void
smallname_attach(void *ctx, void *pval, uint32_t ival) {
UNUSED(ctx);
return (isc_refcount_increment0(smallname_refcount(pval, ival)));
isc_refcount_increment0(smallname_refcount(pval, ival));
}
static uint32_t
static void
smallname_detach(void *ctx, void *pval, uint32_t ival) {
uint32_t refs = isc_refcount_decrement(smallname_refcount(pval, ival));
if (refs == 1) {
if (isc_refcount_decrement(smallname_refcount(pval, ival)) == 1) {
isc_mem_free(ctx, pval);
}
return (refs);
}
static void
@ -116,7 +114,7 @@ testname(void *ctx, char *buf, size_t size) {
strlcpy(buf, "test", size);
}
const struct dns_qpmethods methods = {
const dns_qpmethods_t methods = {
smallname_attach,
smallname_detach,
qpkey_from_smallname,
@ -126,15 +124,23 @@ const struct dns_qpmethods methods = {
static void
usage(void) {
fprintf(stderr,
"usage: qp_dump [-drt] <filename>\n"
"usage: qp_dump [-dt] <filename>\n"
" -d output in graphviz dot format\n"
" -t output in ad-hoc indented text format\n");
}
int
main(int argc, char *argv[]) {
bool dumpdot = false;
bool dumptxt = false;
isc_result_t result;
dns_qp_t *qp = NULL;
const char *filename = NULL;
char *filetext = NULL;
size_t filesize;
off_t fileoff;
FILE *fp = NULL;
size_t wirebytes = 0, labels = 0, names = 0;
char *pos = NULL, *file_end = NULL;
bool dumpdot = false, dumptxt = false;
int opt;
while ((opt = isc_commandline_parse(argc, argv, "dt")) != -1) {
@ -162,18 +168,17 @@ main(int argc, char *argv[]) {
isc_mem_create(&mctx);
const char *filename = argv[0];
off_t fileoff;
isc_result_t result = isc_file_getsize(filename, &fileoff);
filename = argv[0];
result = isc_file_getsize(filename, &fileoff);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "stat(%s): %s\n", filename,
isc_result_totext(result));
exit(1);
}
size_t filesize = (size_t)fileoff;
char *filetext = isc_mem_get(mctx, filesize + 1);
FILE *fp = fopen(filename, "r");
filesize = (size_t)fileoff;
filetext = isc_mem_get(mctx, filesize + 1);
fp = fopen(filename, "r");
if (fp == NULL || fread(filetext, 1, filesize, fp) < filesize) {
fprintf(stderr, "read(%s): %s\n", filename, strerror(errno));
exit(1);
@ -181,31 +186,30 @@ main(int argc, char *argv[]) {
fclose(fp);
filetext[filesize] = '\0';
dns_qp_t *qp = NULL;
dns_qp_create(mctx, &methods, NULL, &qp);
size_t wirebytes = 0;
size_t labels = 0;
size_t names = 0;
char *pos = filetext;
char *file_end = pos + filesize;
pos = filetext;
file_end = pos + filesize;
while (pos < file_end) {
char *domain = pos;
pos += strcspn(pos, "\r\n");
char *newline = pos;
pos += strspn(pos, "\r\n");
size_t len = newline - domain;
domain[len] = '\0';
void *pval = NULL;
uint32_t ival = 0;
dns_fixedname_t fixed;
dns_name_t *name = dns_fixedname_initname(&fixed);
isc_buffer_t buffer;
char *newline = NULL, *domain = pos;
size_t len;
pos += strcspn(pos, "\r\n");
newline = pos;
pos += strspn(pos, "\r\n");
len = newline - domain;
domain[len] = '\0';
isc_buffer_init(&buffer, domain, len);
isc_buffer_add(&buffer, len);
result = dns_name_fromtext(name, &buffer, dns_rootname, 0,
NULL);
void *pval = NULL;
uint32_t ival = 0;
if (result == ISC_R_SUCCESS) {
smallname_from_name(name, &pval, &ival);
result = dns_qp_insert(qp, pval, ival);
@ -226,15 +230,16 @@ main(int argc, char *argv[]) {
}
dns_qp_compact(qp, DNS_QPGC_ALL);
size_t smallbytes = wirebytes + labels + names * sizeof(isc_refcount_t);
dns_qp_memusage_t memusage = dns_qp_memusage(qp);
uint64_t compaction_us, recovery_us, rollback_us;
dns_qp_gctime(&compaction_us, &recovery_us, &rollback_us);
#define print_megabytes(label, value) \
printf("%6.2f MiB - " label "\n", (double)(value) / 1048576.0)
if (!dumptxt && !dumpdot) {
size_t smallbytes = wirebytes + labels +
names * sizeof(isc_refcount_t);
dns_qp_memusage_t memusage = dns_qp_memusage(qp);
uint64_t compaction_us, recovery_us, rollback_us;
dns_qp_gctime(&compaction_us, &recovery_us, &rollback_us);
printf("leaves %zu\n"
" nodes %zu\n"
" used %zu\n"
@ -264,10 +269,12 @@ main(int argc, char *argv[]) {
printf("%6zu - max key len\n", qp_test_maxkeylen(qp));
}
if (dumptxt)
if (dumptxt) {
qp_test_dumptrie(qp);
if (dumpdot)
}
if (dumpdot) {
qp_test_dumpdot(qp);
}
return (0);
}

View file

@ -89,12 +89,11 @@ static struct {
dns_qpkey_t key;
} *item;
static uint32_t
static void
item_refcount(void *ctx, void *pval, uint32_t ival) {
UNUSED(ctx);
UNUSED(pval);
UNUSED(ival);
return (1);
}
static size_t
@ -111,7 +110,7 @@ benchname(void *ctx, char *buf, size_t size) {
strlcpy(buf, "bench", size);
}
const struct dns_qpmethods item_methods = {
const dns_qpmethods_t item_methods = {
item_refcount,
item_refcount,
item_makekey,
@ -128,13 +127,12 @@ init_items(isc_mem_t *mctx) {
void *pval = NULL;
uint32_t ival = ~0U;
dns_qp_t *qp = NULL;
size_t bytes = ITEM_COUNT * sizeof(*item);
uint64_t start;
start = isc_time_monotonic();
item = isc_mem_allocatex(mctx, bytes, ISC_MEM_ZERO);
uint64_t start = isc_time_monotonic();
/* ensure there are no duplicate names */
dns_qp_create(mctx, &item_methods, NULL, &qp);
for (size_t i = 0; i < ITEM_COUNT; i++) {
@ -224,6 +222,7 @@ first_loop(void *varg) {
static void
next_loop(struct thread_args *args, isc_nanosecs_t start) {
isc_nanosecs_t stop = isc_time_monotonic();
args->worked += stop - start;
args->stop = stop;
if (args->stop - args->start < RUNTIME) {
@ -238,6 +237,9 @@ next_loop(struct thread_args *args, isc_nanosecs_t start) {
static void
read_zipf(uv_idle_t *idle) {
struct thread_args *args = idle->data;
isc_nanosecs_t start;
void *pval = NULL;
uint32_t ival;
/* outside time because it is v slow */
uint32_t r[args->tx_per_loop][args->ops_per_tx];
@ -247,10 +249,7 @@ read_zipf(uv_idle_t *idle) {
}
}
isc_nanosecs_t start = isc_time_monotonic();
void *pval;
uint32_t ival;
start = isc_time_monotonic();
for (uint32_t tx = 0; tx < args->tx_per_loop; tx++) {
args->transactions++;
dns_qpread_t qp;
@ -277,7 +276,7 @@ static void
read_transactions(uv_idle_t *idle) {
struct thread_args *args = idle->data;
isc_nanosecs_t start = isc_time_monotonic();
void *pval;
void *pval = NULL;
uint32_t ival;
for (uint32_t tx = 0; tx < args->tx_per_loop; tx++) {
@ -379,13 +378,13 @@ static void
load_multi(struct bench_state *bctx) {
dns_qp_t *qp = NULL;
size_t count = 0;
uint64_t start = isc_time_monotonic();
uint64_t start;
dns_qpmulti_create(bctx->mctx, bctx->loopmgr, &item_methods, NULL,
&bctx->multi);
/* initial contents of the trie */
start = isc_time_monotonic();
dns_qpmulti_update(bctx->multi, &qp);
for (size_t i = 0; i < bctx->max_item; i++) {
if (isc_random_uniform(2) == 0) {
@ -745,11 +744,18 @@ dispatch(struct bench_state *bctx) {
static void
collect(void *varg) {
TRACE("");
struct thread_args *args = varg;
struct bench_state *bctx = args->bctx;
struct thread_args *thread = bctx->thread;
struct {
uint64_t worked, txns, ops, compactions;
} stats[2] = {};
double load_time = bctx->load_time;
double elapsed = 0, mut_work, readers, read_work, elapsed_ms;
uint32_t nloops;
bool zipf;
TRACE("collect");
bctx->waiting--;
if (bctx->waiting > 0) {
@ -757,20 +763,15 @@ collect(void *varg) {
}
isc_barrier_destroy(&bctx->barrier);
struct {
uint64_t worked, txns, ops, compactions;
} stats[2] = {};
double load_time = bctx->load_time;
load_time = load_time > 0 ? load_time / (double)NS_PER_SEC : NAN;
double elapsed = 0;
bool zipf = bctx->mutate == 0 && bctx->readers == 0;
uint32_t nloops = zipf ? bctx->nloops : bctx->readers + bctx->mutate;
zipf = bctx->mutate == 0 && bctx->readers == 0;
nloops = zipf ? bctx->nloops : bctx->readers + bctx->mutate;
for (uint32_t t = 0; t < nloops; t++) {
struct thread_args *tp = &thread[t];
elapsed = ISC_MAX(elapsed, (tp->stop - tp->start));
bool mut = t < bctx->mutate;
stats[mut].worked += tp->worked;
stats[mut].txns += tp->transactions;
stats[mut].ops += tp->transactions * tp->ops_per_tx;
@ -783,7 +784,7 @@ collect(void *varg) {
printf("%7.2f\t", (double)bctx->qp_bytes / bctx->qp_items);
printf("%7u\t", bctx->max_item);
double mut_work = stats[1].worked / (double)US_PER_MS;
mut_work = stats[1].worked / (double)US_PER_MS;
printf("%7u\t", bctx->mutate);
printf("%7u\t", bctx->mut_tx_per_loop);
printf("%7u\t", bctx->mut_ops_per_tx);
@ -794,9 +795,9 @@ collect(void *varg) {
printf("%7.2f\t", stats[1].txns / mut_work);
printf("%7.2f\t", stats[1].ops / mut_work);
double readers = zipf ? bctx->nloops - bctx->mutate : bctx->readers;
double read_work = stats[0].worked / (double)US_PER_MS;
double elapsed_ms = elapsed / (double)US_PER_MS;
readers = zipf ? bctx->nloops - bctx->mutate : bctx->readers;
read_work = stats[0].worked / (double)US_PER_MS;
elapsed_ms = elapsed / (double)US_PER_MS;
printf("%7u\t", bctx->readers);
printf("%7u\t", bctx->read_tx_per_loop);
printf("%7u\t", bctx->read_ops_per_tx);
@ -817,10 +818,8 @@ startup(void *arg) {
isc_loop_t *loop = isc_loop_current(loopmgr);
isc_mem_t *mctx = isc_loop_getmctx(loop);
uint32_t nloops = isc_loopmgr_nloops(loopmgr);
size_t bytes = sizeof(struct bench_state) +
sizeof(struct thread_args) * nloops;
struct bench_state *bctx = isc_mem_getx(mctx, bytes, ISC_MEM_ZERO);
*bctx = (struct bench_state){
@ -885,9 +884,9 @@ int
main(void) {
isc_loopmgr_t *loopmgr = NULL;
isc_mem_t *mctx = NULL;
uint32_t nloops;
const char *env_workers = getenv("ISC_TASK_WORKERS");
if (env_workers != NULL) {
nloops = atoi(env_workers);
} else {

View file

@ -136,12 +136,11 @@ ISC_RUN_TEST_IMPL(qpkey_sort) {
#define ITER_ITEMS 100
static uint32_t
static void
check_leaf(void *uctx, void *pval, uint32_t ival) {
uint32_t *items = uctx;
assert_in_range(ival, 1, ITER_ITEMS - 1);
assert_ptr_equal(items + ival, pval);
return (1);
}
static size_t
@ -168,7 +167,7 @@ getname(void *uctx, char *buf, size_t size) {
UNUSED(size);
}
const struct dns_qpmethods qpiter_methods = {
const dns_qpmethods_t qpiter_methods = {
check_leaf,
check_leaf,
qpiter_makekey,
@ -216,12 +215,11 @@ ISC_RUN_TEST_IMPL(qpiter) {
dns_qp_destroy(&qp);
}
static uint32_t
static void
no_op(void *uctx, void *pval, uint32_t ival) {
UNUSED(uctx);
UNUSED(pval);
UNUSED(ival);
return (1);
}
static size_t
@ -237,7 +235,7 @@ qpkey_fromstring(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival) {
return (dns_qpkey_fromname(key, dns_fixedname_name(&fixed)));
}
const struct dns_qpmethods string_methods = {
const dns_qpmethods_t string_methods = {
no_op,
no_op,
qpkey_fromstring,

View file

@ -104,19 +104,19 @@ static struct {
dns_qpkey_t ascii;
} item[ITEM_COUNT];
static uint32_t
static void
item_attach(void *ctx, void *pval, uint32_t ival) {
assert_null(ctx);
assert_ptr_equal(pval, &item[ival]);
return (item[ival].refcount++);
INSIST(ctx == NULL);
INSIST(pval == &item[ival]);
item[ival].refcount++;
}
static uint32_t
static void
item_detach(void *ctx, void *pval, uint32_t ival) {
assert_null(ctx);
assert_ptr_equal(pval, &item[ival]);
assert_int_not_equal(item[ival].refcount, 0);
return (item[ival].refcount--);
item[ival].refcount--;
}
static size_t
@ -144,7 +144,7 @@ testname(void *ctx, char *buf, size_t size) {
strlcpy(buf, "test", size);
}
const struct dns_qpmethods test_methods = {
const dns_qpmethods_t test_methods = {
item_attach,
item_detach,
item_makekey,