Commit 493b6a9f authored by Witold Krecicki's avatar Witold Krecicki

Make hazard pointers max_threads configurable at runtime.

hp implementation requires an object for each thread accessing
a hazard pointer. previous implementation had a hardcoded
HP_MAX_THREAD value of 128, which failed on machines with lots of
CPU cores (named uses 3n threads). We make isc__hp_max_threads
configurable at startup, with the value set to 4*named_g_cpus.
It's also important for this value not to be too big as we do
linear searches on a list.
parent 1639dc8d
......@@ -23,6 +23,7 @@
#include <isc/dir.h>
#include <isc/file.h>
#include <isc/hash.h>
#include <isc/hp.h>
#include <isc/httpd.h>
#include <isc/netmgr.h>
#include <isc/os.h>
......@@ -907,6 +908,12 @@ create_managers(void) {
"using %u UDP listener%s per interface",
named_g_udpdisp, named_g_udpdisp == 1 ? "" : "s");
/*
* We have ncpus network threads, ncpus worker threads, ncpus
* old network threads - make it 4x just to be safe. The memory
* impact is neglible.
*/
isc_hp_init(4*named_g_cpus);
named_g_nm = isc_nm_start(named_g_mctx, named_g_cpus);
if (named_g_nm == NULL) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
......
......@@ -54,12 +54,13 @@
#include <isc/thread.h>
#define HP_MAX_THREADS 128
static int isc__hp_max_threads = HP_MAX_THREADS;
#define HP_MAX_HPS 4 /* This is named 'K' in the HP paper */
#define CLPAD (128 / sizeof(uintptr_t))
#define HP_THRESHOLD_R 0 /* This is named 'R' in the HP paper */
/* Maximum number of retired objects per thread */
#define MAX_RETIRED (HP_MAX_THREADS * HP_MAX_HPS)
static int isc__hp_max_retired = HP_MAX_THREADS * HP_MAX_HPS;
#define TID_UNKNOWN -1
......@@ -69,14 +70,14 @@ ISC_THREAD_LOCAL int tid_v = TID_UNKNOWN;
typedef struct retirelist {
int size;
uintptr_t list[MAX_RETIRED];
uintptr_t *list;
} retirelist_t;
struct isc_hp {
int max_hps;
isc_mem_t *mctx;
atomic_uintptr_t *hp[HP_MAX_THREADS];
retirelist_t *rl[HP_MAX_THREADS];
atomic_uintptr_t **hp;
retirelist_t **rl;
isc_hp_deletefunc_t *deletefunc;
};
......@@ -84,12 +85,18 @@ static inline int
tid() {
if (tid_v == TID_UNKNOWN) {
tid_v = atomic_fetch_add(&tid_v_base, 1);
REQUIRE(tid_v < HP_MAX_THREADS);
REQUIRE(tid_v < isc__hp_max_threads);
}
return (tid_v);
}
void
isc_hp_init(int max_threads) {
isc__hp_max_threads = max_threads;
isc__hp_max_retired = max_threads * HP_MAX_HPS;
}
isc_hp_t *
isc_hp_new(isc_mem_t *mctx, size_t max_hps, isc_hp_deletefunc_t *deletefunc) {
isc_hp_t *hp = isc_mem_get(mctx, sizeof(*hp));
......@@ -105,7 +112,10 @@ isc_hp_new(isc_mem_t *mctx, size_t max_hps, isc_hp_deletefunc_t *deletefunc) {
isc_mem_attach(mctx, &hp->mctx);
for (int i = 0; i < HP_MAX_THREADS; i++) {
hp->hp = isc_mem_get(mctx, isc__hp_max_threads * sizeof(hp->hp[0]));
hp->rl = isc_mem_get(mctx, isc__hp_max_threads * sizeof(hp->rl[0]));
for (int i = 0; i < isc__hp_max_threads; i++) {
hp->hp[i] = isc_mem_get(mctx, CLPAD * 2 * sizeof(hp->hp[i][0]));
hp->rl[i] = isc_mem_get(mctx, sizeof(*hp->rl[0]));
*hp->rl[i] = (retirelist_t) { .size = 0 };
......@@ -113,6 +123,7 @@ isc_hp_new(isc_mem_t *mctx, size_t max_hps, isc_hp_deletefunc_t *deletefunc) {
for (int j = 0; j < hp->max_hps; j++) {
atomic_init(&hp->hp[i][j], 0);
}
hp->rl[i]->list = isc_mem_get(hp->mctx, isc__hp_max_retired * sizeof(uintptr_t));
}
return (hp);
......@@ -120,7 +131,7 @@ isc_hp_new(isc_mem_t *mctx, size_t max_hps, isc_hp_deletefunc_t *deletefunc) {
void
isc_hp_destroy(isc_hp_t *hp) {
for (int i = 0; i < HP_MAX_THREADS; i++) {
for (int i = 0; i < isc__hp_max_threads; i++) {
isc_mem_put(hp->mctx, hp->hp[i],
CLPAD * 2 * sizeof(uintptr_t));
......@@ -128,9 +139,11 @@ isc_hp_destroy(isc_hp_t *hp) {
void *data = (void *)hp->rl[i]->list[j];
hp->deletefunc(data);
}
isc_mem_put(hp->mctx, hp->rl[i]->list, isc__hp_max_retired * sizeof(uintptr_t));
isc_mem_put(hp->mctx, hp->rl[i], sizeof(*hp->rl[0]));
}
isc_mem_put(hp->mctx, hp->hp, isc__hp_max_threads * sizeof(hp->hp[0]));
isc_mem_put(hp->mctx, hp->rl, isc__hp_max_threads * sizeof(hp->rl[0]));
isc_mem_putanddetach(&hp->mctx, hp, sizeof(*hp));
}
......@@ -172,7 +185,7 @@ isc_hp_protect_release(isc_hp_t *hp, int ihp, atomic_uintptr_t ptr) {
void
isc_hp_retire(isc_hp_t *hp, uintptr_t ptr) {
hp->rl[tid()]->list[hp->rl[tid()]->size++] = ptr;
INSIST(hp->rl[tid()]->size < MAX_RETIRED);
INSIST(hp->rl[tid()]->size < isc__hp_max_retired);
if (hp->rl[tid()]->size < HP_THRESHOLD_R) {
return;
......@@ -182,7 +195,7 @@ isc_hp_retire(isc_hp_t *hp, uintptr_t ptr) {
uintptr_t obj = hp->rl[tid()]->list[iret];
bool can_delete = true;
for (int itid = 0;
itid < HP_MAX_THREADS && can_delete;
itid < isc__hp_max_threads && can_delete;
itid++)
{
for (int ihp = hp->max_hps-1; ihp >= 0; ihp--) {
......
......@@ -64,6 +64,13 @@
typedef void
(isc_hp_deletefunc_t)(void *);
void
isc_hp_init(int max_threads);
/*%<
* Initialize hazard pointer constants - isc__hp_max_threads. If more threads
* will try to access hp it will assert.
*/
isc_hp_t *
isc_hp_new(isc_mem_t *mctx, size_t max_hps, isc_hp_deletefunc_t *deletefunc);
/*%<
......
......@@ -248,6 +248,7 @@ isc_hex_tobuffer
isc_hex_totext
isc_hp_clear
isc_hp_destroy
isc_hp_init
isc_hp_protect
isc_hp_protect_ptr
isc_hp_protect_release
......
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