diff options
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/kvm_main.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 0892b75eeedd..1e10ebe1a370 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -1579,6 +1579,43 @@ bool kvm_vcpu_yield_to(struct kvm_vcpu *target) | |||
1579 | } | 1579 | } |
1580 | EXPORT_SYMBOL_GPL(kvm_vcpu_yield_to); | 1580 | EXPORT_SYMBOL_GPL(kvm_vcpu_yield_to); |
1581 | 1581 | ||
1582 | #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT | ||
1583 | /* | ||
1584 | * Helper that checks whether a VCPU is eligible for directed yield. | ||
1585 | * Most eligible candidate to yield is decided by following heuristics: | ||
1586 | * | ||
1587 | * (a) VCPU which has not done pl-exit or cpu relax intercepted recently | ||
1588 | * (preempted lock holder), indicated by @in_spin_loop. | ||
1589 | * Set at the beiginning and cleared at the end of interception/PLE handler. | ||
1590 | * | ||
1591 | * (b) VCPU which has done pl-exit/ cpu relax intercepted but did not get | ||
1592 | * chance last time (mostly it has become eligible now since we have probably | ||
1593 | * yielded to lockholder in last iteration. This is done by toggling | ||
1594 | * @dy_eligible each time a VCPU checked for eligibility.) | ||
1595 | * | ||
1596 | * Yielding to a recently pl-exited/cpu relax intercepted VCPU before yielding | ||
1597 | * to preempted lock-holder could result in wrong VCPU selection and CPU | ||
1598 | * burning. Giving priority for a potential lock-holder increases lock | ||
1599 | * progress. | ||
1600 | * | ||
1601 | * Since algorithm is based on heuristics, accessing another VCPU data without | ||
1602 | * locking does not harm. It may result in trying to yield to same VCPU, fail | ||
1603 | * and continue with next VCPU and so on. | ||
1604 | */ | ||
1605 | bool kvm_vcpu_eligible_for_directed_yield(struct kvm_vcpu *vcpu) | ||
1606 | { | ||
1607 | bool eligible; | ||
1608 | |||
1609 | eligible = !vcpu->spin_loop.in_spin_loop || | ||
1610 | (vcpu->spin_loop.in_spin_loop && | ||
1611 | vcpu->spin_loop.dy_eligible); | ||
1612 | |||
1613 | if (vcpu->spin_loop.in_spin_loop) | ||
1614 | kvm_vcpu_set_dy_eligible(vcpu, !vcpu->spin_loop.dy_eligible); | ||
1615 | |||
1616 | return eligible; | ||
1617 | } | ||
1618 | #endif | ||
1582 | void kvm_vcpu_on_spin(struct kvm_vcpu *me) | 1619 | void kvm_vcpu_on_spin(struct kvm_vcpu *me) |
1583 | { | 1620 | { |
1584 | struct kvm *kvm = me->kvm; | 1621 | struct kvm *kvm = me->kvm; |
@@ -1607,6 +1644,8 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me) | |||
1607 | continue; | 1644 | continue; |
1608 | if (waitqueue_active(&vcpu->wq)) | 1645 | if (waitqueue_active(&vcpu->wq)) |
1609 | continue; | 1646 | continue; |
1647 | if (!kvm_vcpu_eligible_for_directed_yield(vcpu)) | ||
1648 | continue; | ||
1610 | if (kvm_vcpu_yield_to(vcpu)) { | 1649 | if (kvm_vcpu_yield_to(vcpu)) { |
1611 | kvm->last_boosted_vcpu = i; | 1650 | kvm->last_boosted_vcpu = i; |
1612 | yielded = 1; | 1651 | yielded = 1; |
@@ -1615,6 +1654,9 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me) | |||
1615 | } | 1654 | } |
1616 | } | 1655 | } |
1617 | kvm_vcpu_set_in_spin_loop(me, false); | 1656 | kvm_vcpu_set_in_spin_loop(me, false); |
1657 | |||
1658 | /* Ensure vcpu is not eligible during next spinloop */ | ||
1659 | kvm_vcpu_set_dy_eligible(me, false); | ||
1618 | } | 1660 | } |
1619 | EXPORT_SYMBOL_GPL(kvm_vcpu_on_spin); | 1661 | EXPORT_SYMBOL_GPL(kvm_vcpu_on_spin); |
1620 | 1662 | ||