Skip to content

Commit b67cffc

Browse files
Frederic Weisbeckerfbq
authored andcommitted
rcu/exp: Handle parallel exp gp kworkers affinity
Affine the parallel expedited gp kworkers to their respective RCU node in order to make them close to the cache their are playing with. This reuses the boost kthreads machinery that probe into CPU hotplug operations such that the kthreads become/stay affine to their respective node as soon/long as they contain online CPUs. Otherwise and if the current CPU going down was the last online on the leaf node, the related kthread is affine to the housekeeping CPUs. In the long run, this affinity VS CPU hotplug operation game should probably be implemented at the generic kthread level. Signed-off-by: Frederic Weisbecker <frederic@kernel.org> Reviewed-by: Paul E. McKenney <paulmck@kernel.org> [boqun: s/* rcu_boost_task/*rcu_boost_task as reported by checkpatch] Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
1 parent 8e5e621 commit b67cffc

File tree

2 files changed

+78
-43
lines changed

2 files changed

+78
-43
lines changed

kernel/rcu/tree.c

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ static int rcu_scheduler_fully_active __read_mostly;
145145

146146
static void rcu_report_qs_rnp(unsigned long mask, struct rcu_node *rnp,
147147
unsigned long gps, unsigned long flags);
148-
static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu);
148+
static struct task_struct *rcu_boost_task(struct rcu_node *rnp);
149149
static void invoke_rcu_core(void);
150150
static void rcu_report_exp_rdp(struct rcu_data *rdp);
151151
static void sync_sched_exp_online_cleanup(int cpu);
@@ -4417,6 +4417,16 @@ static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
44174417
sched_setscheduler_nocheck(kworker->task, SCHED_FIFO, &param);
44184418
}
44194419

4420+
static struct task_struct *rcu_exp_par_gp_task(struct rcu_node *rnp)
4421+
{
4422+
struct kthread_worker *kworker = READ_ONCE(rnp->exp_kworker);
4423+
4424+
if (!kworker)
4425+
return NULL;
4426+
4427+
return kworker->task;
4428+
}
4429+
44204430
static void __init rcu_start_exp_gp_kworker(void)
44214431
{
44224432
const char *name = "rcu_exp_gp_kthread_worker";
@@ -4441,6 +4451,11 @@ static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
44414451
{
44424452
}
44434453

4454+
static struct task_struct *rcu_exp_par_gp_task(struct rcu_node *rnp)
4455+
{
4456+
return NULL;
4457+
}
4458+
44444459
static void __init rcu_start_exp_gp_kworker(void)
44454460
{
44464461
}
@@ -4519,13 +4534,67 @@ int rcutree_prepare_cpu(unsigned int cpu)
45194534
}
45204535

45214536
/*
4522-
* Update RCU priority boot kthread affinity for CPU-hotplug changes.
4537+
* Update kthreads affinity during CPU-hotplug changes.
4538+
*
4539+
* Set the per-rcu_node kthread's affinity to cover all CPUs that are
4540+
* served by the rcu_node in question. The CPU hotplug lock is still
4541+
* held, so the value of rnp->qsmaskinit will be stable.
4542+
*
4543+
* We don't include outgoingcpu in the affinity set, use -1 if there is
4544+
* no outgoing CPU. If there are no CPUs left in the affinity set,
4545+
* this function allows the kthread to execute on any CPU.
4546+
*
4547+
* Any future concurrent calls are serialized via ->kthread_mutex.
45234548
*/
4524-
static void rcutree_affinity_setting(unsigned int cpu, int outgoing)
4549+
static void rcutree_affinity_setting(unsigned int cpu, int outgoingcpu)
45254550
{
4526-
struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
4551+
cpumask_var_t cm;
4552+
unsigned long mask;
4553+
struct rcu_data *rdp;
4554+
struct rcu_node *rnp;
4555+
struct task_struct *task_boost, *task_exp;
4556+
4557+
if (!IS_ENABLED(CONFIG_RCU_EXP_KTHREAD) && !IS_ENABLED(CONFIG_RCU_BOOST))
4558+
return;
4559+
4560+
rdp = per_cpu_ptr(&rcu_data, cpu);
4561+
rnp = rdp->mynode;
4562+
4563+
task_boost = rcu_boost_task(rnp);
4564+
task_exp = rcu_exp_par_gp_task(rnp);
4565+
4566+
/*
4567+
* If CPU is the boot one, those tasks are created later from early
4568+
* initcall since kthreadd must be created first.
4569+
*/
4570+
if (!task_boost && !task_exp)
4571+
return;
4572+
4573+
if (!zalloc_cpumask_var(&cm, GFP_KERNEL))
4574+
return;
4575+
4576+
mutex_lock(&rnp->kthread_mutex);
4577+
mask = rcu_rnp_online_cpus(rnp);
4578+
for_each_leaf_node_possible_cpu(rnp, cpu)
4579+
if ((mask & leaf_node_cpu_bit(rnp, cpu)) &&
4580+
cpu != outgoingcpu)
4581+
cpumask_set_cpu(cpu, cm);
4582+
cpumask_and(cm, cm, housekeeping_cpumask(HK_TYPE_RCU));
4583+
if (cpumask_empty(cm)) {
4584+
cpumask_copy(cm, housekeeping_cpumask(HK_TYPE_RCU));
4585+
if (outgoingcpu >= 0)
4586+
cpumask_clear_cpu(outgoingcpu, cm);
4587+
}
4588+
4589+
if (task_exp)
4590+
set_cpus_allowed_ptr(task_exp, cm);
4591+
4592+
if (task_boost)
4593+
set_cpus_allowed_ptr(task_boost, cm);
4594+
4595+
mutex_unlock(&rnp->kthread_mutex);
45274596

4528-
rcu_boost_kthread_setaffinity(rdp->mynode, outgoing);
4597+
free_cpumask_var(cm);
45294598
}
45304599

45314600
/*

kernel/rcu/tree_plugin.h

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,43 +1211,9 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
12111211
wake_up_process(t); /* get to TASK_INTERRUPTIBLE quickly. */
12121212
}
12131213

1214-
/*
1215-
* Set the per-rcu_node kthread's affinity to cover all CPUs that are
1216-
* served by the rcu_node in question. The CPU hotplug lock is still
1217-
* held, so the value of rnp->qsmaskinit will be stable.
1218-
*
1219-
* We don't include outgoingcpu in the affinity set, use -1 if there is
1220-
* no outgoing CPU. If there are no CPUs left in the affinity set,
1221-
* this function allows the kthread to execute on any CPU.
1222-
*
1223-
* Any future concurrent calls are serialized via ->kthread_mutex.
1224-
*/
1225-
static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
1214+
static struct task_struct *rcu_boost_task(struct rcu_node *rnp)
12261215
{
1227-
struct task_struct *t = rnp->boost_kthread_task;
1228-
unsigned long mask;
1229-
cpumask_var_t cm;
1230-
int cpu;
1231-
1232-
if (!t)
1233-
return;
1234-
if (!zalloc_cpumask_var(&cm, GFP_KERNEL))
1235-
return;
1236-
mutex_lock(&rnp->kthread_mutex);
1237-
mask = rcu_rnp_online_cpus(rnp);
1238-
for_each_leaf_node_possible_cpu(rnp, cpu)
1239-
if ((mask & leaf_node_cpu_bit(rnp, cpu)) &&
1240-
cpu != outgoingcpu)
1241-
cpumask_set_cpu(cpu, cm);
1242-
cpumask_and(cm, cm, housekeeping_cpumask(HK_TYPE_RCU));
1243-
if (cpumask_empty(cm)) {
1244-
cpumask_copy(cm, housekeeping_cpumask(HK_TYPE_RCU));
1245-
if (outgoingcpu >= 0)
1246-
cpumask_clear_cpu(outgoingcpu, cm);
1247-
}
1248-
set_cpus_allowed_ptr(t, cm);
1249-
mutex_unlock(&rnp->kthread_mutex);
1250-
free_cpumask_var(cm);
1216+
return READ_ONCE(rnp->boost_kthread_task);
12511217
}
12521218

12531219
#else /* #ifdef CONFIG_RCU_BOOST */
@@ -1266,10 +1232,10 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
12661232
{
12671233
}
12681234

1269-
static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
1235+
static struct task_struct *rcu_boost_task(struct rcu_node *rnp)
12701236
{
1237+
return NULL;
12711238
}
1272-
12731239
#endif /* #else #ifdef CONFIG_RCU_BOOST */
12741240

12751241
/*

0 commit comments

Comments
 (0)