mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 22:02:58 +00:00
- Add some TIMER values to the ddk.
- 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
This commit is contained in:
parent
e037b1c36b
commit
77203d0406
3 changed files with 138 additions and 103 deletions
|
@ -1189,6 +1189,9 @@ typedef struct _KGUARDED_MUTEX
|
||||||
};
|
};
|
||||||
} KGUARDED_MUTEX, *PKGUARDED_MUTEX;
|
} KGUARDED_MUTEX, *PKGUARDED_MUTEX;
|
||||||
|
|
||||||
|
#define TIMER_TABLE_SIZE 512
|
||||||
|
#define TIMER_TABLE_SHIFT 9
|
||||||
|
|
||||||
typedef struct _KTIMER {
|
typedef struct _KTIMER {
|
||||||
DISPATCHER_HEADER Header;
|
DISPATCHER_HEADER Header;
|
||||||
ULARGE_INTEGER DueTime;
|
ULARGE_INTEGER DueTime;
|
||||||
|
@ -1197,6 +1200,10 @@ typedef struct _KTIMER {
|
||||||
LONG Period;
|
LONG Period;
|
||||||
} KTIMER, *PKTIMER, *RESTRICTED_POINTER PRKTIMER;
|
} KTIMER, *PKTIMER, *RESTRICTED_POINTER PRKTIMER;
|
||||||
|
|
||||||
|
#define ASSERT_TIMER(E) \
|
||||||
|
ASSERT(((E)->Header.Type == TimerNotificationObject) || \
|
||||||
|
((E)->Header.Type == TimerSynchronizationObject))
|
||||||
|
|
||||||
typedef struct _KMUTANT {
|
typedef struct _KMUTANT {
|
||||||
DISPATCHER_HEADER Header;
|
DISPATCHER_HEADER Header;
|
||||||
LIST_ENTRY MutantListEntry;
|
LIST_ENTRY MutantListEntry;
|
||||||
|
|
|
@ -39,12 +39,17 @@ CHAR KiTimerSystemAuditing = 0;
|
||||||
static KDPC KiExpireTimerDpc;
|
static KDPC KiExpireTimerDpc;
|
||||||
static BOOLEAN KiClockSetupComplete = FALSE;
|
static BOOLEAN KiClockSetupComplete = FALSE;
|
||||||
|
|
||||||
|
extern ULONG KiMaximumDpcQueueDepth;
|
||||||
|
extern ULONG KiMinimumDpcRate;
|
||||||
|
extern ULONG KiAdjustDpcThreshold;
|
||||||
|
extern ULONG KiIdealDpcRate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of timer interrupts since initialisation
|
* Number of timer interrupts since initialisation
|
||||||
*/
|
*/
|
||||||
volatile KSYSTEM_TIME KeTickCount = {0};
|
volatile KSYSTEM_TIME KeTickCount = {0};
|
||||||
volatile ULONG KiRawTicks = 0;
|
volatile ULONG KiRawTicks = 0;
|
||||||
|
LONG KiTickOffset = 0;
|
||||||
extern LIST_ENTRY KiTimerListHead;
|
extern LIST_ENTRY KiTimerListHead;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -237,73 +242,87 @@ KeSetTimeUpdateNotifyRoutine(
|
||||||
*/
|
*/
|
||||||
VOID
|
VOID
|
||||||
STDCALL
|
STDCALL
|
||||||
KeUpdateRunTime(
|
KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
|
||||||
IN PKTRAP_FRAME TrapFrame,
|
IN KIRQL Irql)
|
||||||
IN KIRQL Irql
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
PKPRCB Prcb;
|
PKPRCB Prcb = KeGetCurrentPrcb();
|
||||||
PKTHREAD CurrentThread;
|
PKTHREAD CurrentThread;
|
||||||
PKPROCESS CurrentProcess;
|
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) || !(Prcb->CurrentThread)) return;
|
||||||
|
|
||||||
/* Make sure we don't go further if we're in early boot phase. */
|
/* Get the current thread and process */
|
||||||
if (Prcb == NULL || Prcb->CurrentThread == NULL)
|
CurrentThread = Prcb->CurrentThread;
|
||||||
return;
|
CurrentProcess = CurrentThread->ApcState.Process;
|
||||||
|
|
||||||
DPRINT("KernelTime %u, UserTime %u \n", Prcb->KernelTime, Prcb->UserTime);
|
/* 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++;
|
||||||
|
}
|
||||||
|
|
||||||
CurrentThread = Prcb->CurrentThread;
|
/* Update CPU kernel time in all cases */
|
||||||
CurrentProcess = CurrentThread->ApcState.Process;
|
Prcb->KernelTime++;
|
||||||
|
|
||||||
/*
|
|
||||||
* 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++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
/* Set the last DPC Count and request rate */
|
||||||
DpcLastCount = Prcb->DpcLastCount;
|
Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
|
||||||
Prcb->DpcLastCount = Prcb->DpcCount;
|
Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
|
||||||
Prcb->DpcRequestRate = ((Prcb->DpcCount - DpcLastCount) +
|
Prcb->DpcRequestRate) / 2;
|
||||||
Prcb->DpcRequestRate) / 2;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (Prcb->DpcData[0].DpcQueueDepth > 0 &&
|
/* Check if we should request a DPC */
|
||||||
Prcb->DpcRoutineActive == FALSE &&
|
if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
|
||||||
Prcb->DpcInterruptRequested == FALSE)
|
{
|
||||||
{
|
/* Request one */
|
||||||
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: Do DPC rate adjustments */
|
/* 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
|
* 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
|
* we don't care about the quantum value anymore after the QuantumEnd
|
||||||
* flag is set.
|
* flag is set.
|
||||||
*/
|
*/
|
||||||
if ((CurrentThread->Quantum -= 3) <= 0)
|
if ((CurrentThread->Quantum -= 3) <= 0)
|
||||||
{
|
{
|
||||||
Prcb->QuantumEnd = TRUE;
|
Prcb->QuantumEnd = TRUE;
|
||||||
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -333,51 +352,56 @@ KeUpdateRunTime(
|
||||||
*/
|
*/
|
||||||
VOID
|
VOID
|
||||||
STDCALL
|
STDCALL
|
||||||
KeUpdateSystemTime(
|
KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
|
||||||
IN PKTRAP_FRAME TrapFrame,
|
IN KIRQL Irql)
|
||||||
IN KIRQL Irql
|
|
||||||
)
|
|
||||||
/*
|
|
||||||
* FUNCTION: Handles a timer interrupt
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
LARGE_INTEGER Time;
|
LONG OldOffset;
|
||||||
|
LARGE_INTEGER Time;
|
||||||
|
ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
|
||||||
|
if (!KiClockSetupComplete) return;
|
||||||
|
|
||||||
ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
|
/* 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;
|
||||||
|
|
||||||
KiRawTicks++;
|
/* Increase the tick offset */
|
||||||
|
KiTickOffset -= CLOCK_INCREMENT;
|
||||||
|
OldOffset = KiTickOffset;
|
||||||
|
|
||||||
if (KiClockSetupComplete == FALSE) return;
|
/* 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 */
|
||||||
* Increment the number of timers ticks
|
Time.LowPart = SharedUserData->SystemTime.LowPart;
|
||||||
*/
|
Time.HighPart = SharedUserData->SystemTime.High1Time;
|
||||||
(*(PULONGLONG)&KeTickCount)++;
|
Time.QuadPart += CLOCK_INCREMENT;
|
||||||
SharedUserData->TickCountLowDeprecated++;
|
SharedUserData->SystemTime.High2Time = Time.HighPart;
|
||||||
|
SharedUserData->SystemTime.LowPart = Time.LowPart;
|
||||||
|
SharedUserData->SystemTime.High1Time = Time.HighPart;
|
||||||
|
|
||||||
Time.u.LowPart = SharedUserData->InterruptTime.LowPart;
|
/* Update tick count */
|
||||||
Time.u.HighPart = SharedUserData->InterruptTime.High1Time;
|
(*(PULONGLONG)&KeTickCount)++;
|
||||||
Time.QuadPart += CLOCK_INCREMENT;
|
SharedUserData->TickCountLowDeprecated++;
|
||||||
SharedUserData->InterruptTime.High2Time = Time.u.HighPart;
|
KiRawTicks++;
|
||||||
SharedUserData->InterruptTime.LowPart = Time.u.LowPart;
|
|
||||||
SharedUserData->InterruptTime.High1Time = Time.u.HighPart;
|
|
||||||
|
|
||||||
Time.u.LowPart = SharedUserData->SystemTime.LowPart;
|
/* Queue a DPC that will expire timers */
|
||||||
Time.u.HighPart = SharedUserData->SystemTime.High1Time;
|
KeInsertQueueDpc(&KiExpireTimerDpc, (PVOID)TrapFrame->Eip, 0);
|
||||||
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 */
|
||||||
|
if (OldOffset <= 0) KeUpdateRunTime(TrapFrame, Irql);
|
||||||
/* Update process and thread times */
|
|
||||||
KeUpdateRunTime(TrapFrame, Irql);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Queue a DPC that will expire timers
|
|
||||||
*/
|
|
||||||
KeInsertQueueDpc(&KiExpireTimerDpc, (PVOID)TrapFrame->Eip, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -25,6 +25,10 @@
|
||||||
#pragma alloc_text(INIT, KeInitDpc)
|
#pragma alloc_text(INIT, KeInitDpc)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ULONG KiMaximumDpcQueueDepth = 4;
|
||||||
|
ULONG KiMinimumDpcRate = 3;
|
||||||
|
ULONG KiAdjustDpcThreshold = 20;
|
||||||
|
ULONG KiIdealDpcRate = 20;
|
||||||
|
|
||||||
/* TYPES *******************************************************************/
|
/* TYPES *******************************************************************/
|
||||||
|
|
||||||
|
@ -49,8 +53,8 @@ KeInitDpc(PKPRCB Prcb)
|
||||||
KeInitializeEvent(Prcb->DpcEvent, 0, 0);
|
KeInitializeEvent(Prcb->DpcEvent, 0, 0);
|
||||||
#endif
|
#endif
|
||||||
KeInitializeSpinLock(&Prcb->DpcData[0].DpcLock);
|
KeInitializeSpinLock(&Prcb->DpcData[0].DpcLock);
|
||||||
Prcb->MaximumDpcQueueDepth = 4;
|
Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
|
||||||
Prcb->MinimumDpcRate = 3;
|
Prcb->MinimumDpcRate = KiMinimumDpcRate;
|
||||||
Prcb->DpcData[0].DpcQueueDepth = 0;
|
Prcb->DpcData[0].DpcQueueDepth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue