diff options
author | Maria Matejka <mq@ucw.cz> | 2023-01-19 10:49:47 +0100 |
---|---|---|
committer | Maria Matejka <mq@ucw.cz> | 2023-01-19 11:13:50 +0100 |
commit | 84c298465f6360a8694d4837f3420961ea321fa5 (patch) | |
tree | 273455bf0e6f1b7a1be8956692feacbf6b3484a3 /lib | |
parent | 4d8d81f144e72fe2e182d7569087f2a8c8c5b938 (diff) |
Decoupling loops from threads to allow fixed thread count
On large configurations, too many threads would spawn with one thread
per loop. Therefore, threads may now run multiple loops at once. The
thread count is configurable and may be changed during run. All threads
are spawned on startup.
This change helps with memory bloating. BIRD filters need large
temporary memory blocks to store their stack and also memory management
keeps its hot page storage per-thread.
Known bugs:
* Thread autobalancing is not yet implemented.
* Low latency loops are executed together with standard loops.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/event.c | 2 | ||||
-rw-r--r-- | lib/event.h | 1 | ||||
-rw-r--r-- | lib/locking.h | 4 | ||||
-rw-r--r-- | lib/rcu.c | 24 | ||||
-rw-r--r-- | lib/rcu.h | 16 |
5 files changed, 25 insertions, 22 deletions
diff --git a/lib/event.c b/lib/event.c index 68ee4c06..55e7f446 100644 --- a/lib/event.c +++ b/lib/event.c @@ -261,7 +261,7 @@ ev_send(event_list *l, event *e) memory_order_acq_rel, memory_order_acquire)); edlog(l, e, next, 4, EDL_SEND); - birdloop_ping(l->loop); + if (l->loop) birdloop_ping(l->loop); } void io_log_event(void *hook, void *data); diff --git a/lib/event.h b/lib/event.h index 0bef737a..6fd9f31c 100644 --- a/lib/event.h +++ b/lib/event.h @@ -11,7 +11,6 @@ #include "lib/resource.h" #include "lib/locking.h" -#include "lib/rcu.h" #include <stdatomic.h> diff --git a/lib/locking.h b/lib/locking.h index 498afdc8..7e014bd0 100644 --- a/lib/locking.h +++ b/lib/locking.h @@ -14,6 +14,7 @@ struct domain_generic; /* Here define the global lock order; first to last. */ struct lock_order { struct domain_generic *the_bird; + struct domain_generic *control; struct domain_generic *proto; struct domain_generic *service; struct domain_generic *rtable; @@ -34,6 +35,9 @@ struct domain_generic *domain_new(const char *name, uint order); #define DOMAIN_FREE(type, d) domain_free((d).type) void domain_free(struct domain_generic *); +#define DOMAIN_NAME(type, d) domain_name((d).type) +const char *domain_name(struct domain_generic *); + #define DOMAIN_NULL(type) (DOMAIN(type)) {} #define LOCK_DOMAIN(type, d) do_lock(((d).type), &(locking_stack.type)) @@ -17,11 +17,11 @@ #include "lib/locking.h" _Atomic uint rcu_gp_ctl = RCU_NEST_CNT; -_Thread_local struct rcu_birdloop *this_rcu_birdloop = NULL; +_Thread_local struct rcu_thread *this_rcu_thread = NULL; -static list rcu_birdloop_list; +static list rcu_thread_list; -static struct rcu_birdloop main_rcu_birdloop; +static struct rcu_thread main_rcu_thread; DEFINE_DOMAIN(resource); static DOMAIN(resource) rcu_domain; @@ -37,8 +37,8 @@ static void update_counter_and_wait(void) { atomic_fetch_xor(&rcu_gp_ctl, RCU_GP_PHASE); - struct rcu_birdloop *rc; - WALK_LIST(rc, rcu_birdloop_list) + struct rcu_thread *rc; + WALK_LIST(rc, rcu_thread_list) while (rcu_gp_ongoing(&rc->ctl)) birdloop_yield(); } @@ -53,19 +53,19 @@ synchronize_rcu(void) } void -rcu_birdloop_start(struct rcu_birdloop *rc) +rcu_thread_start(struct rcu_thread *rc) { LOCK_DOMAIN(resource, rcu_domain); - add_tail(&rcu_birdloop_list, &rc->n); - this_rcu_birdloop = rc; + add_tail(&rcu_thread_list, &rc->n); + this_rcu_thread = rc; UNLOCK_DOMAIN(resource, rcu_domain); } void -rcu_birdloop_stop(struct rcu_birdloop *rc) +rcu_thread_stop(struct rcu_thread *rc) { LOCK_DOMAIN(resource, rcu_domain); - this_rcu_birdloop = NULL; + this_rcu_thread = NULL; rem_node(&rc->n); UNLOCK_DOMAIN(resource, rcu_domain); } @@ -74,6 +74,6 @@ void rcu_init(void) { rcu_domain = DOMAIN_NEW(resource, "Read-Copy-Update"); - init_list(&rcu_birdloop_list); - rcu_birdloop_start(&main_rcu_birdloop); + init_list(&rcu_thread_list); + rcu_thread_start(&main_rcu_thread); } @@ -21,33 +21,33 @@ extern _Atomic uint rcu_gp_ctl; -struct rcu_birdloop { +struct rcu_thread { node n; _Atomic uint ctl; }; -extern _Thread_local struct rcu_birdloop *this_rcu_birdloop; +extern _Thread_local struct rcu_thread *this_rcu_thread; static inline void rcu_read_lock(void) { - uint cmp = atomic_load_explicit(&this_rcu_birdloop->ctl, memory_order_acquire); + uint cmp = atomic_load_explicit(&this_rcu_thread->ctl, memory_order_acquire); if (cmp & RCU_NEST_MASK) - atomic_store_explicit(&this_rcu_birdloop->ctl, cmp + RCU_NEST_CNT, memory_order_relaxed); + atomic_store_explicit(&this_rcu_thread->ctl, cmp + RCU_NEST_CNT, memory_order_relaxed); else - atomic_store(&this_rcu_birdloop->ctl, atomic_load_explicit(&rcu_gp_ctl, memory_order_acquire)); + atomic_store(&this_rcu_thread->ctl, atomic_load_explicit(&rcu_gp_ctl, memory_order_acquire)); } static inline void rcu_read_unlock(void) { - atomic_fetch_sub(&this_rcu_birdloop->ctl, RCU_NEST_CNT); + atomic_fetch_sub(&this_rcu_thread->ctl, RCU_NEST_CNT); } void synchronize_rcu(void); /* Registering and unregistering a birdloop. To be called from birdloop implementation */ -void rcu_birdloop_start(struct rcu_birdloop *); -void rcu_birdloop_stop(struct rcu_birdloop *); +void rcu_thread_start(struct rcu_thread *); +void rcu_thread_stop(struct rcu_thread *); /* Run this from resource init */ void rcu_init(void); |