Skip to content

Commit 8e5e621

Browse files
Frederic Weisbeckerfbq
authored andcommitted
rcu/exp: Make parallel exp gp kworker per rcu node
When CONFIG_RCU_EXP_KTHREAD=n, the expedited grace period per node initialization is performed in parallel via workqueues (one work per node). However in CONFIG_RCU_EXP_KTHREAD=y, this per node initialization is performed by a single kworker serializing each node initialization (one work for all nodes). The second part is certainly less scalable and efficient beyond a single leaf node. To improve this, expand this single kworker into per-node kworkers. This new layout is eventually intended to remove the workqueues based implementation since it will essentially now become duplicate code. Signed-off-by: Frederic Weisbecker <frederic@kernel.org> Reviewed-by: Paul E. McKenney <paulmck@kernel.org> Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
1 parent c19e5d3 commit 8e5e621

File tree

5 files changed

+52
-33
lines changed

5 files changed

+52
-33
lines changed

kernel/rcu/rcu.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,6 @@ void rcu_force_quiescent_state(void);
625625
extern struct workqueue_struct *rcu_gp_wq;
626626
#ifdef CONFIG_RCU_EXP_KTHREAD
627627
extern struct kthread_worker *rcu_exp_gp_kworker;
628-
extern struct kthread_worker *rcu_exp_par_gp_kworker;
629628
#else /* !CONFIG_RCU_EXP_KTHREAD */
630629
extern struct workqueue_struct *rcu_par_gp_wq;
631630
#endif /* CONFIG_RCU_EXP_KTHREAD */

kernel/rcu/tree.c

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4396,33 +4396,39 @@ rcu_boot_init_percpu_data(int cpu)
43964396

43974397
#ifdef CONFIG_RCU_EXP_KTHREAD
43984398
struct kthread_worker *rcu_exp_gp_kworker;
4399-
struct kthread_worker *rcu_exp_par_gp_kworker;
44004399

4401-
static void __init rcu_start_exp_gp_kworkers(void)
4400+
static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
44024401
{
4403-
const char *par_gp_kworker_name = "rcu_exp_par_gp_kthread_worker";
4404-
const char *gp_kworker_name = "rcu_exp_gp_kthread_worker";
4402+
struct kthread_worker *kworker;
4403+
const char *name = "rcu_exp_par_gp_kthread_worker/%d";
44054404
struct sched_param param = { .sched_priority = kthread_prio };
4405+
int rnp_index = rnp - rcu_get_root();
44064406

4407-
rcu_exp_gp_kworker = kthread_create_worker(0, gp_kworker_name);
4408-
if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) {
4409-
pr_err("Failed to create %s!\n", gp_kworker_name);
4410-
rcu_exp_gp_kworker = NULL;
4407+
if (rnp->exp_kworker)
4408+
return;
4409+
4410+
kworker = kthread_create_worker(0, name, rnp_index);
4411+
if (IS_ERR_OR_NULL(kworker)) {
4412+
pr_err("Failed to create par gp kworker on %d/%d\n",
4413+
rnp->grplo, rnp->grphi);
44114414
return;
44124415
}
4416+
WRITE_ONCE(rnp->exp_kworker, kworker);
4417+
sched_setscheduler_nocheck(kworker->task, SCHED_FIFO, &param);
4418+
}
44134419

4414-
rcu_exp_par_gp_kworker = kthread_create_worker(0, par_gp_kworker_name);
4415-
if (IS_ERR_OR_NULL(rcu_exp_par_gp_kworker)) {
4416-
pr_err("Failed to create %s!\n", par_gp_kworker_name);
4417-
rcu_exp_par_gp_kworker = NULL;
4418-
kthread_destroy_worker(rcu_exp_gp_kworker);
4420+
static void __init rcu_start_exp_gp_kworker(void)
4421+
{
4422+
const char *name = "rcu_exp_gp_kthread_worker";
4423+
struct sched_param param = { .sched_priority = kthread_prio };
4424+
4425+
rcu_exp_gp_kworker = kthread_create_worker(0, name);
4426+
if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) {
4427+
pr_err("Failed to create %s!\n", name);
44194428
rcu_exp_gp_kworker = NULL;
44204429
return;
44214430
}
4422-
44234431
sched_setscheduler_nocheck(rcu_exp_gp_kworker->task, SCHED_FIFO, &param);
4424-
sched_setscheduler_nocheck(rcu_exp_par_gp_kworker->task, SCHED_FIFO,
4425-
&param);
44264432
}
44274433

44284434
static inline void rcu_alloc_par_gp_wq(void)
@@ -4431,7 +4437,11 @@ static inline void rcu_alloc_par_gp_wq(void)
44314437
#else /* !CONFIG_RCU_EXP_KTHREAD */
44324438
struct workqueue_struct *rcu_par_gp_wq;
44334439

4434-
static void __init rcu_start_exp_gp_kworkers(void)
4440+
static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
4441+
{
4442+
}
4443+
4444+
static void __init rcu_start_exp_gp_kworker(void)
44354445
{
44364446
}
44374447

@@ -4442,6 +4452,17 @@ static inline void rcu_alloc_par_gp_wq(void)
44424452
}
44434453
#endif /* CONFIG_RCU_EXP_KTHREAD */
44444454

4455+
static void rcu_spawn_rnp_kthreads(struct rcu_node *rnp)
4456+
{
4457+
if ((IS_ENABLED(CONFIG_RCU_EXP_KTHREAD) ||
4458+
IS_ENABLED(CONFIG_RCU_BOOST)) && rcu_scheduler_fully_active) {
4459+
mutex_lock(&rnp->kthread_mutex);
4460+
rcu_spawn_one_boost_kthread(rnp);
4461+
rcu_spawn_exp_par_gp_kworker(rnp);
4462+
mutex_unlock(&rnp->kthread_mutex);
4463+
}
4464+
}
4465+
44454466
/*
44464467
* Invoked early in the CPU-online process, when pretty much all services
44474468
* are available. The incoming CPU is not present.
@@ -4490,7 +4511,7 @@ int rcutree_prepare_cpu(unsigned int cpu)
44904511
rdp->rcu_iw_gp_seq = rdp->gp_seq - 1;
44914512
trace_rcu_grace_period(rcu_state.name, rdp->gp_seq, TPS("cpuonl"));
44924513
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
4493-
rcu_spawn_one_boost_kthread(rnp);
4514+
rcu_spawn_rnp_kthreads(rnp);
44944515
rcu_spawn_cpu_nocb_kthread(cpu);
44954516
WRITE_ONCE(rcu_state.n_online_cpus, rcu_state.n_online_cpus + 1);
44964517

@@ -4812,10 +4833,10 @@ static int __init rcu_spawn_gp_kthread(void)
48124833
* due to rcu_scheduler_fully_active.
48134834
*/
48144835
rcu_spawn_cpu_nocb_kthread(smp_processor_id());
4815-
rcu_spawn_one_boost_kthread(rdp->mynode);
4836+
rcu_spawn_rnp_kthreads(rdp->mynode);
48164837
rcu_spawn_core_kthreads();
48174838
/* Create kthread worker for expedited GPs */
4818-
rcu_start_exp_gp_kworkers();
4839+
rcu_start_exp_gp_kworker();
48194840
return 0;
48204841
}
48214842
early_initcall(rcu_spawn_gp_kthread);

kernel/rcu/tree.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ struct rcu_node {
7272
/* Online CPUs for next expedited GP. */
7373
/* Any CPU that has ever been online will */
7474
/* have its bit set. */
75+
struct kthread_worker *exp_kworker;
76+
/* Workers performing per node expedited GP */
77+
/* initialization. */
7578
unsigned long cbovldmask;
7679
/* CPUs experiencing callback overload. */
7780
unsigned long ffmask; /* Fully functional CPUs. */

kernel/rcu/tree_exp.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,9 @@ static inline bool rcu_exp_worker_started(void)
432432
return !!READ_ONCE(rcu_exp_gp_kworker);
433433
}
434434

435-
static inline bool rcu_exp_par_worker_started(void)
435+
static inline bool rcu_exp_par_worker_started(struct rcu_node *rnp)
436436
{
437-
return !!READ_ONCE(rcu_exp_par_gp_kworker);
437+
return !!READ_ONCE(rnp->exp_kworker);
438438
}
439439

440440
static inline void sync_rcu_exp_select_cpus_queue_work(struct rcu_node *rnp)
@@ -445,7 +445,7 @@ static inline void sync_rcu_exp_select_cpus_queue_work(struct rcu_node *rnp)
445445
* another work item on the same kthread worker can result in
446446
* deadlock.
447447
*/
448-
kthread_queue_work(rcu_exp_par_gp_kworker, &rnp->rew.rew_work);
448+
kthread_queue_work(READ_ONCE(rnp->exp_kworker), &rnp->rew.rew_work);
449449
}
450450

451451
static inline void sync_rcu_exp_select_cpus_flush_work(struct rcu_node *rnp)
@@ -487,7 +487,7 @@ static inline bool rcu_exp_worker_started(void)
487487
return !!READ_ONCE(rcu_gp_wq);
488488
}
489489

490-
static inline bool rcu_exp_par_worker_started(void)
490+
static inline bool rcu_exp_par_worker_started(struct rcu_node *rnp)
491491
{
492492
return !!READ_ONCE(rcu_par_gp_wq);
493493
}
@@ -550,7 +550,7 @@ static void sync_rcu_exp_select_cpus(void)
550550
rnp->exp_need_flush = false;
551551
if (!READ_ONCE(rnp->expmask))
552552
continue; /* Avoid early boot non-existent wq. */
553-
if (!rcu_exp_par_worker_started() ||
553+
if (!rcu_exp_par_worker_started(rnp) ||
554554
rcu_scheduler_active != RCU_SCHEDULER_RUNNING ||
555555
rcu_is_last_leaf_node(rnp)) {
556556
/* No worker started yet or last leaf, do direct call. */

kernel/rcu/tree_plugin.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,24 +1195,20 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
11951195
struct sched_param sp;
11961196
struct task_struct *t;
11971197

1198-
mutex_lock(&rnp->kthread_mutex);
1199-
if (rnp->boost_kthread_task || !rcu_scheduler_fully_active)
1200-
goto out;
1198+
if (rnp->boost_kthread_task)
1199+
return;
12011200

12021201
t = kthread_create(rcu_boost_kthread, (void *)rnp,
12031202
"rcub/%d", rnp_index);
12041203
if (WARN_ON_ONCE(IS_ERR(t)))
1205-
goto out;
1204+
return;
12061205

12071206
raw_spin_lock_irqsave_rcu_node(rnp, flags);
12081207
rnp->boost_kthread_task = t;
12091208
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
12101209
sp.sched_priority = kthread_prio;
12111210
sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
12121211
wake_up_process(t); /* get to TASK_INTERRUPTIBLE quickly. */
1213-
1214-
out:
1215-
mutex_unlock(&rnp->kthread_mutex);
12161212
}
12171213

12181214
/*

0 commit comments

Comments
 (0)