Compare commits

...

6 Commits

Author SHA1 Message Date
11683762c3
[NTOSKRNL:CC] Calculate Dirty Pages like NT5 2024-08-18 07:28:25 +02:00
3ae19eaf01
[NTOSKRNL::CC] Implement CcOkToAddWriteBehindThread 2024-08-17 20:13:20 +02:00
e75a2adeec
[NTOSKRNL:CC] Implement CcAdjustWriteBehindThreadPool and CcAdjustWriteBehindThreadPoolIfNeeded
These two function are responsible for  calling threadpool,when needed
2024-08-17 15:32:37 +02:00
1c173364a1
[NTOSKRNL::CC]Implement CcRescheduleLazyWriteScan CcSetLazyWriteScanQueued
These two function Rescheduling and Scheduling Lazy write scan
2024-08-17 15:08:39 +02:00
104a0212e0
[NTOSKRNL:CC] Add CcQueueLazyWriteScanThread
Implemented CcQueueLazyWriteScanThread
2024-08-17 08:47:34 +02:00
1dec536c4d
[NTOSKRNL:CC] Threadpool 2024-08-16 07:53:05 +02:00

View File

@ -13,8 +13,291 @@
extern "C"
/*Internal Function*/
/* Move Typedef Later to cctypes.hpp */
typedef struct _WRITE_BEHIND_THROUGHPUT
{
ULONG PagesYetToWrite;
ULONG Throughput;
} WRITE_BEHIND_THROUGHPUT, *PWRITE_BEHIND_THROUGHPUT;
BOOLEAN
CcOkToAddWriteBehindThread(VOID)
{
ULONG ActiveExtraWriteBehindThreads = {0};
PWRITE_BEHIND_THROUGHPUT ThroughputStats = nullptr;
ULONG PagesYetToWrite = {0};
ULONG Throughput = {0};
ULONG PreviousThroughput = {0};
LONG ThroughputTrend = {0};
BOOLEAN Result = false;
ActiveExtraWriteBehindThreads = CcActiveExtraWriteBehindThreads;
ThroughputStats = CcThroughputStats;
PagesYetToWrite = CcPagesYetToWrite;
Throughput = ThroughputStats[ActiveExtraWriteBehindThreads].PagesYetToWrite;
PreviousThroughput = 0;
if (Throughput >= PagesYetToWrite)
{
Throughput -= PagesYetToWrite;
}
else
{
Throughput = 0;
}
ThroughputStats[ActiveExtraWriteBehindThreads].PagesYetToWrite = PagesYetToWrite;
Result = true;
if (ActiveExtraWriteBehindThreads > 0)
{
PreviousThroughput = ThroughputStats[ActiveExtraWriteBehindThreads - 1].Throughput;
}
ThroughputStats[ActiveExtraWriteBehindThreads].Throughput = Throughput;
if (Throughput > 0)
{
ThroughputTrend = CcThroughputTrend;
if (Throughput < PreviousThroughput)
{
if (ThroughputTrend > 0)
ThroughputTrend = 0;
ThroughputTrend--;
}
else
{
if (ThroughputTrend < 0)
ThroughputTrend = 0;
ThroughputTrend++;
}
CcThroughputTrend = ThroughputTrend;
if (ThroughputTrend == 3)
{
CcThroughputTrend = 0;
Result = true;
if (ActiveExtraWriteBehindThreads < CcMaxExtraWriteBehindThreads)
{
ThroughputStats[ActiveExtraWriteBehindThreads + 1].Throughput = 0;
ThroughputStats[ActiveExtraWriteBehindThreads + 1].PagesYetToWrite = PagesYetToWrite;
}
}
else if (ThroughputTrend == -3)
{
CcThroughputTrend = 0;
Result = true;
if (ActiveExtraWriteBehindThreads > 0)
{
ThroughputStats[ActiveExtraWriteBehindThreads - 1].Throughput = 0;
ThroughputStats[ActiveExtraWriteBehindThreads - 1].PagesYetToWrite = PagesYetToWrite;
}
}
}
return Result;
}
VOID
NTAPI
CcSetLazyWriteScanQueued(
IN ULONG FlushReason,
IN BOOLEAN QueuedState)
{
switch (FlushReason)
{
case 1:
LazyWriter.PendingLowMemoryScan = QueuedState;
break;
case 2:
LazyWriter.PendingPowerScan = QueuedState;
break;
case 4:
LazyWriter.PendingPeriodicScan = QueuedState;
break;
case 8:
LazyWriter.PendingTeardownScan = QueuedState;
break;
case 16:
LazyWriter.PendingCoalescingFlushScan = QueuedState;
break;
default:
break;
}
}
BOOLEAN
VECTORCALL
CcIsLazyWriteScanQueued(
_In_ ULONG ReasonForFlush
)
{
switch (ReasonForFlush)
{
case 0:
return false;
case 1:
case 2:
case 16:
if (LazyWriter.PendingLowMemoryScan ||
LazyWriter.PendingPowerScan ||
LazyWriter.PendingCoalescingFlushScan)
{
return true;
}
return false;
case 4:
if (LazyWriter.PendingPeriodicScan ||
LazyWriter.PendingTeardownScan)
{
return true;
}
return false;
case 8:
return (BOOLEAN)LazyWriter.PendingTeardownScan;
default:
return false;
}
}
VOID
NTAPI
CcQueueLazyWriteScanThread(
_In_ PVOID NULL_PARAM
)
{
UNREFERENCED_PARAMETER(NULL_PARAM);
ULONG Reason = 0;
BOOLEAN NeedAdjustment;
NTSTATUS Status;
KIRQL OldIrql;
PWORK_QUEUE_ENTRY WorkQueueEntry;
PVOID WaitObjects[5];
WaitObjects[0] = &CcLowMemoryEvent;
WaitObjects[1] = &CcPowerEvent;
WaitObjects[2] = &CcPeriodicEvent;
WaitObjects[3] = &CcWaitingForTeardownEvent;
WaitObjects[4] = &CcCoalescingFlushEvent;
for (;;)
{
NeedAdjustment = false;
Status = KeWaitForMultipleObjects(
5,
WaitObjects,
WaitAny,
WrFreePage,
KernelMode,
false,
NULL,
WaitBlockArray);
switch (Status)
{
case STATUS_WAIT_0:
Reason = 1;
NeedAdjustment = true;
break;
case STATUS_WAIT_1:
Reason = 2;
break;
case STATUS_WAIT_2:
Reason = 4;
break;
case STATUS_WAIT_3:
Reason = 8;
break;
case STATUS_WAIT_4:
Reason = 16;
break;
default:
continue;
}
if (CcNumberOfExternalCaches && !IsListEmpty(&CcExternalCacheList))
{
CcNotifyExternalCaches(Reason);
}
CcAdjustWriteBehindThreadPoolIfNeeded(NeedAdjustment);
OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
if (CcIsLazyWriteScanQueued(Reason))
{
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
continue;
}
CcSetLazyWriteScanQueued(Reason, true);
KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
if (!NT_SUCCESS(CcAllocateWorkQueueEntry(&WorkQueueEntry)))
{
KSPIN_LOCK_QUEUE_NUMBER queueNumber = LockQueueMasterLock;
SpinLockGuard guard(queueNumber);
LazyWriter.ScanActive = false;
CcSetLazyWriteScanQueued(Reason, false);
}
else
{
WorkQueueEntry->Function = 3;
WorkQueueEntry->Parameters.Notification.Reason = Reason;
CcPostWorkQueue(
WorkQueueEntry,
(Reason != 8) ? &CcRegularWorkQueue : &CcFastTeardownWorkQueue);
}
}
}
VOID
NTAPI
CcRescheduleLazyWriteScan( IN PLARGE_INTEGER NextScanDelay)
{
UNREFERENCED_PARAMETER(NextScanDelay);
LARGE_INTEGER Delay = {0};
if (LazyWriter.ScanActive)
{
if (NextScanDelay && NextScanDelay->QuadPart != 0x7FFFFFFFFFFFFFFF && NextScanDelay->QuadPart != 0)
{
Delay.QuadPart = NextScanDelay->QuadPart * KeMaximumIncrement;
if (Delay.QuadPart > 160000000)
Delay.QuadPart = 160000000;
if(Delay.QuadPart < 10000000 )
Delay = CcIdleDelay;
}
KeSetCoalescableTimer(&LazyWriter.ScanTimer,CcIdleDelay,0,1000,&LazyWriter.ScanDpc);
}
else
{
CcScheduleLazyWriteScan(0, 0);
}
}
VOID
@ -981,44 +1264,7 @@ NTAPI CcLazyWriteScan()
CcScheduleLazyWriteScan(FALSE);
}
}
NTSTATUS CcWaitForCurrentLazyWriterActivity()
{
NTSTATUS result;
PWORK_QUEUE_ENTRY WorkQueueEntry = nullptr;
KEVENT Event = {0};
KIRQL irql = {0};
result = CcAllocateWorkQueueEntry(&WorkQueueEntry);
if (NT_SUCCESS(result))
{
WorkQueueEntry->Function = SetDone;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
WorkQueueEntry->Parameters.Notification.Reason = (ULONG_PTR)&Event;
if ((PerfGlobalGroupMask.Masks[4] & 0x20000) != 0)
CcPerfLogWorkItemEnqueue(&CcPostTickWorkQueue, WorkQueueEntry, 0, 0);
irql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
WorkQueueEntry->WorkQueueLinks.Flink = &CcPostTickWorkQueue;
WorkQueueEntry->WorkQueueLinks.Blink = CcPostTickWorkQueue.Blink;
CcPostTickWorkQueue.Blink->Flink = &WorkQueueEntry->WorkQueueLinks;
CcPostTickWorkQueue.Blink = &WorkQueueEntry->WorkQueueLinks;
LazyWriter.OtherWork = 1;
_InterlockedIncrement(&CcPostTickWorkItemCount);
CcScheduleLazyWriteScan(1, 1);
KeReleaseQueuedSpinLock(LockQueueMasterLock, irql);
result = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
_InterlockedDecrement(&CcPostTickWorkItemCount);
}
return result;
}
VOID VECTORCALL CcReEngageWorkerThreads(
ULONG NormalThreadsToActivate,
ULONG ExtraWriteBehindThreadsToActivate
@ -1087,6 +1333,62 @@ VOID VECTORCALL CcReEngageWorkerThreads(
ExQueueWorkItem(currentExtraThreadEntry, CriticalWorkQueue);
}
}
VOID
NTAPI
CcAdjustWriteBehindThreadPool(
IN BOOLEAN IsThreadPriorityLow)
{
if (IsThreadPriorityLow)
{
CcMaxNumberOfWriteBehindThreads = 1;
if (CcAddExtraWriteBehindThreads)
{
CcAddExtraWriteBehindThreads = false;
}
}
else
{
CcMaxNumberOfWriteBehindThreads = (ULONG)-1;
if (!IsListEmpty(&CcRegularWorkQueue) && !CcQueueThrottle)
{
CcReEngageWorkerThreads(CcNumberofWorkerThreads, 0);
}
}
}
VOID
NTAPI
CcAdjustWriteBehindThreadPoolIfNeeded(
IN BOOLEAN NeedAdjustment)
{
BOOLEAN NeedBoost = false;
KSPIN_LOCK_QUEUE_NUMBER queueNumber = LockQueueMasterLock;
SpinLockGuard guard(queueNumber);
if (CcPostTickWorkItemCount != 0)
{
if (CcIsWriteBehindThreadpoolAtLowPriority())
{
CcAdjustWriteBehindThreadPool(false);
}
}
else
{ auto DirtyPages = (CcTotalDirtyPages + CcPagesWrittenLastTime);
if (DirtyPages > 0x2000 || NeedAdjustment)
{
if (CcIsWriteBehindThreadpoolAtLowPriority())
{
CcAdjustWriteBehindThreadPool(false);
}
}
else if (!CcExecutingWriteBehindWorkItems && IsListEmpty(&CcRegularWorkQueue))
{
CcAdjustWriteBehindThreadPool(true);
}
}
}
VOID
NTAPI
CcWorkerThread(PVOID Parameter)