|
@@ -66,9 +66,18 @@
|
|
MODULE_AUTHOR("Qumranet");
|
|
MODULE_AUTHOR("Qumranet");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
|
|
-static unsigned int halt_poll_ns;
|
|
|
|
|
|
+/* halt polling only reduces halt latency by 5-7 us, 500us is enough */
|
|
|
|
+static unsigned int halt_poll_ns = 500000;
|
|
module_param(halt_poll_ns, uint, S_IRUGO | S_IWUSR);
|
|
module_param(halt_poll_ns, uint, S_IRUGO | S_IWUSR);
|
|
|
|
|
|
|
|
+/* Default doubles per-vcpu halt_poll_ns. */
|
|
|
|
+static unsigned int halt_poll_ns_grow = 2;
|
|
|
|
+module_param(halt_poll_ns_grow, int, S_IRUGO);
|
|
|
|
+
|
|
|
|
+/* Default resets per-vcpu halt_poll_ns . */
|
|
|
|
+static unsigned int halt_poll_ns_shrink;
|
|
|
|
+module_param(halt_poll_ns_shrink, int, S_IRUGO);
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Ordering of locks:
|
|
* Ordering of locks:
|
|
*
|
|
*
|
|
@@ -1907,6 +1916,31 @@ void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(kvm_vcpu_mark_page_dirty);
|
|
EXPORT_SYMBOL_GPL(kvm_vcpu_mark_page_dirty);
|
|
|
|
|
|
|
|
+static void grow_halt_poll_ns(struct kvm_vcpu *vcpu)
|
|
|
|
+{
|
|
|
|
+ int val = vcpu->halt_poll_ns;
|
|
|
|
+
|
|
|
|
+ /* 10us base */
|
|
|
|
+ if (val == 0 && halt_poll_ns_grow)
|
|
|
|
+ val = 10000;
|
|
|
|
+ else
|
|
|
|
+ val *= halt_poll_ns_grow;
|
|
|
|
+
|
|
|
|
+ vcpu->halt_poll_ns = val;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void shrink_halt_poll_ns(struct kvm_vcpu *vcpu)
|
|
|
|
+{
|
|
|
|
+ int val = vcpu->halt_poll_ns;
|
|
|
|
+
|
|
|
|
+ if (halt_poll_ns_shrink == 0)
|
|
|
|
+ val = 0;
|
|
|
|
+ else
|
|
|
|
+ val /= halt_poll_ns_shrink;
|
|
|
|
+
|
|
|
|
+ vcpu->halt_poll_ns = val;
|
|
|
|
+}
|
|
|
|
+
|
|
static int kvm_vcpu_check_block(struct kvm_vcpu *vcpu)
|
|
static int kvm_vcpu_check_block(struct kvm_vcpu *vcpu)
|
|
{
|
|
{
|
|
if (kvm_arch_vcpu_runnable(vcpu)) {
|
|
if (kvm_arch_vcpu_runnable(vcpu)) {
|
|
@@ -1929,6 +1963,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
|
|
ktime_t start, cur;
|
|
ktime_t start, cur;
|
|
DEFINE_WAIT(wait);
|
|
DEFINE_WAIT(wait);
|
|
bool waited = false;
|
|
bool waited = false;
|
|
|
|
+ u64 block_ns;
|
|
|
|
|
|
start = cur = ktime_get();
|
|
start = cur = ktime_get();
|
|
if (vcpu->halt_poll_ns) {
|
|
if (vcpu->halt_poll_ns) {
|
|
@@ -1961,7 +1996,21 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
|
|
cur = ktime_get();
|
|
cur = ktime_get();
|
|
|
|
|
|
out:
|
|
out:
|
|
- trace_kvm_vcpu_wakeup(ktime_to_ns(cur) - ktime_to_ns(start), waited);
|
|
|
|
|
|
+ block_ns = ktime_to_ns(cur) - ktime_to_ns(start);
|
|
|
|
+
|
|
|
|
+ if (halt_poll_ns) {
|
|
|
|
+ if (block_ns <= vcpu->halt_poll_ns)
|
|
|
|
+ ;
|
|
|
|
+ /* we had a long block, shrink polling */
|
|
|
|
+ else if (vcpu->halt_poll_ns && block_ns > halt_poll_ns)
|
|
|
|
+ shrink_halt_poll_ns(vcpu);
|
|
|
|
+ /* we had a short halt and our poll time is too small */
|
|
|
|
+ else if (vcpu->halt_poll_ns < halt_poll_ns &&
|
|
|
|
+ block_ns < halt_poll_ns)
|
|
|
|
+ grow_halt_poll_ns(vcpu);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ trace_kvm_vcpu_wakeup(block_ns, waited);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(kvm_vcpu_block);
|
|
EXPORT_SYMBOL_GPL(kvm_vcpu_block);
|
|
|
|
|