vlapic: Schedule callouts on the local CPU

The virtual LAPIC driver uses callouts to implement the LAPIC timer.
Callouts are armed using callout_reset_sbt(), which currently puts
everything on CPU 0.  On systems running many bhyve VMs this results in
a large amount of contention for CPU 0's callout lock.

Modify vlapic to schedule callouts on the local CPU instead.  This
allows timer interrupts to be scheduled more evenly among CPUs where
bhyve is running.

Reviewed by:	grehan, jhb
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D32559
This commit is contained in:
Mark Johnston 2021-10-19 20:50:06 -04:00
parent bd49c454ca
commit 4c812fe61b

View File

@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$");
#define VLAPIC_BUS_FREQ (128 * 1024 * 1024)
static void vlapic_set_error(struct vlapic *, uint32_t, bool);
static void vlapic_callout_handler(void *arg);
static __inline uint32_t
vlapic_get_id(struct vlapic *vlapic)
@ -710,6 +711,13 @@ vlapic_trigger_lvt(struct vlapic *vlapic, int vector)
return (0);
}
static void
vlapic_callout_reset(struct vlapic *vlapic, sbintime_t t)
{
callout_reset_sbt_curcpu(&vlapic->callout, t, 0,
vlapic_callout_handler, vlapic, 0);
}
static void
vlapic_callout_handler(void *arg)
{
@ -765,8 +773,7 @@ vlapic_callout_handler(void *arg)
}
bintime_add(&vlapic->timer_fire_bt, &vlapic->timer_period_bt);
callout_reset_sbt(&vlapic->callout, rem_sbt, 0,
vlapic_callout_handler, vlapic, 0);
vlapic_callout_reset(vlapic, rem_sbt);
}
done:
VLAPIC_TIMER_UNLOCK(vlapic);
@ -792,8 +799,7 @@ vlapic_icrtmr_write_handler(struct vlapic *vlapic)
bintime_add(&vlapic->timer_fire_bt, &vlapic->timer_period_bt);
sbt = bttosbt(vlapic->timer_period_bt);
callout_reset_sbt(&vlapic->callout, sbt, 0,
vlapic_callout_handler, vlapic, 0);
vlapic_callout_reset(vlapic, sbt);
} else
callout_stop(&vlapic->callout);
@ -1667,8 +1673,7 @@ vlapic_reset_callout(struct vlapic *vlapic, uint32_t ccr)
bintime_add(&vlapic->timer_fire_bt, &bt);
sbt = bttosbt(bt);
callout_reset_sbt(&vlapic->callout, sbt, 0,
vlapic_callout_handler, vlapic, 0);
vlapic_callout_reset(vlapic, sbt);
} else {
/* even if the CCR was 0, periodic timers should be reset */
if (vlapic_periodic_timer(vlapic)) {
@ -1678,8 +1683,7 @@ vlapic_reset_callout(struct vlapic *vlapic, uint32_t ccr)
sbt = bttosbt(vlapic->timer_period_bt);
callout_stop(&vlapic->callout);
callout_reset_sbt(&vlapic->callout, sbt, 0,
vlapic_callout_handler, vlapic, 0);
vlapic_callout_reset(vlapic, sbt);
}
}