Skip to content

Commit 64b6d1d

Browse files
Marc ZyngierKAGA-KOKO
authored andcommitted
genirq: Get rid of global lock in irq_do_set_affinity()
Kunkun Jiang reports that for a workload involving the simultaneous startup of a large number of VMs (for a total of about 200 vcpus), a lot of CPU time gets spent on spinning on the tmp_mask_lock that exists as a static raw spinlock in irq_do_set_affinity(). This lock protects a global cpumask (tmp_mask) that is used as a temporary variable to compute the resulting affinity. While this is triggered by KVM issuing a irq_set_affinity() call each time a vcpu is about to execute, it is obvious that having a single global resource is not very scalable. Since a cpumask can be a fairly large structure on systems with a high core count, a stack allocation is not really appropriate. Instead, turn the global cpumask into a per-CPU variable, removing the need for locking altogether as the code is executed with preemption and interrupts disabled. [ tglx: Moved the per CPU variable declaration outside of the function ] Reported-by: Kunkun Jiang <[email protected]> Suggested-by: Thomas Gleixner <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Tested-by: Kunkun Jiang <[email protected]> Link: https://lore.kernel.org/all/[email protected] Link: https://lore.kernel.org/all/[email protected]
1 parent 17e28a9 commit 64b6d1d

File tree

1 file changed

+9
-12
lines changed

1 file changed

+9
-12
lines changed

kernel/irq/manage.c

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -218,21 +218,20 @@ static void irq_validate_effective_affinity(struct irq_data *data)
218218
static inline void irq_validate_effective_affinity(struct irq_data *data) { }
219219
#endif
220220

221+
static DEFINE_PER_CPU(struct cpumask, __tmp_mask);
222+
221223
int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
222224
bool force)
223225
{
226+
struct cpumask *tmp_mask = this_cpu_ptr(&__tmp_mask);
224227
struct irq_desc *desc = irq_data_to_desc(data);
225228
struct irq_chip *chip = irq_data_get_irq_chip(data);
226229
const struct cpumask *prog_mask;
227230
int ret;
228231

229-
static DEFINE_RAW_SPINLOCK(tmp_mask_lock);
230-
static struct cpumask tmp_mask;
231-
232232
if (!chip || !chip->irq_set_affinity)
233233
return -EINVAL;
234234

235-
raw_spin_lock(&tmp_mask_lock);
236235
/*
237236
* If this is a managed interrupt and housekeeping is enabled on
238237
* it check whether the requested affinity mask intersects with
@@ -258,11 +257,11 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
258257

259258
hk_mask = housekeeping_cpumask(HK_TYPE_MANAGED_IRQ);
260259

261-
cpumask_and(&tmp_mask, mask, hk_mask);
262-
if (!cpumask_intersects(&tmp_mask, cpu_online_mask))
260+
cpumask_and(tmp_mask, mask, hk_mask);
261+
if (!cpumask_intersects(tmp_mask, cpu_online_mask))
263262
prog_mask = mask;
264263
else
265-
prog_mask = &tmp_mask;
264+
prog_mask = tmp_mask;
266265
} else {
267266
prog_mask = mask;
268267
}
@@ -272,16 +271,14 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
272271
* unless we are being asked to force the affinity (in which
273272
* case we do as we are told).
274273
*/
275-
cpumask_and(&tmp_mask, prog_mask, cpu_online_mask);
276-
if (!force && !cpumask_empty(&tmp_mask))
277-
ret = chip->irq_set_affinity(data, &tmp_mask, force);
274+
cpumask_and(tmp_mask, prog_mask, cpu_online_mask);
275+
if (!force && !cpumask_empty(tmp_mask))
276+
ret = chip->irq_set_affinity(data, tmp_mask, force);
278277
else if (force)
279278
ret = chip->irq_set_affinity(data, mask, force);
280279
else
281280
ret = -EINVAL;
282281

283-
raw_spin_unlock(&tmp_mask_lock);
284-
285282
switch (ret) {
286283
case IRQ_SET_MASK_OK:
287284
case IRQ_SET_MASK_OK_DONE:

0 commit comments

Comments
 (0)