From: Witold Kręcicki Date: Thu, 12 Dec 2019 22:41:57 +0000 (+0100) Subject: Make hazard pointers max_threads configurable at runtime. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e83951144b40588e46c3d9584b208d6dcb538782;p=thirdparty%2Fbind9.git 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. --- diff --git a/bin/named/main.c b/bin/named/main.c index f1c14c511d1..c0b74953262 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -892,6 +893,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__, diff --git a/lib/isc/hp.c b/lib/isc/hp.c index 4bdd23c2847..659fb9d8dea 100644 --- a/lib/isc/hp.c +++ b/lib/isc/hp.c @@ -53,13 +53,13 @@ #include #include -#define HP_MAX_THREADS 128 +static int isc__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; #define TID_UNKNOWN -1 @@ -69,14 +69,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 +84,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 +111,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 +122,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 +130,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 +138,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 +184,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 +194,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--) { diff --git a/lib/isc/include/isc/hp.h b/lib/isc/include/isc/hp.h index 678c5f8b28d..dba0a648362 100644 --- a/lib/isc/include/isc/hp.h +++ b/lib/isc/include/isc/hp.h @@ -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); /*%<