http://blogs.technet.com/b/askperf/archive/2010/07/23/windows-xp-guests-exhibiting-poor-performance-when-running-under-vdi.aspx

Windows does have APIC Lazy IRQL, Microsoft are not idiots.

Best regards,
Alex Ionescu


On Mon, Sep 12, 2011 at 2:46 AM, <[email protected]> wrote:

> Author: tkreuzer
> Date: Mon Sep 12 09:46:20 2011
> New Revision: 53695
>
> URL: http://svn.reactos.org/svn/reactos?rev=53695&view=rev
> Log:
> [HAL]
> Implement lazy irql for APIC. This is useful for VMs, since APIC usually
> has high overhead due to the need of invoking the hypervisor on every irql
> raise and lower. With lazy irql we avoid that until absolutely neccessary.
> Note that we misuse the PCR's IRR field to save the current hardware irql.
> Its a huge performance boost (some parts take half the time), making APIC
> performance close to PIC performance on VBox. This is something that Windows
> doesn't have :)
>
> Modified:
>    trunk/reactos/hal/halx86/apic/apic.c
>    trunk/reactos/hal/halx86/apic/rtctimer.c
>
> Modified: trunk/reactos/hal/halx86/apic/apic.c
> URL:
> http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/apic/apic.c?rev=53695&r1=53694&r2=53695&view=diff
>
> ==============================================================================
> --- trunk/reactos/hal/halx86/apic/apic.c [iso-8859-1] (original)
> +++ trunk/reactos/hal/halx86/apic/apic.c [iso-8859-1] Mon Sep 12 09:46:20
> 2011
> @@ -17,6 +17,8 @@
>
>  #include "apic.h"
>  void HackEoi(void);
> +
> +#define APIC_LAZY_IRQL
>
>  /* GLOBALS
> ********************************************************************/
>
> @@ -105,6 +107,46 @@
>
>  VOID
>  FORCEINLINE
> +ApicWriteIORedirectionEntry(
> +    UCHAR Index,
> +    IOAPIC_REDIRECTION_REGISTER ReDirReg)
> +{
> +    IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0);
> +    IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1);
> +}
> +
> +IOAPIC_REDIRECTION_REGISTER
> +FORCEINLINE
> +ApicReadIORedirectionEntry(
> +    UCHAR Index)
> +{
> +    IOAPIC_REDIRECTION_REGISTER ReDirReg;
> +
> +    ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index);
> +    ReDirReg.Long1 = IOApicRead(IOAPIC_REDTBL + 2 * Index + 1);
> +
> +    return ReDirReg;
> +}
> +
> +VOID
> +FORCEINLINE
> +ApicRequestInterrupt(IN UCHAR Vector)
> +{
> +    APIC_COMMAND_REGISTER CommandRegister;
> +
> +    /* Setup the command register */
> +    CommandRegister.Long0 = 0;
> +    CommandRegister.Vector = Vector;
> +    CommandRegister.MessageType = APIC_MT_Fixed;
> +    CommandRegister.TriggerMode = APIC_TGM_Edge;
> +    CommandRegister.DestinationShortHand = APIC_DSH_Self;
> +
> +    /* Write the low dword to send the interrupt */
> +    ApicWrite(APIC_ICR0, CommandRegister.Long0);
> +}
> +
> +VOID
> +FORCEINLINE
>  ApicSendEOI(void)
>  {
>     //ApicWrite(APIC_EOI, 0);
> @@ -125,6 +167,12 @@
>  {
>  #ifdef _M_AMD64
>     return (KIRQL)__readcr8();
> +#elif defined(APIC_LAZY_IRQL)
> +    // HACK: some magic to Sync VBox's APIC registers
> +    ApicRead(APIC_VER);
> +
> +    /* Return the field in the PCR */
> +    return (KIRQL)__readfsbyte(FIELD_OFFSET(KPCR, Irql));
>  #else
>     // HACK: some magic to Sync VBox's APIC registers
>     ApicRead(APIC_VER);
> @@ -136,16 +184,42 @@
>
>  VOID
>  FORCEINLINE
> -ApicSetCurrentIrql(KIRQL Irql)
> +ApicRaiseIrql(KIRQL Irql)
>  {
>  #ifdef _M_AMD64
>     __writecr8(Irql);
> +#elif defined(APIC_LAZY_IRQL)
> +    __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql);
>  #else
>     /* Convert IRQL and write the TPR */
>     ApicWrite(APIC_TPR, IrqlToTpr(Irql));
>  #endif
>  }
>
> +VOID
> +FORCEINLINE
> +ApicLowerIrql(KIRQL Irql)
> +{
> +#ifdef _M_AMD64
> +    __writecr8(Irql);
> +#elif defined(APIC_LAZY_IRQL)
> +    __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql);
> +
> +    /* Is the new Irql lower than set in the TPR? */
> +    if (Irql < KeGetPcr()->IRR)
> +    {
> +        /* Save the new hard IRQL in the IRR field */
> +        KeGetPcr()->IRR = Irql;
> +
> +        /* Need to lower it back */
> +        ApicWrite(APIC_TPR, IrqlToTpr(Irql));
> +    }
> +#else
> +    /* Convert IRQL and write the TPR */
> +    ApicWrite(APIC_TPR, IrqlToTpr(Irql));
> +#endif
> +}
> +
>  UCHAR
>  FASTCALL
>  HalpIrqToVector(UCHAR Irq)
> @@ -171,6 +245,13 @@
>  HalpVectorToIrq(UCHAR Vector)
>  {
>     return HalpVectorToIndex[Vector];
> +}
> +
> +VOID
> +NTAPI
> +HalpSendEOI(VOID)
> +{
> +    ApicSendEOI();
>  }
>
>  VOID
> @@ -311,31 +392,10 @@
>     ApicWrite(APIC_ERRLVTR, LvtEntry.Long);
>
>     /* Set the IRQL from the PCR */
> -    ApicSetCurrentIrql(KeGetPcr()->Irql);
> -}
> -
> -
> -VOID
> -FORCEINLINE
> -ApicWriteIORedirectionEntry(
> -    UCHAR Index,
> -    IOAPIC_REDIRECTION_REGISTER ReDirReg)
> -{
> -    IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0);
> -    IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1);
> -}
> -
> -IOAPIC_REDIRECTION_REGISTER
> -FORCEINLINE
> -ApicReadIORedirectionEntry(
> -    UCHAR Index)
> -{
> -    IOAPIC_REDIRECTION_REGISTER ReDirReg;
> -
> -    ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index);
> -    ReDirReg.Long1 = IOApicRead(IOAPIC_REDTBL + 2 * Index + 1);
> -
> -    return ReDirReg;
> +    ApicWrite(APIC_TPR, IrqlToTpr(KeGetPcr()->Irql));
> +
> +    /* Save the new hard IRQL in the IRR field */
> +    KeGetPcr()->IRR = KeGetPcr()->Irql;
>  }
>
>  UCHAR
> @@ -486,6 +546,9 @@
>     __writeeflags(EFlags);
>  }
>
> +
> +/* SOFTWARE INTERRUPT TRAPS
> ***************************************************/
> +
>  VOID
>  DECLSPEC_NORETURN
>  FASTCALL
> @@ -493,17 +556,25 @@
>  {
>     KPROCESSOR_MODE ProcessorMode;
>     KIRQL OldIrql;
> -    ASSERT(ApicGetCurrentIrql() < APC_LEVEL);
>     ASSERT(ApicGetProcessorIrql() == APC_LEVEL);
>
>    /* Enter trap */
>     KiEnterInterruptTrap(TrapFrame);
>
> +#ifdef APIC_LAZY_IRQL
> +    if (!HalBeginSystemInterrupt(APC_LEVEL, APC_VECTOR, &OldIrql))
> +    {
> +        /* "Spurious" interrupt, exit the interrupt */
> +        KiEoiHelper(TrapFrame);
> +    }
> +#else
>     /* Save the old IRQL */
>     OldIrql = ApicGetCurrentIrql();
> +    ASSERT(OldIrql < APC_LEVEL);
> +#endif
>
>     /* Raise to APC_LEVEL */
> -    ApicSetCurrentIrql(APC_LEVEL);
> +    ApicRaiseIrql(APC_LEVEL);
>
>     /* End the interrupt */
>     ApicSendEOI();
> @@ -521,7 +592,7 @@
>     _disable();
>
>     /* Restore the old IRQL */
> -    ApicSetCurrentIrql(OldIrql);
> +    ApicLowerIrql(OldIrql);
>
>     /* Exit the interrupt */
>     KiEoiHelper(TrapFrame);
> @@ -534,17 +605,25 @@
>  HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame)
>  {
>     KIRQL OldIrql;
> -    ASSERT(ApicGetCurrentIrql() < DISPATCH_LEVEL);
>     ASSERT(ApicGetProcessorIrql() == DISPATCH_LEVEL);
>
>    /* Enter trap */
>     KiEnterInterruptTrap(TrapFrame);
>
> -    /* Save the old IRQL */
> +#ifdef APIC_LAZY_IRQL
> +    if (!HalBeginSystemInterrupt(DISPATCH_LEVEL, DISPATCH_VECTOR,
> &OldIrql))
> +    {
> +        /* "Spurious" interrupt, exit the interrupt */
> +        KiEoiHelper(TrapFrame);
> +    }
> +#else
> +    /* Get the current IRQL */
>     OldIrql = ApicGetCurrentIrql();
> +    ASSERT(OldIrql < DISPATCH_LEVEL);
> +#endif
>
>     /* Raise to DISPATCH_LEVEL */
> -    ApicSetCurrentIrql(DISPATCH_LEVEL);
> +    ApicRaiseIrql(DISPATCH_LEVEL);
>
>     /* End the interrupt */
>     ApicSendEOI();
> @@ -555,37 +634,23 @@
>     _disable();
>
>     /* Restore the old IRQL */
> -    ApicSetCurrentIrql(OldIrql);
> +    ApicLowerIrql(OldIrql);
>
>     /* Exit the interrupt */
>     KiEoiHelper(TrapFrame);
>  }
>  #endif
>
> -VOID
> -NTAPI
> -HalpSendEOI(VOID)
> -{
> -    ApicSendEOI();
> -}
> -
> -/* PUBLIC FUNCTIONS
> ***********************************************************/
> +
> +/* SOFTWARE INTERRUPTS
> ********************************************************/
> +
>
>  VOID
>  FASTCALL
>  HalRequestSoftwareInterrupt(IN KIRQL Irql)
>  {
> -    APIC_COMMAND_REGISTER CommandRegister;
> -
> -    /* Setup the command register */
> -    CommandRegister.Long0 = 0;
> -    CommandRegister.Vector = IrqlToTpr(Irql);
> -    CommandRegister.MessageType = APIC_MT_Fixed;
> -    CommandRegister.TriggerMode = APIC_TGM_Edge;
> -    CommandRegister.DestinationShortHand = APIC_DSH_Self;
> -
> -    /* Write the low dword to send the interrupt */
> -    ApicWrite(APIC_ICR0, CommandRegister.Long0);
> +    /* Convert irql to vector and request an interrupt */
> +    ApicRequestInterrupt(IrqlToTpr(Irql));
>  }
>
>  VOID
> @@ -595,6 +660,9 @@
>  {
>     /* Nothing to do */
>  }
> +
> +
> +/* SYSTEM INTERRUPTS
> **********************************************************/
>
>  BOOLEAN
>  NTAPI
> @@ -678,11 +746,37 @@
>     IN UCHAR Vector,
>     OUT PKIRQL OldIrql)
>  {
> +    KIRQL CurrentIrql;
> +
>     /* Get the current IRQL */
> -    *OldIrql = ApicGetCurrentIrql();
> +    CurrentIrql = ApicGetCurrentIrql();
> +
> +#ifdef APIC_LAZY_IRQL
> +    /* Check if this interrupt is allowed */
> +    if (CurrentIrql >= Irql)
> +    {
> +        /* It is not, set the real Irql in the TPR! */
> +        ApicWrite(APIC_TPR, IrqlToTpr(CurrentIrql));
> +
> +        /* Save the new hard IRQL in the IRR field */
> +        KeGetPcr()->IRR = CurrentIrql;
> +
> +        /* End this interrupt */
> +        ApicSendEOI();
> +
> +        // FIXME: level interrupts
> +        /* Re-request the interrupt to be handled later */
> +        ApicRequestInterrupt(Vector);
> +
> +        /* Pretend it was a spurious interrupt */
> +        return FALSE;
> +    }
> +#endif
> +    /* Save the current IRQL */
> +    *OldIrql = CurrentIrql;
>
>     /* Set the new IRQL */
> -    ApicSetCurrentIrql(Irql);
> +    ApicRaiseIrql(Irql);
>
>     /* Turn on interrupts */
>     _enable();
> @@ -701,9 +795,11 @@
>     ApicSendEOI();
>
>     /* Restore the old IRQL */
> -    ApicSetCurrentIrql(OldIrql);
> -}
> -
> +    ApicLowerIrql(OldIrql);
> +}
> +
> +
> +/* IRQL MANAGEMENT
> ************************************************************/
>
>  KIRQL
>  NTAPI
> @@ -726,8 +822,8 @@
>         KeBugCheck(IRQL_NOT_LESS_OR_EQUAL);
>     }
>  #endif
> -    /* Convert the new IRQL to a TPR value and write the register */
> -    ApicSetCurrentIrql(OldIrql);
> +    /* Set the new IRQL */
> +    ApicLowerIrql(OldIrql);
>  }
>
>  KIRQL
> @@ -748,7 +844,7 @@
>     }
>  #endif
>     /* Convert the new IRQL to a TPR value and write the register */
> -    ApicSetCurrentIrql(NewIrql);
> +    ApicRaiseIrql(NewIrql);
>
>     /* Return old IRQL */
>     return OldIrql;
>
> Modified: trunk/reactos/hal/halx86/apic/rtctimer.c
> URL:
> http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/apic/rtctimer.c?rev=53695&r1=53694&r2=53695&view=diff
>
> ==============================================================================
> --- trunk/reactos/hal/halx86/apic/rtctimer.c [iso-8859-1] (original)
> +++ trunk/reactos/hal/halx86/apic/rtctimer.c [iso-8859-1] Mon Sep 12
> 09:46:20 2011
> @@ -111,7 +111,7 @@
>     KiEnterInterruptTrap(TrapFrame);
>
>     /* Start the interrupt */
> -    if (HalBeginSystemInterrupt(CLOCK_LEVEL, PRIMARY_VECTOR_BASE, &Irql))
> +    if (HalBeginSystemInterrupt(CLOCK_LEVEL, HalpClockVector, &Irql))
>     {
>         /* Read register C, so that the next interrupt can happen */
>         HalpReadCmos(RTC_REGISTER_C);;
>
>
>
_______________________________________________
Ros-dev mailing list
[email protected]
http://www.reactos.org/mailman/listinfo/ros-dev

Reply via email to