- Add some TIMER values to the ddk.
authorAlex Ionescu <aionescu@gmail.com>
Thu, 13 Jul 2006 06:23:34 +0000 (06:23 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Thu, 13 Jul 2006 06:23:34 +0000 (06:23 +0000)
- Add DPC Settings (Queue Depths, Rates, etc)
- Cleanup System/Run Time Update code.
- Always increase kernel time in PRCB when inside kernel-mode code.
- Get rid of superflous interlocked commands when not needed.
- Improve detection of DPC vs non-DPC time.
- Respect and apply DPC queue/rate rules.
- Allow future use of non-fulltick time increments.

svn path=/trunk/; revision=23039

reactos/include/ddk/winddk.h
reactos/ntoskrnl/ke/clock.c
reactos/ntoskrnl/ke/dpc.c

index 0586737..bbd1f83 100644 (file)
@@ -1189,6 +1189,9 @@ typedef struct _KGUARDED_MUTEX
     };
 } KGUARDED_MUTEX, *PKGUARDED_MUTEX;
 
+#define TIMER_TABLE_SIZE 512
+#define TIMER_TABLE_SHIFT 9
+
 typedef struct _KTIMER {
   DISPATCHER_HEADER  Header;
   ULARGE_INTEGER  DueTime;
@@ -1197,6 +1200,10 @@ typedef struct _KTIMER {
   LONG  Period;
 } KTIMER, *PKTIMER, *RESTRICTED_POINTER PRKTIMER;
 
+#define ASSERT_TIMER(E) \
+    ASSERT(((E)->Header.Type == TimerNotificationObject) || \
+           ((E)->Header.Type == TimerSynchronizationObject))
+
 typedef struct _KMUTANT {
   DISPATCHER_HEADER  Header;
   LIST_ENTRY  MutantListEntry;
index 29a27cd..14a5cdf 100644 (file)
@@ -39,12 +39,17 @@ CHAR KiTimerSystemAuditing = 0;
 static KDPC KiExpireTimerDpc;
 static BOOLEAN KiClockSetupComplete = FALSE;
 
+extern ULONG KiMaximumDpcQueueDepth;
+extern ULONG KiMinimumDpcRate;
+extern ULONG KiAdjustDpcThreshold;
+extern ULONG KiIdealDpcRate;
+
 /*
  * Number of timer interrupts since initialisation
  */
 volatile KSYSTEM_TIME KeTickCount = {0};
 volatile ULONG KiRawTicks = 0;
-
+LONG KiTickOffset = 0;
 extern LIST_ENTRY KiTimerListHead;
 
 /*
@@ -237,73 +242,87 @@ KeSetTimeUpdateNotifyRoutine(
  */
 VOID
 STDCALL
-KeUpdateRunTime(
-    IN PKTRAP_FRAME  TrapFrame,
-    IN KIRQL  Irql
-    )
+KeUpdateRunTime(IN PKTRAP_FRAME  TrapFrame,
+                IN KIRQL  Irql)
 {
-   PKPRCB Prcb;
-   PKTHREAD CurrentThread;
-   PKPROCESS CurrentProcess;
-#if 0
-   ULONG DpcLastCount;
-#endif
-
-   Prcb = KeGetCurrentPrcb();
-
-   /* Make sure we don't go further if we're in early boot phase. */
-   if (Prcb == NULL || Prcb->CurrentThread == NULL)
-      return;
+    PKPRCB Prcb = KeGetCurrentPrcb();
+    PKTHREAD CurrentThread;
+    PKPROCESS CurrentProcess;
 
-   DPRINT("KernelTime  %u, UserTime %u \n", Prcb->KernelTime, Prcb->UserTime);
+    /* Make sure we don't go further if we're in early boot phase. */
+    if (!(Prcb) || !(Prcb->CurrentThread)) return;
 
-   CurrentThread = Prcb->CurrentThread;
-   CurrentProcess = CurrentThread->ApcState.Process;
+    /* Get the current thread and process */
+    CurrentThread = Prcb->CurrentThread;
+    CurrentProcess = CurrentThread->ApcState.Process;
 
-   /*
-    * Cs bit 0 is always set for user mode if we are in protected mode.
-    * V86 mode is counted as user time.
-    */
-   if (TrapFrame->SegCs & MODE_MASK ||
-       TrapFrame->EFlags & X86_EFLAGS_VM)
-   {
-      (void)InterlockedIncrementUL(&CurrentThread->UserTime);
-      (void)InterlockedIncrementUL(&CurrentProcess->UserTime);
-      Prcb->UserTime++;
-   }
-   else
-   {
-      if (Irql > DISPATCH_LEVEL)
-      {
-         Prcb->InterruptTime++;
-      }
-      else if (Irql == DISPATCH_LEVEL)
-      {
-         Prcb->DpcTime++;
-      }
-      else
-      {
-         (void)InterlockedIncrementUL(&CurrentThread->KernelTime);
-         (void)InterlockedIncrementUL(&CurrentProcess->KernelTime);
-         Prcb->KernelTime++;
-      }
+    /* Check if we came from user mode */
+    if (TrapFrame->PreviousPreviousMode != KernelMode)
+    {
+        /* Update user times */
+        CurrentThread->UserTime++;
+        InterlockedIncrement(&CurrentProcess->UserTime);
+        Prcb->UserTime++;
+    }
+    else
+    {
+        /* Check IRQ */
+        if (Irql > DISPATCH_LEVEL)
+        {
+            /* This was an interrupt */
+            Prcb->InterruptTime++;
+        }
+        else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive))
+        {
+            /* This was normal kernel time */
+            CurrentThread->KernelTime++;
+            InterlockedIncrement(&CurrentProcess->KernelTime);
+        }
+        else if (Irql == DISPATCH_LEVEL)
+        {
+            /* This was DPC time */
+            Prcb->DpcTime++;
+        }
+
+        /* Update CPU kernel time in all cases */
+        Prcb->KernelTime++;
    }
 
-#if 0
-   DpcLastCount = Prcb->DpcLastCount;
-   Prcb->DpcLastCount = Prcb->DpcCount;
-   Prcb->DpcRequestRate = ((Prcb->DpcCount - DpcLastCount) +
-                                   Prcb->DpcRequestRate) / 2;
-#endif
+    /* Set the last DPC Count and request rate */
+    Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
+    Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
+                             Prcb->DpcRequestRate) / 2;
 
-   if (Prcb->DpcData[0].DpcQueueDepth > 0 &&
-       Prcb->DpcRoutineActive == FALSE &&
-       Prcb->DpcInterruptRequested == FALSE)
-   {
-      HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
-   }
-
-   /* FIXME: Do DPC rate adjustments */
+    /* Check if we should request a DPC */
+    if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
+    {
+        /* Request one */
+        HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
+
+        /* Update the depth if needed */
+        if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
+            (Prcb->MaximumDpcQueueDepth > 1))
+        {
+            /* Decrease the maximum depth by one */
+            Prcb->MaximumDpcQueueDepth--;
+        }
+    }
+    else
+    {
+        /* Decrease the adjustment threshold */
+        if (!(--Prcb->AdjustDpcThreshold))
+        {
+            /* We've hit 0, reset it */
+            Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
+
+            /* Check if we've hit queue maximum */
+            if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
+            {
+                /* Increase maximum by one */
+                Prcb->MaximumDpcQueueDepth++;
+            }
+        }
+    }
 
    /*
     * If we're at end of quantum request software interrupt. The rest
@@ -315,11 +334,11 @@ KeUpdateRunTime(
     * we don't care about the quantum value anymore after the QuantumEnd
     * flag is set.
     */
-   if ((CurrentThread->Quantum -= 3) <= 0)
-   {
-      Prcb->QuantumEnd = TRUE;
-      HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
-   }
+    if ((CurrentThread->Quantum -= 3) <= 0)
+    {
+        Prcb->QuantumEnd = TRUE;
+        HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
+    }
 }
 
 
@@ -333,51 +352,56 @@ KeUpdateRunTime(
  */
 VOID
 STDCALL
-KeUpdateSystemTime(
-    IN PKTRAP_FRAME  TrapFrame,
-    IN KIRQL  Irql
-    )
-/*
- * FUNCTION: Handles a timer interrupt
- */
+KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
+                   IN KIRQL Irql)
 {
-   LARGE_INTEGER Time;
-
-   ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
-
-   KiRawTicks++;
-
-   if (KiClockSetupComplete == FALSE) return;
-
-   /*
-    * Increment the number of timers ticks
-    */
-   (*(PULONGLONG)&KeTickCount)++;
-   SharedUserData->TickCountLowDeprecated++;
-
-   Time.u.LowPart = SharedUserData->InterruptTime.LowPart;
-   Time.u.HighPart = SharedUserData->InterruptTime.High1Time;
-   Time.QuadPart += CLOCK_INCREMENT;
-   SharedUserData->InterruptTime.High2Time = Time.u.HighPart;
-   SharedUserData->InterruptTime.LowPart = Time.u.LowPart;
-   SharedUserData->InterruptTime.High1Time = Time.u.HighPart;
-
-   Time.u.LowPart = SharedUserData->SystemTime.LowPart;
-   Time.u.HighPart = SharedUserData->SystemTime.High1Time;
-   Time.QuadPart += CLOCK_INCREMENT;
-   SharedUserData->SystemTime.High2Time = Time.u.HighPart;
-   SharedUserData->SystemTime.LowPart = Time.u.LowPart;
-   SharedUserData->SystemTime.High1Time = Time.u.HighPart;
-
-   /* FIXME: Here we should check for remote debugger break-ins */
-
-   /* Update process and thread times */
-   KeUpdateRunTime(TrapFrame, Irql);
+    LONG OldOffset;
+    LARGE_INTEGER Time;
+    ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
+    if (!KiClockSetupComplete) return;
+
+    /* Update interrupt time */
+    Time.LowPart = SharedUserData->InterruptTime.LowPart;
+    Time.HighPart = SharedUserData->InterruptTime.High1Time;
+    Time.QuadPart += CLOCK_INCREMENT;
+    SharedUserData->InterruptTime.High2Time = Time.u.HighPart;
+    SharedUserData->InterruptTime.LowPart = Time.u.LowPart;
+    SharedUserData->InterruptTime.High1Time = Time.u.HighPart;
+
+    /* Increase the tick offset */
+    KiTickOffset -= CLOCK_INCREMENT;
+    OldOffset = KiTickOffset;
+
+    /* Check if this isn't a tick yet */
+    if (KiTickOffset > 0)
+    {
+        /* Expire timers */
+        KeInsertQueueDpc(&KiExpireTimerDpc, (PVOID)TrapFrame->Eip, 0);
+    }
+    else
+    {
+        /* This was a tick, calculate the next one */
+        KiTickOffset += CLOCK_INCREMENT;
+
+        /* Setup time structure for system time */
+        Time.LowPart = SharedUserData->SystemTime.LowPart;
+        Time.HighPart = SharedUserData->SystemTime.High1Time;
+        Time.QuadPart += CLOCK_INCREMENT;
+        SharedUserData->SystemTime.High2Time = Time.HighPart;
+        SharedUserData->SystemTime.LowPart = Time.LowPart;
+        SharedUserData->SystemTime.High1Time = Time.HighPart;
+
+        /* Update tick count */
+        (*(PULONGLONG)&KeTickCount)++;
+        SharedUserData->TickCountLowDeprecated++;
+        KiRawTicks++;
+
+        /* Queue a DPC that will expire timers */
+        KeInsertQueueDpc(&KiExpireTimerDpc, (PVOID)TrapFrame->Eip, 0);
+    }
 
-   /*
-    * Queue a DPC that will expire timers
-    */
-   KeInsertQueueDpc(&KiExpireTimerDpc, (PVOID)TrapFrame->Eip, 0);
+    /* Update process and thread times */
+    if (OldOffset <= 0) KeUpdateRunTime(TrapFrame, Irql);
 }
 
 /*
index 5ca1616..b8455fe 100644 (file)
 #pragma alloc_text(INIT, KeInitDpc)
 #endif
 
+ULONG KiMaximumDpcQueueDepth = 4;
+ULONG KiMinimumDpcRate = 3;
+ULONG KiAdjustDpcThreshold = 20;
+ULONG KiIdealDpcRate = 20;
 
 /* TYPES *******************************************************************/
 
@@ -49,8 +53,8 @@ KeInitDpc(PKPRCB Prcb)
    KeInitializeEvent(Prcb->DpcEvent, 0, 0);
 #endif
    KeInitializeSpinLock(&Prcb->DpcData[0].DpcLock);
-   Prcb->MaximumDpcQueueDepth = 4;
-   Prcb->MinimumDpcRate = 3;
+   Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
+   Prcb->MinimumDpcRate = KiMinimumDpcRate;
    Prcb->DpcData[0].DpcQueueDepth = 0;
 }