There is still a minor issue with the in-kernel APIC (even in v8)
w.r.t. informing QEMU about irq-windows.  As a result, QEMU thinks there are
more windows than there actually are, and pushes another round of interrupts
down into the kernel.  Since PICs can generally only queue 1-2 interrupts,
this results in an occasional interrupt being "lost".

Despite this, the system operates functionally correct, but slower than
optimal.  Even so, the in-kernel APIC offers an 11% speed-up over kvm-trunk.
But the potential speedup is much more due to the many conversions of many
common exits to light-exits.

This patch is a workaround to the lost interrupt problem that can be applied
to reveal another 12% performance improvement.  It is an interim solution
while I fix the real lost interrupts problem (hopefully in the next day or so)
in case you want to test "full speed".  I find the combination of v8 +
backlog.patch to offer the best performance I have seen to date.

Signed-off-by: Gregory Haskins <[EMAIL PROTECTED]>
---

 drivers/kvm/lapic.c |   36 ++++++++++++++++--------------------
 1 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c
index 602e94c..1b5f001 100644
--- a/drivers/kvm/lapic.c
+++ b/drivers/kvm/lapic.c
@@ -39,6 +39,8 @@
 /* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
 #define apic_debug(fmt,arg...)
 
+#define MAX_APIC_INT_VECTOR 256
+
 struct kvm_kern_apic {
        spinlock_t              lock;
        atomic_t                ref_count;
@@ -49,11 +51,11 @@ struct kvm_kern_apic {
        unsigned long           base_address;
        struct kvm_io_device    mmio_dev;
        struct {
-               unsigned long   pending;
                u32             divide_count;
                ktime_t         last_update;
                struct hrtimer  dev;
        } timer;
+       u64                     backlog[MAX_APIC_INT_VECTOR];
        u32                     err_status;
        u32                     err_write_count;
        struct kvm_vcpu         *vcpu;
@@ -82,7 +84,6 @@ static __inline__ int find_highest_bit(unsigned long *data, 
int nr_bits)
 #define APIC_GLOB_DISABLE_MASK         0x1
 #define APIC_SOFTWARE_DISABLE_MASK     0x2
 #define _APIC_BSP_ACCEPT_PIC           0x3
-#define MAX_APIC_INT_VECTOR             256
 
 #define inject_gp(vcpu) kvm_arch_ops->inject_gp(vcpu, 0);
 
@@ -384,6 +385,8 @@ static int __apic_accept_irq(struct kvm_kern_apic *apic,
                        set_bit(vector, apic->regs + APIC_TMR);
                }
 
+               ++apic->backlog[vector];
+               
                apic_debug("FIXED/LOWEST interrupt for vector %d\n", vector);
                pin = kvm_irqpin_localint;
                break;
@@ -465,7 +468,7 @@ static void apic_set_eoi(struct kvm_kern_apic *apic)
        __clear_bit(vector, apic->regs + APIC_ISR);
        forward = apic_update_ppr(apic);
 
-       __clear_bit(vector, apic->regs + APIC_TMR);
+       //__clear_bit(vector, apic->regs + APIC_TMR);
 
        if (forward) {
                spin_unlock_bh(&apic->lock);
@@ -1118,9 +1121,10 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
        apic->base_address = apic->base_msr & MSR_IA32_APICBASE_BASE;
 
        apic->timer.divide_count = 0;
-       apic->timer.pending = 0;
        apic->status = 0;
 
+       memset(apic->backlog, 0, sizeof(apic->backlog));
+
 #ifdef APIC_NO_BIOS
        /*
         * XXX According to mp specification, BIOS will enable LVT0/1,
@@ -1182,7 +1186,6 @@ static int __apic_timer_fn(struct kvm_kern_apic *apic)
        vector                  = apic_lvt_vector(apic, APIC_LVTT);
        now                     = apic->timer.dev.base->get_time();
        apic->timer.last_update = now;
-       apic->timer.pending++;
 
        __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0);
 
@@ -1254,24 +1257,17 @@ static int apic_irqdev_ack(struct kvm_irqdevice *this, 
int flags,
                irq = apic_find_highest_irr(apic);
                if ((irq & 0xf0) > apic_get_reg(apic, APIC_PROCPRI)) {
                        BUG_ON (irq < 0x10);
+                       BUG_ON (irq > 0xff);
 
                        __set_bit(irq, apic->regs + APIC_ISR);
-                       __clear_bit(irq, apic->regs + APIC_IRR);
-                       apic_update_ppr(apic);
 
-                       /*
-                        * We have to special case the timer interrupt
-                        * because we want the vector to stay pending
-                        * for each tick of the clock, even for a backlog.
-                        * Therefore, if this was a timer vector and we
-                        * still have ticks pending, keep IRR set
-                        */
-                       if (irq == apic_lvt_vector(apic, APIC_LVTT)) {
-                               BUG_ON(!apic->timer.pending);
-                               apic->timer.pending--;
-                               if (apic->timer.pending)
-                                       __set_bit(irq, apic->regs + APIC_IRR);
-                       }
+                       if (apic->backlog[irq])
+                               --apic->backlog[irq];
+
+                       if (!apic->backlog[irq])
+                               __clear_bit(irq, apic->regs + APIC_IRR);
+
+                       apic_update_ppr(apic);
 
                        data->flags |= KVM_IRQACKDATA_VECTOR_VALID;
                        data->vector = irq;


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to