2022-09-28 16:56:46 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
|
|
*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2023-06-21 14:10:28 +02:00
|
|
|
#include <isc/barrier.h>
|
2022-09-28 16:56:46 +01:00
|
|
|
#include <isc/file.h>
|
|
|
|
#include <isc/hashmap.h>
|
|
|
|
#include <isc/ht.h>
|
2025-02-04 13:17:31 +01:00
|
|
|
#include <isc/lib.h>
|
Refactor qp-trie to use QSBR
The first working multi-threaded qp-trie was stuck with an unpleasant
trade-off:
* Use `isc_rwlock`, which has acceptable write performance, but
terrible read scalability because the qp-trie made all accesses
through a single lock.
* Use `liburcu`, which has great read scalability, but terrible
write performance, because I was relying on `rcu_synchronize()`
which is rather slow. And `liburcu` is LGPL.
To get the best of both worlds, we need our own scalable read side,
which we now have with `isc_qsbr`. And we need to modify the write
side so that it is not blocked by readers.
Better write performance requires an async cleanup function like
`call_rcu()`, instead of the blocking `rcu_synchronize()`. (There
is no blocking cleanup in `isc_qsbr`, because I have concluded
that it would be an attractive nuisance.)
Until now, all my multithreading qp-trie designs have been based
around two versions, read-only and mutable. This is too few to
work with asynchronous cleanup. The bare minimum (as in epoch
based reclamation) is three, but it makes more sense to support an
arbitrary number. Doing multi-version support "properly" makes
fewer assumptions about how safe memory reclamation works, and it
makes snapshots and rollbacks simpler.
To avoid making the memory management even more complicated, I
have introduced a new kind of "packed reader node" to anchor the
root of a version of the trie. This is simpler because it re-uses
the existing chunk lifetime logic - see the discussion under
"packed reader nodes" in `qp_p.h`.
I have also made the chunk lifetime logic simpler. The idea of a
"generation" is gone; instead, chunks are either mutable or
immutable. And the QSBR phase number is used to indicate when a
chunk can be reclaimed.
Instead of the `shared_base` flag (which was basically a one-bit
reference count, with a two version limit) the base array now has a
refcount, which replaces the confusing ad-hoc lifetime logic with
something more familiar and systematic.
2022-12-22 14:55:14 +00:00
|
|
|
#include <isc/list.h>
|
2024-11-03 10:22:29 +01:00
|
|
|
#include <isc/refcount.h>
|
2022-09-28 16:56:46 +01:00
|
|
|
#include <isc/rwlock.h>
|
2023-06-21 14:10:28 +02:00
|
|
|
#include <isc/thread.h>
|
2023-03-08 14:52:30 +00:00
|
|
|
#include <isc/urcu.h>
|
2022-09-28 16:56:46 +01:00
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include <dns/fixedname.h>
|
2025-02-04 13:17:31 +01:00
|
|
|
#include <dns/lib.h>
|
2022-09-28 16:56:46 +01:00
|
|
|
#include <dns/qp.h>
|
|
|
|
#include <dns/types.h>
|
|
|
|
|
2025-02-21 12:09:28 +01:00
|
|
|
#include "dns/name.h"
|
2022-09-28 16:56:46 +01:00
|
|
|
#include "qp_p.h"
|
|
|
|
|
|
|
|
#include <tests/dns.h>
|
|
|
|
#include <tests/qp.h>
|
|
|
|
|
2023-06-21 14:10:28 +02:00
|
|
|
struct item_s {
|
2022-09-28 16:56:46 +01:00
|
|
|
const char *text;
|
|
|
|
dns_fixedname_t fixed;
|
2023-06-21 14:10:28 +02:00
|
|
|
struct cds_lfht_node ht_node;
|
2022-09-28 16:56:46 +01:00
|
|
|
} item[1024 * 1024];
|
|
|
|
|
2023-06-21 14:10:28 +02:00
|
|
|
isc_barrier_t barrier;
|
|
|
|
isc_rwlock_t rwl;
|
|
|
|
|
|
|
|
struct thread_s {
|
|
|
|
isc_thread_t thread;
|
|
|
|
struct fun *fun;
|
|
|
|
void *map;
|
|
|
|
size_t start;
|
|
|
|
size_t end;
|
|
|
|
uint64_t d0;
|
|
|
|
uint64_t d1;
|
|
|
|
} threads[1024];
|
|
|
|
|
2023-03-10 15:55:00 +00:00
|
|
|
static void
|
2022-09-28 16:56:46 +01:00
|
|
|
item_check(void *ctx, void *pval, uint32_t ival) {
|
|
|
|
UNUSED(ctx);
|
|
|
|
assert(pval == &item[ival]);
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
item_makekey(dns_qpkey_t key, void *ctx, void *pval, uint32_t ival) {
|
|
|
|
UNUSED(ctx);
|
|
|
|
assert(pval == &item[ival]);
|
|
|
|
return dns_qpkey_fromname(key, &item[ival].fixed.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
testname(void *ctx, char *buf, size_t size) {
|
|
|
|
REQUIRE(ctx == NULL);
|
|
|
|
strlcpy(buf, "test", size);
|
|
|
|
}
|
|
|
|
|
2023-03-10 15:55:00 +00:00
|
|
|
const dns_qpmethods_t qpmethods = {
|
2022-09-28 16:56:46 +01:00
|
|
|
item_check,
|
|
|
|
item_check,
|
|
|
|
item_makekey,
|
|
|
|
testname,
|
|
|
|
};
|
|
|
|
|
2023-06-21 14:10:28 +02:00
|
|
|
#define CHECK(count, result) \
|
|
|
|
do { \
|
|
|
|
if (result != ISC_R_SUCCESS) { \
|
|
|
|
dns_name_t *name = &item[count].fixed.name; \
|
|
|
|
char buf[DNS_NAME_MAXTEXT] = { 0 }; \
|
|
|
|
dns_name_format(name, buf, sizeof(buf)); \
|
|
|
|
fprintf(stderr, "%s: %s\n", buf, \
|
|
|
|
isc_result_totext(result)); \
|
2024-02-07 14:50:38 +01:00
|
|
|
exit(EXIT_FAILURE); \
|
2023-06-21 14:10:28 +02:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
struct fun {
|
|
|
|
const char *name;
|
|
|
|
void *(*new)(isc_mem_t *mem);
|
|
|
|
isc_threadfunc_t thread;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* cds_lfht
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void *
|
|
|
|
new_lfht(isc_mem_t *mem ISC_ATTR_UNUSED) {
|
|
|
|
struct cds_lfht *lfht = cds_lfht_new(
|
|
|
|
1, 1, 0, CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
|
|
|
|
return lfht;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
lfht_match(struct cds_lfht_node *ht_node, const void *_key) {
|
|
|
|
const struct item_s *i = caa_container_of(ht_node, struct item_s,
|
|
|
|
ht_node);
|
|
|
|
const dns_name_t *key = _key;
|
|
|
|
|
|
|
|
return dns_name_equal(key, &i->fixed.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
add_lfht(void *lfht, size_t count) {
|
|
|
|
unsigned long hash = dns_name_hash(&item[count].fixed.name);
|
|
|
|
|
|
|
|
struct cds_lfht_node *ht_node = cds_lfht_add_unique(
|
|
|
|
lfht, hash, lfht_match, &item[count].fixed.name,
|
|
|
|
&item[count].ht_node);
|
|
|
|
|
|
|
|
if (ht_node != &item[count].ht_node) {
|
|
|
|
return ISC_R_EXISTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
get_lfht(void *lfht, size_t count, void **pval) {
|
|
|
|
unsigned long hash = dns_name_hash(&item[count].fixed.name);
|
|
|
|
|
|
|
|
struct cds_lfht_iter iter;
|
|
|
|
cds_lfht_lookup(lfht, hash, lfht_match, &item[count].fixed.name, &iter);
|
|
|
|
|
|
|
|
struct cds_lfht_node *ht_node = cds_lfht_iter_get_node(&iter);
|
|
|
|
if (ht_node == NULL) {
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pval = caa_container_of(ht_node, struct item_s, ht_node);
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
thread_lfht(void *arg0) {
|
|
|
|
struct thread_s *arg = arg0;
|
|
|
|
|
|
|
|
isc_barrier_wait(&barrier);
|
|
|
|
|
|
|
|
isc_time_t t0 = isc_time_now_hires();
|
|
|
|
for (size_t n = arg->start; n < arg->end; n++) {
|
|
|
|
isc_result_t result = add_lfht(arg->map, n);
|
|
|
|
CHECK(n, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_time_t t1 = isc_time_now_hires();
|
|
|
|
for (size_t n = arg->start; n < arg->end; n++) {
|
|
|
|
void *pval = NULL;
|
|
|
|
isc_result_t result = get_lfht(arg->map, n, &pval);
|
|
|
|
CHECK(n, result);
|
|
|
|
assert(pval == &item[n]);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_time_t t2 = isc_time_now_hires();
|
|
|
|
|
|
|
|
arg->d0 = isc_time_microdiff(&t1, &t0);
|
|
|
|
arg->d1 = isc_time_microdiff(&t2, &t1);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-09-28 16:56:46 +01:00
|
|
|
/*
|
|
|
|
* hashmap
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void *
|
|
|
|
new_hashmap(isc_mem_t *mem) {
|
|
|
|
isc_hashmap_t *hashmap = NULL;
|
2023-08-28 10:08:59 +02:00
|
|
|
isc_hashmap_create(mem, 1, &hashmap);
|
2023-06-21 14:10:28 +02:00
|
|
|
|
2022-09-28 16:56:46 +01:00
|
|
|
return hashmap;
|
|
|
|
}
|
|
|
|
|
2023-08-28 10:08:59 +02:00
|
|
|
static bool
|
|
|
|
name_match(void *node, const void *key) {
|
2023-10-06 10:28:32 +02:00
|
|
|
const struct item_s *i = node;
|
|
|
|
return dns_name_equal(&i->fixed.name, key);
|
2023-08-28 10:08:59 +02:00
|
|
|
}
|
|
|
|
|
2022-09-28 16:56:46 +01:00
|
|
|
static isc_result_t
|
|
|
|
add_hashmap(void *hashmap, size_t count) {
|
2023-08-28 10:08:59 +02:00
|
|
|
isc_result_t result = isc_hashmap_add(
|
|
|
|
hashmap, dns_name_hash(&item[count].fixed.name), name_match,
|
|
|
|
&item[count].fixed.name, &item[count], NULL);
|
2023-06-21 14:10:28 +02:00
|
|
|
return result;
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
get_hashmap(void *hashmap, size_t count, void **pval) {
|
2023-08-28 10:08:59 +02:00
|
|
|
isc_result_t result = isc_hashmap_find(
|
|
|
|
hashmap, dns_name_hash(&item[count].fixed.name), name_match,
|
|
|
|
&item[count].fixed.name, pval);
|
2023-06-21 14:10:28 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
thread_hashmap(void *arg0) {
|
|
|
|
struct thread_s *arg = arg0;
|
|
|
|
|
|
|
|
isc_barrier_wait(&barrier);
|
|
|
|
|
|
|
|
isc_time_t t0 = isc_time_now_hires();
|
|
|
|
WRLOCK(&rwl);
|
|
|
|
for (size_t n = arg->start; n < arg->end; n++) {
|
|
|
|
isc_result_t result = add_hashmap(arg->map, n);
|
|
|
|
CHECK(n, result);
|
|
|
|
}
|
|
|
|
WRUNLOCK(&rwl);
|
|
|
|
|
|
|
|
isc_time_t t1 = isc_time_now_hires();
|
|
|
|
RDLOCK(&rwl);
|
|
|
|
for (size_t n = arg->start; n < arg->end; n++) {
|
|
|
|
void *pval = NULL;
|
|
|
|
isc_result_t result = get_hashmap(arg->map, n, &pval);
|
|
|
|
CHECK(n, result);
|
|
|
|
assert(pval == &item[n]);
|
|
|
|
}
|
|
|
|
RDUNLOCK(&rwl);
|
|
|
|
isc_time_t t2 = isc_time_now_hires();
|
|
|
|
|
|
|
|
arg->d0 = isc_time_microdiff(&t1, &t0);
|
|
|
|
arg->d1 = isc_time_microdiff(&t2, &t1);
|
|
|
|
|
|
|
|
return NULL;
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ht
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void *
|
|
|
|
new_ht(isc_mem_t *mem) {
|
|
|
|
isc_ht_t *ht = NULL;
|
2023-06-21 14:10:28 +02:00
|
|
|
isc_ht_init(&ht, mem, 1, 0);
|
2022-09-28 16:56:46 +01:00
|
|
|
return ht;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
add_ht(void *ht, size_t count) {
|
2023-06-21 14:10:28 +02:00
|
|
|
isc_result_t result = isc_ht_add(ht, item[count].fixed.name.ndata,
|
|
|
|
item[count].fixed.name.length,
|
|
|
|
&item[count]);
|
|
|
|
return result;
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
get_ht(void *ht, size_t count, void **pval) {
|
2023-06-21 14:10:28 +02:00
|
|
|
isc_result_t result = isc_ht_find(ht, item[count].fixed.name.ndata,
|
|
|
|
item[count].fixed.name.length, pval);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
thread_ht(void *arg0) {
|
|
|
|
struct thread_s *arg = arg0;
|
|
|
|
|
|
|
|
isc_barrier_wait(&barrier);
|
|
|
|
|
|
|
|
isc_time_t t0 = isc_time_now_hires();
|
|
|
|
WRLOCK(&rwl);
|
|
|
|
for (size_t n = arg->start; n < arg->end; n++) {
|
|
|
|
isc_result_t result = add_ht(arg->map, n);
|
|
|
|
CHECK(n, result);
|
|
|
|
}
|
|
|
|
WRUNLOCK(&rwl);
|
|
|
|
|
|
|
|
isc_time_t t1 = isc_time_now_hires();
|
|
|
|
RDLOCK(&rwl);
|
|
|
|
for (size_t n = arg->start; n < arg->end; n++) {
|
|
|
|
void *pval = NULL;
|
|
|
|
isc_result_t result = get_ht(arg->map, n, &pval);
|
|
|
|
CHECK(n, result);
|
|
|
|
assert(pval == &item[n]);
|
|
|
|
}
|
|
|
|
RDUNLOCK(&rwl);
|
|
|
|
isc_time_t t2 = isc_time_now_hires();
|
|
|
|
|
|
|
|
arg->d0 = isc_time_microdiff(&t1, &t0);
|
|
|
|
arg->d1 = isc_time_microdiff(&t2, &t1);
|
|
|
|
|
|
|
|
return NULL;
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qp
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void *
|
|
|
|
new_qp(isc_mem_t *mem) {
|
2023-06-21 14:10:28 +02:00
|
|
|
dns_qpmulti_t *qpmulti = NULL;
|
|
|
|
dns_qpmulti_create(mem, &qpmethods, NULL, &qpmulti);
|
|
|
|
return qpmulti;
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
add_qp(void *qp, size_t count) {
|
2023-06-21 14:10:28 +02:00
|
|
|
isc_result_t result = dns_qp_insert(qp, &item[count], count);
|
|
|
|
return result;
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sqz_qp(void *qp) {
|
2024-02-08 08:30:38 +01:00
|
|
|
dns_qp_compact(qp, DNS_QPGC_MAYBE);
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
get_qp(void *qp, size_t count, void **pval) {
|
2023-04-06 11:24:47 +01:00
|
|
|
return dns_qp_getname(qp, &item[count].fixed.name, pval, NULL);
|
2023-06-21 14:10:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
_thread_qp(void *arg0, bool sqz, bool brr) {
|
|
|
|
struct thread_s *arg = arg0;
|
|
|
|
|
|
|
|
isc_barrier_wait(&barrier);
|
|
|
|
|
|
|
|
dns_qp_t *qp = NULL;
|
|
|
|
dns_qpmulti_write(arg->map, &qp);
|
|
|
|
|
|
|
|
isc_time_t t0 = isc_time_now_hires();
|
|
|
|
for (size_t n = arg->start; n < arg->end; n++) {
|
|
|
|
isc_result_t result = add_qp(qp, n);
|
|
|
|
CHECK(n, result);
|
|
|
|
}
|
|
|
|
if (sqz) {
|
|
|
|
sqz_qp(qp);
|
|
|
|
}
|
|
|
|
dns_qpmulti_commit(arg->map, &qp);
|
|
|
|
if (brr) {
|
|
|
|
rcu_barrier();
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_time_t t1 = isc_time_now_hires();
|
|
|
|
|
|
|
|
dns_qpread_t qpr;
|
|
|
|
dns_qpmulti_query(arg->map, &qpr);
|
|
|
|
|
|
|
|
for (size_t n = arg->start; n < arg->end; n++) {
|
|
|
|
void *pval = NULL;
|
|
|
|
isc_result_t result = get_qp(&qpr, n, &pval);
|
|
|
|
CHECK(n, result);
|
|
|
|
assert(pval == &item[n]);
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_qpread_destroy(arg->map, &qpr);
|
|
|
|
|
|
|
|
isc_time_t t2 = isc_time_now_hires();
|
|
|
|
|
|
|
|
arg->d0 = isc_time_microdiff(&t1, &t0);
|
|
|
|
arg->d1 = isc_time_microdiff(&t2, &t1);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
thread_qp(void *arg0) {
|
|
|
|
return _thread_qp(arg0, true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
thread_qp_nosqz(void *arg0) {
|
|
|
|
return _thread_qp(arg0, false, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
thread_qp_brr(void *arg0) {
|
|
|
|
return _thread_qp(arg0, true, true);
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fun table
|
|
|
|
*/
|
2023-06-21 14:10:28 +02:00
|
|
|
static struct fun fun_list[] = {
|
|
|
|
{ "lfht", new_lfht, thread_lfht },
|
|
|
|
{ "ht", new_ht, thread_ht },
|
|
|
|
{ "hashmap", new_hashmap, thread_hashmap },
|
|
|
|
{ "qp", new_qp, thread_qp },
|
|
|
|
{ "qp+nosqz", new_qp, thread_qp_nosqz },
|
|
|
|
{ "qp+barrier", new_qp, thread_qp_brr },
|
|
|
|
{ NULL, NULL, NULL },
|
2022-09-28 16:56:46 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#define FILE_CHECK(check, msg) \
|
|
|
|
do { \
|
|
|
|
if (!(check)) { \
|
2023-03-10 15:55:00 +00:00
|
|
|
fprintf(stderr, "%s:%zu: %s\n", filename, lines, msg); \
|
2024-02-07 14:50:38 +01:00
|
|
|
exit(EXIT_FAILURE); \
|
2022-09-28 16:56:46 +01:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[]) {
|
|
|
|
isc_result_t result;
|
2023-03-10 15:55:00 +00:00
|
|
|
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;
|
2022-09-28 16:56:46 +01:00
|
|
|
|
2023-06-21 14:10:28 +02:00
|
|
|
isc_rwlock_init(&rwl);
|
|
|
|
|
2022-09-28 16:56:46 +01:00
|
|
|
isc_mem_create(&mctx);
|
|
|
|
|
|
|
|
if (argc != 2) {
|
2023-06-21 14:10:28 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
"usage: load-names <filename.csv> <nthreads>\n");
|
2024-02-07 14:50:38 +01:00
|
|
|
exit(EXIT_FAILURE);
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
|
|
|
|
2023-03-10 15:55:00 +00:00
|
|
|
filename = argv[1];
|
2022-09-28 16:56:46 +01:00
|
|
|
result = isc_file_getsize(filename, &fileoff);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "stat(%s): %s\n", filename,
|
|
|
|
isc_result_totext(result));
|
2024-02-07 14:50:38 +01:00
|
|
|
exit(EXIT_FAILURE);
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
2023-03-10 15:55:00 +00:00
|
|
|
filesize = (size_t)fileoff;
|
2022-09-28 16:56:46 +01:00
|
|
|
|
2023-03-10 15:55:00 +00:00
|
|
|
filetext = isc_mem_get(mctx, filesize + 1);
|
|
|
|
fp = fopen(filename, "r");
|
2022-09-28 16:56:46 +01:00
|
|
|
if (fp == NULL || fread(filetext, 1, filesize, fp) < filesize) {
|
|
|
|
fprintf(stderr, "read(%s): %s\n", filename, strerror(errno));
|
2024-02-07 14:50:38 +01:00
|
|
|
exit(EXIT_FAILURE);
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
filetext[filesize] = '\0';
|
|
|
|
|
2023-03-10 15:55:00 +00:00
|
|
|
pos = filetext;
|
|
|
|
file_end = pos + filesize;
|
2022-09-28 16:56:46 +01:00
|
|
|
while (pos < file_end) {
|
2023-03-10 15:55:00 +00:00
|
|
|
char *domain = NULL, *newline = NULL;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
FILE_CHECK(lines < ARRAY_SIZE(item), "too many lines");
|
2022-09-28 16:56:46 +01:00
|
|
|
pos += strspn(pos, "0123456789");
|
|
|
|
|
|
|
|
FILE_CHECK(*pos++ == ',', "missing comma");
|
|
|
|
|
2023-03-10 15:55:00 +00:00
|
|
|
domain = pos;
|
2022-09-28 16:56:46 +01:00
|
|
|
pos += strcspn(pos, "\r\n");
|
|
|
|
FILE_CHECK(*pos != '\0', "missing newline");
|
2023-03-10 15:55:00 +00:00
|
|
|
newline = pos;
|
2022-09-28 16:56:46 +01:00
|
|
|
pos += strspn(pos, "\r\n");
|
2023-03-10 15:55:00 +00:00
|
|
|
len = newline - domain;
|
2022-09-28 16:56:46 +01:00
|
|
|
|
2023-03-10 15:55:00 +00:00
|
|
|
item[lines].text = domain;
|
2022-09-28 16:56:46 +01:00
|
|
|
domain[len] = '\0';
|
|
|
|
|
2023-03-10 15:55:00 +00:00
|
|
|
dns_name_t *name = dns_fixedname_initname(&item[lines].fixed);
|
2022-09-28 16:56:46 +01:00
|
|
|
isc_buffer_t buffer;
|
|
|
|
isc_buffer_init(&buffer, domain, len);
|
|
|
|
isc_buffer_add(&buffer, len);
|
2025-02-22 00:11:38 -08:00
|
|
|
result = dns_name_fromtext(name, &buffer, dns_rootname, 0);
|
2022-09-28 16:56:46 +01:00
|
|
|
FILE_CHECK(result == ISC_R_SUCCESS, isc_result_totext(result));
|
|
|
|
|
|
|
|
wirebytes += name->length;
|
2025-02-21 12:09:28 +01:00
|
|
|
labels += dns_name_countlabels(name);
|
2023-03-10 15:55:00 +00:00
|
|
|
lines++;
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
|
|
|
|
2023-06-21 14:10:28 +02:00
|
|
|
printf("names %g MB labels %g MB\n\n", (double)wirebytes / 1048576.0,
|
2022-09-28 16:56:46 +01:00
|
|
|
(double)labels / 1048576.0);
|
|
|
|
|
2023-06-21 14:10:28 +02:00
|
|
|
printf("%10s | %10s | %10s | %10s | %10s | %10s | %10s |\n",
|
|
|
|
"algorithm", "threads", "load", "query", "dirty MB", "total",
|
|
|
|
"final MB");
|
2023-03-10 15:55:00 +00:00
|
|
|
|
2023-06-21 14:10:28 +02:00
|
|
|
for (size_t nthreads = 128; nthreads > 0; nthreads /= 2) {
|
|
|
|
printf("---------- | ---------- | ---------- | ---------- | "
|
|
|
|
"---------- | ---------- | ---------- |\n");
|
2022-09-28 16:56:46 +01:00
|
|
|
|
2023-06-21 14:10:28 +02:00
|
|
|
for (struct fun *fun = fun_list; fun->name != NULL; fun++) {
|
|
|
|
isc_mem_t *mem = NULL;
|
|
|
|
void *map = NULL;
|
|
|
|
|
|
|
|
isc_mem_create(&mem);
|
2024-08-15 09:36:53 +02:00
|
|
|
map = fun->new(mem);
|
2023-06-21 14:10:28 +02:00
|
|
|
|
2023-10-06 10:06:36 +02:00
|
|
|
size_t nitems = lines / (nthreads + 1);
|
2023-06-21 14:10:28 +02:00
|
|
|
|
|
|
|
isc_barrier_init(&barrier, nthreads);
|
|
|
|
|
|
|
|
isc_time_t t0 = isc_time_now_hires();
|
|
|
|
size_t m0 = isc_mem_inuse(mem);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < nthreads; i++) {
|
|
|
|
threads[i] = (struct thread_s){
|
|
|
|
.fun = fun,
|
|
|
|
.map = map,
|
|
|
|
.start = nitems * i,
|
|
|
|
.end = nitems * i + nitems,
|
|
|
|
};
|
|
|
|
isc_thread_create(fun->thread, &threads[i],
|
|
|
|
&threads[i].thread);
|
|
|
|
}
|
2022-09-28 16:56:46 +01:00
|
|
|
|
2023-06-21 14:10:28 +02:00
|
|
|
uint64_t d0 = 0;
|
|
|
|
uint64_t d1 = 0;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < nthreads; i++) {
|
|
|
|
isc_thread_join(threads[i].thread, NULL);
|
|
|
|
d0 += threads[i].d0;
|
|
|
|
d1 += threads[i].d1;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t m1 = isc_mem_inuse(mem);
|
|
|
|
|
|
|
|
rcu_barrier();
|
|
|
|
|
|
|
|
isc_time_t t1 = isc_time_now_hires();
|
|
|
|
uint64_t d3 = isc_time_microdiff(&t1, &t0);
|
|
|
|
size_t m2 = isc_mem_inuse(mem);
|
|
|
|
|
|
|
|
printf("%10s | %10zu | %10.4f | %10.4f | %10.4f | "
|
|
|
|
"%10.4f | %10.4f |\n",
|
|
|
|
fun->name, nthreads,
|
|
|
|
(double)(d0 / nthreads) / (1000.0 * 1000.0),
|
|
|
|
(double)(d1 / nthreads) / (1000.0 * 1000.0),
|
|
|
|
(double)(m1 - m0) / (1024.0 * 1024.0),
|
|
|
|
(double)d3 / (1000.0 * 1000.0),
|
|
|
|
(double)(m2 - m0) / (1024.0 * 1024.0)
|
|
|
|
|
|
|
|
);
|
|
|
|
}
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|
2023-06-21 14:10:28 +02:00
|
|
|
|
|
|
|
printf("---------- | ---------- | ---------- | ---------- | "
|
|
|
|
"---------- | ---------- | ---------- |\n");
|
2022-09-28 16:56:46 +01:00
|
|
|
}
|