Skip to content

Commit ecf08da

Browse files
Anthoine Bourgeoisrkrcmar
authored andcommitted
KVM: x86: remove APIC Timer periodic/oneshot spikes
Since the commit "8003c9ae204e: add APIC Timer periodic/oneshot mode VMX preemption timer support", a Windows 10 guest has some erratic timer spikes. Here the results on a 150000 times 1ms timer without any load: Before 8003c9a | After 8003c9a Max 1834us | 86000us Mean 1100us | 1021us Deviation 59us | 149us Here the results on a 150000 times 1ms timer with a cpu-z stress test: Before 8003c9a | After 8003c9a Max 32000us | 140000us Mean 1006us | 1997us Deviation 140us | 11095us The root cause of the problem is starting hrtimer with an expiry time already in the past can take more than 20 milliseconds to trigger the timer function. It can be solved by forward such past timers immediately, rather than submitting them to hrtimer_start(). In case the timer is periodic, update the target expiration and call hrtimer_start with it. v2: Check if the tsc deadline is already expired. Thank you Mika. v3: Execute the past timers immediately rather than submitting them to hrtimer_start(). v4: Rearm the periodic timer with advance_periodic_target_expiration() a simpler version of set_target_expiration(). Thank you Paolo. Cc: Mika Penttilä <[email protected]> Cc: Wanpeng Li <[email protected]> Cc: Paolo Bonzini <[email protected]> Cc: [email protected] Signed-off-by: Anthoine Bourgeois <[email protected]> 8003c9a ("KVM: LAPIC: add APIC Timer periodic/oneshot mode VMX preemption timer support") Signed-off-by: Radim Krčmář <[email protected]>
1 parent f3351c6 commit ecf08da

File tree

1 file changed

+20
-17
lines changed

1 file changed

+20
-17
lines changed

arch/x86/kvm/lapic.c

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,23 +1463,6 @@ static void start_sw_tscdeadline(struct kvm_lapic *apic)
14631463
local_irq_restore(flags);
14641464
}
14651465

1466-
static void start_sw_period(struct kvm_lapic *apic)
1467-
{
1468-
if (!apic->lapic_timer.period)
1469-
return;
1470-
1471-
if (apic_lvtt_oneshot(apic) &&
1472-
ktime_after(ktime_get(),
1473-
apic->lapic_timer.target_expiration)) {
1474-
apic_timer_expired(apic);
1475-
return;
1476-
}
1477-
1478-
hrtimer_start(&apic->lapic_timer.timer,
1479-
apic->lapic_timer.target_expiration,
1480-
HRTIMER_MODE_ABS_PINNED);
1481-
}
1482-
14831466
static void update_target_expiration(struct kvm_lapic *apic, uint32_t old_divisor)
14841467
{
14851468
ktime_t now, remaining;
@@ -1546,6 +1529,26 @@ static void advance_periodic_target_expiration(struct kvm_lapic *apic)
15461529
apic->lapic_timer.period);
15471530
}
15481531

1532+
static void start_sw_period(struct kvm_lapic *apic)
1533+
{
1534+
if (!apic->lapic_timer.period)
1535+
return;
1536+
1537+
if (ktime_after(ktime_get(),
1538+
apic->lapic_timer.target_expiration)) {
1539+
apic_timer_expired(apic);
1540+
1541+
if (apic_lvtt_oneshot(apic))
1542+
return;
1543+
1544+
advance_periodic_target_expiration(apic);
1545+
}
1546+
1547+
hrtimer_start(&apic->lapic_timer.timer,
1548+
apic->lapic_timer.target_expiration,
1549+
HRTIMER_MODE_ABS_PINNED);
1550+
}
1551+
15491552
bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu)
15501553
{
15511554
if (!lapic_in_kernel(vcpu))

0 commit comments

Comments
 (0)