From 493b6a9f33eb4ff7a2488f5c805586f1fd70f73a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Witold=20Kr=C4=99cicki?= Date: Thu, 12 Dec 2019 23:41:57 +0100 Subject: [PATCH] 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. --- bin/named/main.c | 7 +++++++ lib/isc/hp.c | 33 +++++++++++++++++++++++---------- lib/isc/include/isc/hp.h | 7 +++++++ lib/isc/win32/libisc.def.in | 1 + 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/bin/named/main.c b/bin/named/main.c index 9d8e1aeedc..1e00f016a4 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -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__, diff --git a/lib/isc/hp.c b/lib/isc/hp.c index 4bdd23c284..ca3a7af539 100644 --- a/lib/isc/hp.c +++ b/lib/isc/hp.c @@ -54,12 +54,13 @@ #include #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--) { diff --git a/lib/isc/include/isc/hp.h b/lib/isc/include/isc/hp.h index 678c5f8b28..dba0a64836 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); /*%< diff --git a/lib/isc/win32/libisc.def.in b/lib/isc/win32/libisc.def.in index 5d5b939ea9..07074ec6b3 100644 --- a/lib/isc/win32/libisc.def.in +++ b/lib/isc/win32/libisc.def.in @@ -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