00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
#include "mi.h"
00078
00079
VOID
00080
MiEmptyAllWorkingSetsWorker (
00081 VOID
00082 );
00083
00084
#ifdef ALLOC_PRAGMA
00085
#pragma alloc_text(PAGELK, MiEmptyAllWorkingSetsWorker)
00086
#pragma alloc_text(PAGELK, MiEmptyAllWorkingSets)
00087
#pragma alloc_text(INIT, MiAdjustWorkingSetManagerParameters)
00088
#endif
00089
00090
00091
00092
00093
00094
00095 ULONG
MiIdealPassFaultCountDisable;
00096
00097 extern ULONG
PsMinimumWorkingSet;
00098
00099 extern PEPROCESS ExpDefaultErrorPortProcess;
00100
00101 #define MM_TRIM_COUNTER_MAXIMUM_LARGE_MEM (6)
00102
00103
00104
00105
00106
00107 KEVENT MiWaitForEmptyEvent;
00108 BOOLEAN
MiWaitingForWorkingSetEmpty;
00109
00110
00111
00112
00113
00114
00115 #define MM_REDUCE_FAULT_COUNT (10000)
00116
00117 #define MM_IGNORE_FAULT_COUNT (100)
00118
00119
#ifdef _MI_USE_CLAIMS_
00120
BOOLEAN MiReplacing =
FALSE;
00121
#endif
00122
00123 PFN_NUMBER
MmMoreThanEnoughFreePages = 1000;
00124
00125 ULONG
MmAmpleFreePages = 200;
00126
00127 ULONG
MmWorkingSetReductionMin = 12;
00128 ULONG
MmWorkingSetReductionMinCacheWs = 12;
00129
00130 ULONG
MmWorkingSetReductionMax = 60;
00131 ULONG
MmWorkingSetReductionMaxCacheWs = 60;
00132
00133 ULONG
MmWorkingSetReductionHuge = (512*1024) >>
PAGE_SHIFT;
00134
00135 ULONG
MmWorkingSetVolReductionMin = 12;
00136
00137 ULONG
MmWorkingSetVolReductionMax = 60;
00138 ULONG
MmWorkingSetVolReductionMaxCacheWs = 60;
00139
00140 ULONG
MmWorkingSetVolReductionHuge = (2*1024*1024) >>
PAGE_SHIFT;
00141
00142 ULONG
MmWorkingSetSwapReduction = 75;
00143
00144 ULONG
MmWorkingSetSwapReductionHuge = (4*1024*1024) >>
PAGE_SHIFT;
00145
00146 ULONG
MmNumberOfForegroundProcesses;
00147
00148
#ifdef _MI_USE_CLAIMS_
00149
00150 ULONG MiAgingShift = 4;
00151 ULONG MiEstimationShift = 5;
00152 ULONG MmTotalClaim = 0;
00153 ULONG MmTotalEstimatedAvailable = 0;
00154
00155 LARGE_INTEGER MiLastAdjustmentOfClaimParams;
00156 LARGE_INTEGER MmClaimParameterAdjustUpTime = {60 * 1000 * 1000 * 10, 0};
00157 LARGE_INTEGER MmClaimParameterAdjustDownTime = {20 * 1000 * 1000 * 10, 0};
00158
00159 ULONG MmPlentyFreePages = 400;
00160
00161
#else
00162
00163 ULONG
MiCheckCounter;
00164 ULONG
MmLastFaultCount;
00165
00166
#endif
00167
00168
#if DBG
00169
PETHREAD MmWorkingSetThread;
00170
#endif
00171
00172 extern PVOID
MmPagableKernelStart;
00173 extern PVOID
MmPagableKernelEnd;
00174
00175 PERFINFO_WSMANAGE_GLOBAL_DECL;
00176
00177 typedef union _MMWS_TRIM_CRITERIA {
00178
#ifdef _MI_USE_CLAIMS_
00179
struct {
00180 ULONG
NumPasses;
00181 PFN_NUMBER
DesiredFreeGoal;
00182 PFN_NUMBER NewTotalClaim;
00183 PFN_NUMBER NewTotalEstimatedAvailable;
00184 ULONG TrimAge;
00185 BOOLEAN DoAging;
00186 ULONG
NumberOfForegroundProcesses;
00187 } ClaimBased;
00188
#else
00189
struct {
00190 ULONG
NumPasses;
00191 PFN_NUMBER
DesiredFreeGoal;
00192 PFN_NUMBER
DesiredReductionGoal;
00193 ULONG
FaultCount;
00194 PFN_NUMBER
TotalReduction;
00195 ULONG
NumberOfForegroundProcesses;
00196 } FaultBased;
00197
#endif
00198
}
MMWS_TRIM_CRITERIA, *
PMMWS_TRIM_CRITERIA;
00199
00200 LOGICAL
00201
MiCheckAndSetSystemTrimCriteria(
00202 IN OUT PMMWS_TRIM_CRITERIA Criteria
00203 );
00204
00205 BOOLEAN
00206
MiCheckSystemTrimEndCriteria(
00207 IN OUT PMMWS_TRIM_CRITERIA Criteria,
00208 IN KIRQL OldIrql
00209 );
00210
00211 BOOLEAN
00212
MiCheckProcessTrimCriteria(
00213 IN PMMWS_TRIM_CRITERIA Criteria,
00214 IN
PMMSUPPORT VmSupport,
00215 IN
PEPROCESS Process,
00216 IN PLARGE_INTEGER CurrentTime
00217 );
00218
00219
#ifndef _MI_USE_CLAIMS_
00220
LOGICAL
00221
MiCheckSystemCacheWsTrimCriteria(
00222 IN
PMMSUPPORT VmSupport
00223 );
00224
#endif
00225
00226 ULONG
00227
MiDetermineWsTrimAmount(
00228 IN PMMWS_TRIM_CRITERIA Criteria,
00229 IN
PMMSUPPORT VmSupport,
00230 IN
PEPROCESS Process
00231 );
00232
00233
#ifdef _MI_USE_CLAIMS_
00234
VOID
00235 MiAgePagesAndEstimateClaims(
00236 VOID
00237 );
00238
00239
VOID
00240 MiAdjustClaimParameters(
00241 IN BOOLEAN EnoughPages
00242 );
00243
00244
VOID
00245 MiAgeAndEstimateAvailableInWorkingSet(
00246 IN
PMMSUPPORT VmSupport,
00247 IN BOOLEAN DoAging,
00248 IN OUT PULONG TotalClaim,
00249 IN OUT PULONG TotalEstimatedAvailable
00250 );
00251
#endif
00252
00253
VOID
00254
MiRearrangeWorkingSetExpansionList(
00255 VOID
00256 );
00257
00258
VOID
00259 MiAdjustWorkingSetManagerParameters(
00260 BOOLEAN WorkStation
00261 )
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 {
00283
00284
#ifdef _MI_USE_CLAIMS_
00285
00286
if (WorkStation &&
MmNumberOfPhysicalPages <= 63*1024*1024/
PAGE_SIZE) {
00287 MiAgingShift = 4;
00288 MiEstimationShift = 5;
00289 }
00290
else {
00291 MiAgingShift = 5;
00292 MiEstimationShift = 6;
00293 }
00294
00295
if (
MmNumberOfPhysicalPages >= 63*1024*1024/
PAGE_SIZE) {
00296 MmPlentyFreePages *= 2;
00297 }
00298
#else
00299
00300
if (WorkStation && (
MmNumberOfPhysicalPages <= (31*1024*1024/
PAGE_SIZE))) {
00301
00302
00303
00304
00305
00306
00307
MiIdealPassFaultCountDisable = 45;
00308
00309
00310
00311
00312
00313
00314
00315
MmWorkingSetVolReductionMax = 100;
00316
MmWorkingSetReductionMax = 100;
00317
00318
00319
00320
00321
00322
00323
MmWorkingSetReductionMin = 40;
00324 }
00325
else {
00326
MiIdealPassFaultCountDisable = 15;
00327 }
00328
#endif
00329
00330
MiWaitingForWorkingSetEmpty =
FALSE;
00331
KeInitializeEvent (&
MiWaitForEmptyEvent, NotificationEvent,
TRUE);
00332 }
00333
00334
00335
VOID
00336 MiObtainFreePages (
00337 VOID
00338 )
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 {
00364
00365
00366
00367
00368
00369
00370
if ((
MmModifiedPageListHead.
Total >=
MmModifiedWriteClusterSize) ||
00371 (
MmModNoWriteInsert)) {
00372
00373
00374
00375
00376
00377
KeSetEvent (&
MmModifiedPageWriterEvent, 0,
FALSE);
00378 }
00379
00380
00381
00382
00383
00384
00385
if ((
MmPagesAboveWsMinimum >
MmPagesAboveWsThreshold) ||
00386 (
MmAvailablePages < 5)) {
00387
00388
00389
00390
00391
00392
KeSetEvent (&
MmWorkingSetManagerEvent, 0,
FALSE);
00393 }
00394 }
00395
00396
VOID
00397 MmWorkingSetManager (
00398 VOID
00399 )
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424 {
00425
00426
PEPROCESS CurrentProcess;
00427
PEPROCESS ProcessToTrim;
00428 PLIST_ENTRY ListEntry;
00429 LOGICAL Attached;
00430 ULONG Trim;
00431 KIRQL OldIrql;
00432
PMMSUPPORT VmSupport;
00433
PMMWSL WorkingSetList;
00434 LARGE_INTEGER CurrentTime;
00435 ULONG count;
00436 LOGICAL DoTrimming;
00437
PMM_SESSION_SPACE SessionSpace;
00438 LOGICAL InformSessionOfRelease;
00439
#if DBG
00440
ULONG LastTrimFaultCount;
00441
#endif // DBG
00442
MMWS_TRIM_CRITERIA TrimCriteria;
00443
PERFINFO_WSMANAGE_DECL();
00444
00445
#if DBG
00446
MmWorkingSetThread =
PsGetCurrentThread ();
00447
#endif
00448
00449
ASSERT (
MiHydra ==
FALSE ||
MmIsAddressValid (
MmSessionSpace) ==
FALSE);
00450
00451 CurrentProcess =
PsGetCurrentProcess ();
00452
00453 Trim = 0;
00454
00455
00456
00457
00458
00459
00460
00461
00462 DoTrimming =
MiCheckAndSetSystemTrimCriteria(&TrimCriteria);
00463
00464
if (DoTrimming) {
00465
00466 Attached = 0;
00467
00468
KeQuerySystemTime (&CurrentTime);
00469
00470
ASSERT (
MiHydra ==
FALSE ||
MmIsAddressValid (
MmSessionSpace) ==
FALSE);
00471
00472
LOCK_EXPANSION (OldIrql);
00473
while (!IsListEmpty (&
MmWorkingSetExpansionHead.
ListHead)) {
00474
00475
00476
00477
00478
00479 ListEntry = RemoveHeadList (&
MmWorkingSetExpansionHead.
ListHead);
00480
00481
if (ListEntry == &
MmSystemCacheWs.
WorkingSetExpansionLinks) {
00482 VmSupport = &
MmSystemCacheWs;
00483
ASSERT (VmSupport->
u.Flags.SessionSpace == 0);
00484
ASSERT (VmSupport->
u.Flags.TrimHard == 0);
00485 SessionSpace =
NULL;
00486 }
00487
else {
00488 VmSupport = CONTAINING_RECORD(ListEntry,
00489
MMSUPPORT,
00490 WorkingSetExpansionLinks);
00491
00492
if (VmSupport->
u.Flags.SessionSpace == 0) {
00493 ProcessToTrim = CONTAINING_RECORD(VmSupport,
00494
EPROCESS,
00495 Vm);
00496
00497
ASSERT (VmSupport == &ProcessToTrim->
Vm);
00498
ASSERT (ProcessToTrim->
AddressSpaceDeleted == 0);
00499 SessionSpace =
NULL;
00500 }
00501
else {
00502
ASSERT (
MiHydra ==
TRUE);
00503 SessionSpace = CONTAINING_RECORD(VmSupport,
00504
MM_SESSION_SPACE,
00505 Vm);
00506 }
00507 }
00508
00509
00510
00511
00512
00513
00514
ASSERT (VmSupport->
u.Flags.BeingTrimmed == 0);
00515
00516
00517
00518
00519
00520
if ((*(PLARGE_INTEGER)&VmSupport->
LastTrimTime).QuadPart ==
00521 (*(PLARGE_INTEGER)&CurrentTime).QuadPart) {
00522
00523 InsertHeadList (&
MmWorkingSetExpansionHead.
ListHead,
00524 &VmSupport->
WorkingSetExpansionLinks);
00525
00526
00527
00528
00529
00530
if (
MiCheckSystemTrimEndCriteria(&TrimCriteria, OldIrql)) {
00531
00532
00533
00534
00535
00536
break;
00537 }
00538
00539
00540
00541
00542
00543
KeQuerySystemTime (&CurrentTime);
00544
00545
continue;
00546 }
00547
00548
PERFINFO_WSMANAGE_TRIMWS(ProcessToTrim, SessionSpace, VmSupport);
00549
00550
if (SessionSpace) {
00551
00552
if (
MiCheckProcessTrimCriteria(&TrimCriteria,
00553 VmSupport,
00554
NULL,
00555 &CurrentTime) ==
FALSE) {
00556
00557 InsertTailList (&
MmWorkingSetExpansionHead.
ListHead,
00558 &VmSupport->
WorkingSetExpansionLinks);
00559
continue;
00560 }
00561
00562 VmSupport->
LastTrimTime = CurrentTime;
00563 VmSupport->
u.Flags.BeingTrimmed = 1;
00564
00565 VmSupport->
WorkingSetExpansionLinks.Flink =
MM_NO_WS_EXPANSION;
00566 VmSupport->
WorkingSetExpansionLinks.Blink =
00567
MM_WS_EXPANSION_IN_PROGRESS;
00568
UNLOCK_EXPANSION (OldIrql);
00569
00570 ProcessToTrim =
NULL;
00571
00572
00573
00574
00575
00576
MiAttachSession (SessionSpace);
00577
00578
00579
00580
00581
00582 WorkingSetList = VmSupport->
VmWorkingSetList;
00583
00584
KeRaiseIrql (
APC_LEVEL, &OldIrql);
00585
00586
if (!
ExTryToAcquireResourceExclusiveLite (&SessionSpace->
WsLock)) {
00587
00588
00589
00590
00591
00592
KeLowerIrql (OldIrql);
00593
00594
MiDetachSession ();
00595
00596
LOCK_EXPANSION (OldIrql);
00597
00598
ASSERT (VmSupport->
u.Flags.BeingTrimmed == 1);
00599
00600 VmSupport->
u.Flags.BeingTrimmed = 0;
00601
00602 VmSupport->
AllowWorkingSetAdjustment =
MM_FORCE_TRIM;
00603
00604
goto WorkingSetLockFailed;
00605 }
00606
00607 VmSupport->
LastTrimFaultCount = VmSupport->
PageFaultCount;
00608
00609
MM_SET_SESSION_RESOURCE_OWNER();
00610
PERFINFO_WSMANAGE_PROCESS_RESET(VmSupport);
00611 }
00612
else if (VmSupport != &
MmSystemCacheWs) {
00613
00614
00615
00616
00617
00618
00619
00620
if (
MiCheckProcessTrimCriteria(&TrimCriteria,
00621 VmSupport,
00622 ProcessToTrim,
00623 &CurrentTime) ==
FALSE) {
00624
00625 InsertTailList (&
MmWorkingSetExpansionHead.
ListHead,
00626 &VmSupport->
WorkingSetExpansionLinks);
00627
continue;
00628 }
00629
00630 VmSupport->
LastTrimTime = CurrentTime;
00631 VmSupport->
u.Flags.BeingTrimmed = 1;
00632
00633 VmSupport->
WorkingSetExpansionLinks.Flink =
MM_NO_WS_EXPANSION;
00634 VmSupport->
WorkingSetExpansionLinks.Blink =
00635
MM_WS_EXPANSION_IN_PROGRESS;
00636
UNLOCK_EXPANSION (OldIrql);
00637 WorkingSetList =
MmWorkingSetList;
00638 InformSessionOfRelease =
FALSE;
00639
00640
00641
00642
00643
00644
if (ProcessToTrim != CurrentProcess) {
00645
00646 Attached =
KeForceAttachProcess (&ProcessToTrim->
Pcb);
00647
00648
if (Attached == 0) {
00649
LOCK_EXPANSION (OldIrql);
00650 VmSupport->
u.Flags.BeingTrimmed = 0;
00651 VmSupport->
AllowWorkingSetAdjustment =
MM_FORCE_TRIM;
00652
goto WorkingSetLockFailed;
00653 }
00654
if (ProcessToTrim->
ProcessOutswapEnabled ==
TRUE) {
00655
ASSERT (ProcessToTrim->
ProcessOutswapped ==
FALSE);
00656
if (
MiHydra ==
TRUE && VmSupport->
u.Flags.ProcessInSession == 1 && VmSupport->
u.Flags.SessionLeader == 0) {
00657 InformSessionOfRelease =
TRUE;
00658 }
00659 }
00660 }
00661
00662
00663
00664
00665
00666
00667 count = 0;
00668
do {
00669
if (ExTryToAcquireFastMutex(&ProcessToTrim->
WorkingSetLock) !=
FALSE) {
00670
break;
00671 }
00672
KeDelayExecutionThread (
KernelMode,
FALSE, &
MmShortTime);
00673 count += 1;
00674
if (count == 5) {
00675
00676
00677
00678
00679
00680
if (InformSessionOfRelease ==
TRUE) {
00681
LOCK_EXPANSION (OldIrql);
00682
ASSERT (ProcessToTrim->
ProcessOutswapEnabled ==
TRUE);
00683 ProcessToTrim->
ProcessOutswapEnabled =
FALSE;
00684
ASSERT (
MmSessionSpace->
ProcessOutSwapCount >= 1);
00685
MmSessionSpace->
ProcessOutSwapCount -= 1;
00686
UNLOCK_EXPANSION (OldIrql);
00687 InformSessionOfRelease =
FALSE;
00688 }
00689
00690
if (Attached) {
00691
KeDetachProcess ();
00692 Attached = 0;
00693 }
00694
00695
LOCK_EXPANSION (OldIrql);
00696 VmSupport->
u.Flags.BeingTrimmed = 0;
00697 VmSupport->
AllowWorkingSetAdjustment =
MM_FORCE_TRIM;
00698
goto WorkingSetLockFailed;
00699 }
00700 }
while (
TRUE);
00701
00702
ASSERT (VmSupport->
u.Flags.BeingTrimmed == 1);
00703
00704
#if DBG
00705
LastTrimFaultCount = VmSupport->
LastTrimFaultCount;
00706
#endif // DBG
00707
VmSupport->
LastTrimFaultCount = VmSupport->
PageFaultCount;
00708
00709
PERFINFO_WSMANAGE_PROCESS_RESET(VmSupport);
00710 }
00711
else {
00712
00713
00714
00715
00716
00717
#if DBG
00718
LastTrimFaultCount = VmSupport->
LastTrimFaultCount;
00719
#endif // DBG
00720
00721
PERFINFO_WSMANAGE_PROCESS_RESET(VmSupport);
00722
00723
00724
00725
00726
00727
00728
#ifndef _MI_USE_CLAIMS_
00729
00730
if (!
MiCheckSystemCacheWsTrimCriteria(VmSupport)) {
00731
00732
00733
00734
00735
00736 InsertTailList (&
MmWorkingSetExpansionHead.
ListHead,
00737 &VmSupport->
WorkingSetExpansionLinks);
00738
continue;
00739 }
00740
#endif
00741
00742 VmSupport->
LastTrimTime = CurrentTime;
00743
00744
00745
00746
00747
00748 VmSupport->
u.Flags.BeingTrimmed = 1;
00749
00750
UNLOCK_EXPANSION (OldIrql);
00751
00752 ProcessToTrim =
NULL;
00753 WorkingSetList =
MmSystemCacheWorkingSetList;
00754
00755
KeRaiseIrql (
APC_LEVEL, &OldIrql);
00756
if (!
ExTryToAcquireResourceExclusiveLite (&
MmSystemWsLock)) {
00757
00758
00759
00760
00761
00762
00763
KeLowerIrql (OldIrql);
00764
LOCK_EXPANSION (OldIrql);
00765 VmSupport->
u.Flags.BeingTrimmed = 0;
00766 InsertTailList (&
MmWorkingSetExpansionHead.
ListHead,
00767 &VmSupport->
WorkingSetExpansionLinks);
00768
continue;
00769 }
00770
00771
MmSystemLockOwner =
PsGetCurrentThread();
00772
00773 VmSupport->
LastTrimFaultCount = VmSupport->
PageFaultCount;
00774
00775 VmSupport->
WorkingSetExpansionLinks.Flink =
MM_NO_WS_EXPANSION;
00776 VmSupport->
WorkingSetExpansionLinks.Blink =
00777
MM_WS_EXPANSION_IN_PROGRESS;
00778 }
00779
00780
00781
00782
00783
00784 Trim =
MiDetermineWsTrimAmount(&TrimCriteria,
00785 VmSupport,
00786 ProcessToTrim
00787 );
00788
00789
#if DBG
00790
if (MmDebug &
MM_DBG_WS_EXPANSION) {
00791
if (Trim) {
00792
if (VmSupport->
u.Flags.SessionSpace == 0) {
00793
DbgPrint(
" Trimming Process %16s %5d Faults, WS %6d, Trimming %5d ==> %5d\n",
00794 ProcessToTrim ? ProcessToTrim->
ImageFileName : (PUCHAR)
"System Cache",
00795 VmSupport->
PageFaultCount - LastTrimFaultCount,
00796 VmSupport->
WorkingSetSize,
00797 Trim,
00798 VmSupport->
WorkingSetSize-Trim
00799 );
00800 }
00801
else {
00802
DbgPrint(
" Trimming Session 0x%x (id %d) %5d Faults, WS %6d, Trimming %5d ==> %5d\n",
00803 SessionSpace,
00804 SessionSpace->
SessionId,
00805 VmSupport->
PageFaultCount - LastTrimFaultCount,
00806 VmSupport->
WorkingSetSize,
00807 Trim,
00808 VmSupport->
WorkingSetSize-Trim
00809 );
00810 }
00811 }
00812 }
00813
#endif //DBG
00814
00815
#ifdef _MI_USE_CLAIMS_
00816
00817
00818
00819
00820
00821
if (Trim != 0 &&
00822 (
MmAvailablePages < TrimCriteria.ClaimBased.
DesiredFreeGoal)) {
00823
00824
00825
00826
00827
00828
PERFINFO_WSMANAGE_TOTRIM(Trim);
00829
00830 Trim =
MiTrimWorkingSet (Trim,
00831 VmSupport,
00832 TrimCriteria.ClaimBased.TrimAge
00833 );
00834
00835
PERFINFO_WSMANAGE_ACTUALTRIM(Trim);
00836 }
00837
00838
00839
00840
00841
00842
00843
00844 MiAgeAndEstimateAvailableInWorkingSet(
00845 VmSupport,
00846 TrimCriteria.ClaimBased.DoAging,
00847 &TrimCriteria.ClaimBased.NewTotalClaim,
00848 &TrimCriteria.ClaimBased.NewTotalEstimatedAvailable
00849 );
00850
#else
00851
if (Trim != 0) {
00852
00853
PERFINFO_WSMANAGE_TOTRIM(Trim);
00854
00855 Trim =
MiTrimWorkingSet (
00856 Trim,
00857 VmSupport,
00858 (BOOLEAN)(
MiCheckCounter <
MM_TRIM_COUNTER_MAXIMUM_LARGE_MEM)
00859 );
00860
00861
PERFINFO_WSMANAGE_ACTUALTRIM(Trim);
00862 }
00863
#endif
00864
00865
00866
00867
00868
00869 WorkingSetList->
Quota = VmSupport->
WorkingSetSize;
00870
if (WorkingSetList->
Quota < VmSupport->
MinimumWorkingSetSize) {
00871 WorkingSetList->
Quota = VmSupport->
MinimumWorkingSetSize;
00872 }
00873
00874
if (SessionSpace) {
00875
00876
ASSERT (VmSupport->
u.Flags.SessionSpace == 1);
00877
00878
UNLOCK_SESSION_SPACE_WS (OldIrql);
00879
00880
MiDetachSession ();
00881 }
00882
else if (VmSupport != &
MmSystemCacheWs) {
00883
00884
ASSERT (VmSupport->
u.Flags.SessionSpace == 0);
00885
UNLOCK_WS (ProcessToTrim);
00886
00887
if (InformSessionOfRelease ==
TRUE) {
00888
LOCK_EXPANSION (OldIrql);
00889
ASSERT (ProcessToTrim->
ProcessOutswapEnabled ==
TRUE);
00890 ProcessToTrim->
ProcessOutswapEnabled =
FALSE;
00891
ASSERT (
MmSessionSpace->
ProcessOutSwapCount >= 1);
00892
MmSessionSpace->
ProcessOutSwapCount -= 1;
00893
UNLOCK_EXPANSION (OldIrql);
00894 InformSessionOfRelease =
FALSE;
00895 }
00896
00897
if (Attached) {
00898
KeDetachProcess ();
00899 Attached = 0;
00900 }
00901
00902 }
00903
else {
00904
ASSERT (VmSupport->
u.Flags.SessionSpace == 0);
00905
UNLOCK_SYSTEM_WS (OldIrql);
00906 }
00907
00908
LOCK_EXPANSION (OldIrql);
00909
00910
ASSERT (VmSupport->
u.Flags.BeingTrimmed == 1);
00911 VmSupport->
u.Flags.BeingTrimmed = 0;
00912
00913 WorkingSetLockFailed:
00914
00915
ASSERT (VmSupport->
WorkingSetExpansionLinks.Flink ==
MM_NO_WS_EXPANSION);
00916
00917
if (VmSupport->
WorkingSetExpansionLinks.Blink ==
00918
MM_WS_EXPANSION_IN_PROGRESS) {
00919
00920
00921
00922
00923
00924
00925 InsertTailList (&
MmWorkingSetExpansionHead.
ListHead,
00926 &VmSupport->
WorkingSetExpansionLinks);
00927 }
00928
else {
00929
00930
00931
00932
00933
00934
00935
ASSERT (VmSupport != &
MmSystemCacheWs);
00936
00937
KeSetEvent ((
PKEVENT)VmSupport->
WorkingSetExpansionLinks.Blink,
00938 0,
00939
FALSE);
00940 }
00941
00942
#ifndef _MI_USE_CLAIMS_
00943
TrimCriteria.
FaultBased.TotalReduction += Trim;
00944
00945
00946
00947
00948
00949 Trim = 0;
00950
00951
if (
MiCheckCounter <
MM_TRIM_COUNTER_MAXIMUM_LARGE_MEM) {
00952
if ((
MmAvailablePages > TrimCriteria.
FaultBased.DesiredFreeGoal) ||
00953 (TrimCriteria.
FaultBased.TotalReduction > TrimCriteria.
FaultBased.DesiredReductionGoal)) {
00954
00955
00956
00957
00958
00959
00960
PERFINFO_WSMANAGE_FINALACTION(WS_ACTION_AMPLE_PAGES_EXIST);
00961
break;
00962 }
00963 }
00964
#endif
00965
00966 }
00967
00968
#ifdef _MI_USE_CLAIMS_
00969
MmTotalClaim = TrimCriteria.ClaimBased.NewTotalClaim;
00970 MmTotalEstimatedAvailable = TrimCriteria.ClaimBased.NewTotalEstimatedAvailable;
00971
PERFINFO_WSMANAGE_TRIMEND_CLAIMS(&TrimCriteria);
00972
#else
00973
MiCheckCounter = 0;
00974
PERFINFO_WSMANAGE_TRIMEND_FAULTS(&TrimCriteria);
00975
#endif
00976
00977
UNLOCK_EXPANSION (OldIrql);
00978 }
00979
00980
00981
00982
00983
00984
00985
if ((
MmAvailablePages <
MmMinimumFreePages) ||
00986 (
MmModifiedPageListHead.
Total >=
MmModifiedPageMaximum)) {
00987
KeSetEvent (&
MmModifiedPageWriterEvent, 0,
FALSE);
00988 }
00989
00990
ASSERT (CurrentProcess ==
PsGetCurrentProcess ());
00991
00992
return;
00993 }
00994
00995 LOGICAL
00996 MiCheckAndSetSystemTrimCriteria(
00997 PMMWS_TRIM_CRITERIA Criteria
00998 )
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022 {
01023 PFN_NUMBER Available;
01024 ULONG PageFaultCount;
01025 KIRQL OldIrql;
01026 BOOLEAN InitiateTrim;
01027
01028
PERFINFO_WSMANAGE_DECL();
01029
01030
01031
01032
01033
01034
01035
if (
MiWaitingForWorkingSetEmpty ==
TRUE) {
01036
01037
MiEmptyAllWorkingSetsWorker ();
01038
01039
LOCK_EXPANSION (OldIrql);
01040
01041
KeSetEvent (&
MiWaitForEmptyEvent, 0,
FALSE);
01042
MiWaitingForWorkingSetEmpty =
FALSE;
01043
01044
UNLOCK_EXPANSION (OldIrql);
01045
01046
#ifdef _MI_USE_CLAIMS_
01047
MiReplacing =
FALSE;
01048
#endif
01049
01050
return FALSE;
01051 }
01052
01053
01054
01055
01056
01057
01058
LOCK_PFN (OldIrql);
01059 Available =
MmAvailablePages;
01060 PageFaultCount =
MmInfoCounters.
PageFaultCount;
01061
UNLOCK_PFN (OldIrql);
01062
01063
#ifdef _MI_USE_CLAIMS_
01064
PERFINFO_WSMANAGE_STARTLOG_CLAIMS();
01065
if (Available > MmPlentyFreePages && MiReplacing ==
FALSE) {
01066
01067
01068
01069
01070
01071
01072 MiAgePagesAndEstimateClaims ();
01073 MiAdjustClaimParameters (
TRUE);
01074
PERFINFO_WSMANAGE_TRIMACTION (WS_ACTION_RESET_COUNTER);
01075 }
01076
else {
01077
01078
01079
01080
01081
01082
01083
01084 Criteria->ClaimBased.
NumPasses = 0;
01085 Criteria->ClaimBased.
DesiredFreeGoal = MmPlentyFreePages +
01086 (MmPlentyFreePages / 2);
01087 Criteria->ClaimBased.NewTotalClaim = 0;
01088 Criteria->ClaimBased.NewTotalEstimatedAvailable = 0;
01089 Criteria->ClaimBased.
NumberOfForegroundProcesses = 0;
01090
01091
01092
01093
01094
01095
MiRearrangeWorkingSetExpansionList ();
01096
01097
#if DBG
01098
if (MmDebug &
MM_DBG_WS_EXPANSION) {
01099
DbgPrint(
"\nMM-wsmanage: Desired = %ld, Avail %ld\n",
01100 Criteria->ClaimBased.
DesiredFreeGoal,
MmAvailablePages);
01101 }
01102
#endif //DBG
01103
01104
PERFINFO_WSMANAGE_WILLTRIM_CLAIMS(Criteria);
01105
01106 MiReplacing =
FALSE;
01107
01108
return TRUE;
01109 }
01110
PERFINFO_WSMANAGE_DUMPENTRIES_CLAIMS();
01111
01112
01113
01114
01115
01116
01117
01118 InitiateTrim = MiReplacing;
01119
01120 MiReplacing =
FALSE;
01121
01122
return InitiateTrim;
01123
01124
#else
01125
01126
PERFINFO_WSMANAGE_STARTLOG_FAULTS();
01127
01128
if ((Available > (
MmNumberOfPhysicalPages >> 2)) ||
01129 ((Available >
MmMoreThanEnoughFreePages) &&
01130 ((PageFaultCount -
MmLastFaultCount) <
MM_REDUCE_FAULT_COUNT))) {
01131
01132
01133
01134
01135
01136
MiCheckCounter = 0;
01137
PERFINFO_WSMANAGE_TRIMACTION(WS_ACTION_RESET_COUNTER);
01138
01139 }
else if ((Available >
MmAmpleFreePages) &&
01140 ((PageFaultCount -
MmLastFaultCount) <
MM_IGNORE_FAULT_COUNT)) {
01141
01142
01143
01144
01145
01146 NOTHING;
01147
PERFINFO_WSMANAGE_TRIMACTION(WS_ACTION_NOTHING);
01148
01149 }
else if ((Available >
MmFreeGoal) &&
01150 (
MiCheckCounter <
MM_TRIM_COUNTER_MAXIMUM_LARGE_MEM)) {
01151
01152
01153
01154
01155
01156
MiCheckCounter += 1;
01157
PERFINFO_WSMANAGE_TRIMACTION(WS_ACTION_INCREMENT_COUNTER);
01158
01159 }
01160
else {
01161
01162
01163
01164
01165
01166 Criteria->
FaultBased.NumPasses = 0;
01167 Criteria->
FaultBased.TotalReduction = 0;
01168 Criteria->
FaultBased.NumberOfForegroundProcesses = 0;
01169
01170
01171
01172
01173
01174 Criteria->
FaultBased.DesiredReductionGoal =
MmPagesAboveWsMinimum >> 2;
01175
if (
MmPagesAboveWsMinimum > (
MmFreeGoal << 1)) {
01176 Criteria->
FaultBased.DesiredFreeGoal =
MmFreeGoal;
01177 }
01178
else {
01179 Criteria->
FaultBased.DesiredFreeGoal =
MmMinimumFreePages + 10;
01180 }
01181
01182
01183
01184
01185
01186
if (Available >
MmMoreThanEnoughFreePages) {
01187 Criteria->
FaultBased.FaultCount = 1;
01188 }
01189
else {
01190 Criteria->
FaultBased.FaultCount =
MiIdealPassFaultCountDisable;
01191 }
01192
01193
#if DBG
01194
if (MmDebug &
MM_DBG_WS_EXPANSION) {
01195
DbgPrint(
"\nMM-wsmanage: checkcounter = %ld, Desired = %ld, Free = %ld Avail %ld\n",
01196
MiCheckCounter, Criteria->
FaultBased.DesiredReductionGoal,
01197 Criteria->
FaultBased.DesiredFreeGoal,
MmAvailablePages);
01198 }
01199
#endif //DBG
01200
01201
PERFINFO_WSMANAGE_WILLTRIM_FAULTS(Criteria);
01202
01203
if (
MiHydra ==
TRUE) {
01204
MiRearrangeWorkingSetExpansionList ();
01205 }
01206
01207
MmLastFaultCount = PageFaultCount;
01208
01209
return TRUE;
01210 }
01211
PERFINFO_WSMANAGE_DUMPENTRIES_FAULTS();
01212
01213
return FALSE;
01214
#endif
01215
}
01216
01217 BOOLEAN
01218 MiCheckSystemTrimEndCriteria(
01219 IN PMMWS_TRIM_CRITERIA Criteria,
01220 IN KIRQL OldIrql
01221 )
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247 {
01248 BOOLEAN FinishedTrimming;
01249
PERFINFO_WSMANAGE_DECL();
01250
01251 FinishedTrimming =
FALSE;
01252
01253
#ifdef _MI_USE_CLAIMS_
01254
if ((
MmAvailablePages > Criteria->ClaimBased.DesiredFreeGoal) ||
01255 (Criteria->ClaimBased.NumPasses >=
MI_MAX_TRIM_PASSES)) {
01256
01257
01258
01259
01260
01261 FinishedTrimming =
TRUE;
01262 }
01263
else {
01264
01265
01266
01267
01268
01269 MmTotalClaim = Criteria->ClaimBased.NewTotalClaim;
01270 MmTotalEstimatedAvailable = Criteria->ClaimBased.NewTotalEstimatedAvailable;
01271 }
01272
#else
01273
if (
MmAvailablePages >
MmMinimumFreePages) {
01274
01275
01276
01277
01278
01279
01280
MmNumberOfForegroundProcesses = Criteria->FaultBased.NumberOfForegroundProcesses;
01281
01282 FinishedTrimming =
TRUE;
01283 }
01284
#endif
01285
01286
if (FinishedTrimming ==
FALSE) {
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
UNLOCK_EXPANSION (OldIrql);
01299
01300
KeDelayExecutionThread (
KernelMode,
01301
FALSE,
01302 &
MmShortTime);
01303
01304
#ifdef _MI_USE_CLAIMS_
01305
PERFINFO_WSMANAGE_WAITFORWRITER_CLAIMS();
01306
#else
01307
PERFINFO_WSMANAGE_WAITFORWRITER_FAULTS();
01308
#endif
01309
01310
01311
01312
01313
01314
#ifdef _MI_USE_CLAIMS_
01315
if (
MmAvailablePages > Criteria->ClaimBased.DesiredFreeGoal) {
01316
01317
01318
01319
01320
01321 FinishedTrimming =
TRUE;
01322 }
01323
else {
01324
01325
01326
01327
01328
01329
01330
01331
if (Criteria->ClaimBased.NumPasses == 0) {
01332 MiAdjustClaimParameters(
FALSE);
01333 }
01334
01335 Criteria->ClaimBased.NumPasses += 1;
01336 Criteria->ClaimBased.NewTotalClaim = 0;
01337 Criteria->ClaimBased.NewTotalEstimatedAvailable = 0;
01338
01339
PERFINFO_WSMANAGE_TRIMACTION(WS_ACTION_FORCE_TRIMMING_PROCESS);
01340 }
01341
#else
01342
01343
if (
MmAvailablePages >
MmMinimumFreePages) {
01344
01345
01346
01347
01348
01349 FinishedTrimming =
TRUE;
01350 }
01351
else {
01352
01353
01354
01355
01356
01357
01358
PERFINFO_WSMANAGE_TRIMACTION(WS_ACTION_FORCE_TRIMMING_PROCESS);
01359
01360
MiCheckCounter = 0;
01361 Criteria->FaultBased.NumPasses += 1;
01362 }
01363
#endif
01364
01365
LOCK_EXPANSION (OldIrql);
01366 }
01367
01368
return FinishedTrimming;
01369 }
01370
01371 BOOLEAN
01372 MiCheckProcessTrimCriteria(
01373 PMMWS_TRIM_CRITERIA Criteria,
01374
PMMSUPPORT VmSupport,
01375
PEPROCESS Process,
01376 PLARGE_INTEGER CurrentTime
01377 )
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405 {
01406 BOOLEAN Trim;
01407 BOOLEAN Reset;
01408 BOOLEAN Responsive;
01409
01410
#if DBG
01411
if (Process) {
01412
ASSERT (VmSupport->
u.Flags.SessionSpace == 0);
01413 }
01414
else {
01415
ASSERT (VmSupport->
u.Flags.SessionSpace == 1);
01416 }
01417
#endif
01418
01419
if (VmSupport->
u.Flags.TrimHard == 1 && VmSupport->
WorkingSetSize) {
01420
return TRUE;
01421 }
01422
01423
#ifdef _MI_USE_CLAIMS_
01424
01425
01426
01427
01428
01429
01430
01431
if (VmSupport->
WorkingSetSize <= 3) {
01432
return FALSE;
01433 }
01434
01435
return TRUE;
01436
#else
01437
01438 Trim =
TRUE;
01439 Reset =
FALSE;
01440
01441
if (Process && Process->
Vm.
MemoryPriority ==
MEMORY_PRIORITY_FOREGROUND && Criteria->
FaultBased.NumPasses == 0) {
01442
01443 Criteria->
FaultBased.NumberOfForegroundProcesses += 1;
01444 }
01445
01446
if (
MiCheckCounter >=
MM_TRIM_COUNTER_MAXIMUM_LARGE_MEM) {
01447
01448
01449
01450
01451
01452
01453
01454
01455
if (((VmSupport->
PageFaultCount - VmSupport->
LastTrimFaultCount) >
01456 Criteria->
FaultBased.FaultCount)
01457 ||
01458 (VmSupport->
WorkingSetSize <= 5)
01459
01460 ||
01461 ((CurrentTime->QuadPart - VmSupport->
LastTrimTime.QuadPart) <
01462
MmWorkingSetProtectionTime.QuadPart)) {
01463
01464
#if DBG
01465
if (MmDebug &
MM_DBG_WS_EXPANSION) {
01466
if (VmSupport->
WorkingSetSize > 5) {
01467
01468
if (Process) {
01469
DbgPrint(
" ***** Skipping Process %16s %5d Faults, WS %6d\n",
01470 Process->
ImageFileName,
01471 VmSupport->
PageFaultCount - VmSupport->
LastTrimFaultCount,
01472 VmSupport->
WorkingSetSize
01473 );
01474 }
01475
else {
01476
PMM_SESSION_SPACE SessionSpace;
01477
01478
ASSERT (
MiHydra ==
TRUE);
01479 SessionSpace = CONTAINING_RECORD(VmSupport,
01480
MM_SESSION_SPACE,
01481 Vm);
01482
01483
DbgPrint(
" ***** Skipping Session %d %5d Faults, WS %6d\n",
01484 SessionSpace->
SessionId,
01485 VmSupport->
PageFaultCount - VmSupport->
LastTrimFaultCount,
01486 VmSupport->
WorkingSetSize
01487 );
01488 }
01489 }
01490 }
01491
#endif //DBG
01492
01493 Reset =
TRUE;
01494 Trim =
FALSE;
01495 }
01496 }
else {
01497
01498
01499
01500
01501
01502
01503
if (VmSupport->
WorkingSetSize <= VmSupport->
MinimumWorkingSetSize) {
01504
01505
01506
01507
01508
01509
01510
if (((
MmAvailablePages + 5) >=
MmFreeGoal) &&
01511 (((VmSupport->
LastTrimFaultCount !=
01512 VmSupport->
PageFaultCount) ||
01513 (Process && Process->
ProcessOutswapEnabled ==
FALSE)))) {
01514
01515
01516
01517
01518
01519
01520
01521 Reset =
TRUE;
01522 Trim =
FALSE;
01523 }
01524
else if ((VmSupport->
WorkingSetSize < 5) ||
01525 ((CurrentTime->QuadPart - VmSupport->
LastTrimTime.QuadPart) <
01526
MmWorkingSetProtectionTime.QuadPart)) {
01527
01528
01529
01530
01531
01532
01533 Reset =
TRUE;
01534 Trim =
FALSE;
01535 }
01536 }
01537 }
01538
01539
if (Trim ==
TRUE) {
01540
01541
01542
01543
01544
01545
01546 Responsive =
FALSE;
01547
01548
if ((
MmNumberOfForegroundProcesses <= 3) &&
01549 (Criteria->
FaultBased.NumberOfForegroundProcesses <= 3) &&
01550 (VmSupport->
MemoryPriority)) {
01551
01552
if ((
MmAvailablePages > (
MmMoreThanEnoughFreePages >> 2)) ||
01553 (VmSupport->
MemoryPriority >=
MEMORY_PRIORITY_FOREGROUND)) {
01554
01555
01556
01557
01558
01559
01560 Responsive =
TRUE;
01561 }
01562 }
01563
01564
if (Responsive ==
TRUE && Criteria->
FaultBased.NumPasses == 0) {
01565
01566
01567
01568
01569
01570
01571
01572 Trim =
FALSE;
01573 }
01574 }
01575
01576
if (Trim ==
FALSE) {
01577
if (Reset ==
TRUE) {
01578 VmSupport->
LastTrimTime = *CurrentTime;
01579 VmSupport->
LastTrimFaultCount = VmSupport->
PageFaultCount;
01580 }
01581
01582
PERFINFO_WSMANAGE_PROCESS_RESET(VmSupport);
01583 }
01584
01585
return Trim;
01586
#endif
01587
}
01588
#ifndef _MI_USE_CLAIMS_
01589
01590 LOGICAL
01591 MiCheckSystemCacheWsTrimCriteria(
01592
PMMSUPPORT VmSupport
01593 )
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615 {
01616 LOGICAL Trim;
01617
01618
01619
01620
01621
01622
01623
01624
if ((
MiCheckCounter >=
MM_TRIM_COUNTER_MAXIMUM_LARGE_MEM) &&
01625 (((LONG)VmSupport->
WorkingSetSize -
01626 (LONG)VmSupport->
MinimumWorkingSetSize) < 100)) {
01627
01628
01629
01630
01631
01632 Trim =
FALSE;
01633 }
01634
else {
01635 Trim =
TRUE;
01636 }
01637
01638
return Trim;
01639 }
01640
#endif
01641
01642
01643 ULONG
01644 MiDetermineWsTrimAmount(
01645 PMMWS_TRIM_CRITERIA Criteria,
01646
PMMSUPPORT VmSupport,
01647
PEPROCESS Process
01648 )
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674 {
01675
PMMWSL WorkingSetList;
01676 ULONG MaxTrim;
01677 ULONG Trim;
01678 BOOLEAN OutswapEnabled;
01679
01680
if (Process) {
01681 OutswapEnabled = Process->
ProcessOutswapEnabled;
01682 }
01683
else {
01684
if (VmSupport->
u.Flags.TrimHard == 1) {
01685 OutswapEnabled =
TRUE;
01686 }
01687
else {
01688 OutswapEnabled =
FALSE;
01689 }
01690 }
01691
01692 WorkingSetList = VmSupport->
VmWorkingSetList;
01693
01694
if (VmSupport->
WorkingSetSize <= WorkingSetList->
FirstDynamic) {
01695
return 0;
01696 }
01697
01698
#ifdef _MI_USE_CLAIMS_
01699
MaxTrim = VmSupport->
WorkingSetSize;
01700
01701
if (OutswapEnabled ==
FALSE) {
01702
01703
01704
01705
01706
01707
01708 MaxTrim -= VmSupport->
MinimumWorkingSetSize;
01709 }
01710
01711
switch (Criteria->ClaimBased.
NumPasses) {
01712
case 0:
01713 Trim = VmSupport->
Claim >>
01714 ((VmSupport->
MemoryPriority ==
MEMORY_PRIORITY_FOREGROUND)
01715 ?
MI_FOREGROUND_CLAIM_AVAILABLE_SHIFT
01716 :
MI_BACKGROUND_CLAIM_AVAILABLE_SHIFT);
01717 Criteria->ClaimBased.TrimAge =
MI_PASS0_TRIM_AGE;
01718 Criteria->ClaimBased.DoAging =
TRUE;
01719
break;
01720
case 1:
01721 Trim = VmSupport->
Claim >>
01722 ((VmSupport->
MemoryPriority ==
MEMORY_PRIORITY_FOREGROUND)
01723 ?
MI_FOREGROUND_CLAIM_AVAILABLE_SHIFT
01724 :
MI_BACKGROUND_CLAIM_AVAILABLE_SHIFT);
01725 Criteria->ClaimBased.TrimAge =
MI_PASS1_TRIM_AGE;
01726 Criteria->ClaimBased.DoAging =
FALSE;
01727
break;
01728
case 2:
01729 Trim = VmSupport->
Claim;
01730 Criteria->ClaimBased.TrimAge =
MI_PASS2_TRIM_AGE;
01731 Criteria->ClaimBased.DoAging =
FALSE;
01732
break;
01733
case 3:
01734 Trim = VmSupport->
EstimatedAvailable;
01735 Criteria->ClaimBased.TrimAge =
MI_PASS3_TRIM_AGE;
01736 Criteria->ClaimBased.DoAging =
FALSE;
01737
break;
01738
default:
01739 Trim = VmSupport->
EstimatedAvailable;
01740 Criteria->ClaimBased.TrimAge =
MI_PASS3_TRIM_AGE;
01741 Criteria->ClaimBased.DoAging =
FALSE;
01742
01743
if (
MmAvailablePages < 100) {
01744
if (VmSupport->
WorkingSetSize > VmSupport->
MinimumWorkingSetSize) {
01745 Trim = (VmSupport->
WorkingSetSize - VmSupport->
MinimumWorkingSetSize) >> 2;
01746 }
01747 Criteria->ClaimBased.TrimAge =
MI_PASS4_TRIM_AGE;
01748 Criteria->ClaimBased.DoAging =
TRUE;
01749 }
01750
01751
break;
01752 }
01753
01754
if (Trim > MaxTrim) {
01755 Trim = MaxTrim;
01756 }
01757
01758
#else
01759
01760 UNREFERENCED_PARAMETER (Criteria);
01761
01762
01763
01764
01765
01766
if (VmSupport->
WorkingSetSize <= VmSupport->
MinimumWorkingSetSize &&
01767 OutswapEnabled ==
TRUE) {
01768
01769
01770
01771
01772
01773
01774 WorkingSetList->
Quota = VmSupport->
MinimumWorkingSetSize;
01775 Trim = VmSupport->
WorkingSetSize - WorkingSetList->
FirstDynamic;
01776
if (Trim >
MmWorkingSetSwapReduction) {
01777 Trim =
MmWorkingSetSwapReduction;
01778 }
01779
01780
ASSERT ((LONG)Trim >= 0);
01781
01782 }
else {
01783
01784 MaxTrim = VmSupport->
WorkingSetSize -
01785 VmSupport->
MinimumWorkingSetSize;
01786
01787
if (OutswapEnabled ==
TRUE) {
01788
01789
01790
01791
01792
01793
01794
01795 ULONG i;
01796
01797 Trim =
MmWorkingSetSwapReduction;
01798 i = VmSupport->
WorkingSetSize - VmSupport->
MaximumWorkingSetSize;
01799
if ((LONG)i > 0) {
01800 Trim = i;
01801
if (Trim >
MmWorkingSetSwapReductionHuge) {
01802 Trim =
MmWorkingSetSwapReductionHuge;
01803 }
01804 }
01805
01806 }
else if (
MiCheckCounter >=
MM_TRIM_COUNTER_MAXIMUM_LARGE_MEM) {
01807
01808
01809
01810
01811
01812
if (VmSupport->
WorkingSetSize >
01813 (VmSupport->
MaximumWorkingSetSize +
01814 (6 *
MmWorkingSetVolReductionHuge))) {
01815 Trim =
MmWorkingSetVolReductionHuge;
01816
01817 }
else if ( (VmSupport != &
MmSystemCacheWs) &&
01818 VmSupport->
WorkingSetSize >
01819 ( VmSupport->
MaximumWorkingSetSize + (2 *
MmWorkingSetReductionHuge))) {
01820 Trim =
MmWorkingSetReductionHuge;
01821 }
else if (VmSupport->
WorkingSetSize > VmSupport->
MaximumWorkingSetSize) {
01822
if (VmSupport != &
MmSystemCacheWs) {
01823 Trim =
MmWorkingSetVolReductionMax;
01824 }
else {
01825 Trim =
MmWorkingSetVolReductionMaxCacheWs;
01826 }
01827 }
else {
01828 Trim =
MmWorkingSetVolReductionMin;
01829 }
01830
01831 }
else {
01832
01833
if (VmSupport->
WorkingSetSize >
01834 (VmSupport->
MaximumWorkingSetSize +
01835 (2 *
MmWorkingSetReductionHuge))) {
01836 Trim =
MmWorkingSetReductionHuge;
01837
01838 }
else if (VmSupport->
WorkingSetSize > VmSupport->
MaximumWorkingSetSize) {
01839
if (VmSupport != &
MmSystemCacheWs) {
01840 Trim =
MmWorkingSetReductionMax;
01841 }
else {
01842 Trim =
MmWorkingSetReductionMaxCacheWs;
01843 }
01844 }
else {
01845
if (VmSupport != &
MmSystemCacheWs) {
01846 Trim =
MmWorkingSetReductionMin;
01847 }
else {
01848 Trim =
MmWorkingSetReductionMinCacheWs;
01849 }
01850 }
01851 }
01852
01853
if (MaxTrim < Trim) {
01854 Trim = MaxTrim;
01855 }
01856 }
01857
#endif
01858
01859
return Trim;
01860 }
01861
#ifdef _MI_USE_CLAIMS_
01862
01863
VOID
01864 MiAgePagesAndEstimateClaims(
01865 VOID
01866 )
01867
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890 {
01891
NTSTATUS status;
01892
PMMSUPPORT VmSupport;
01893
PMMSUPPORT FirstSeen;
01894 BOOLEAN SystemCacheSeen;
01895 LOGICAL Attached;
01896 BOOLEAN Locked;
01897 KIRQL OldIrql;
01898 PLIST_ENTRY ListEntry;
01899
PEPROCESS Process;
01900 ULONG NewTotalClaim;
01901 ULONG NewTotalEstimatedAvailable;
01902
PEPROCESS CurrentProcess;
01903
PMM_SESSION_SPACE SessionSpace;
01904 LOGICAL InformSessionOfRelease;
01905 ULONG LoopCount;
01906
01907 FirstSeen =
NULL;
01908 SystemCacheSeen =
FALSE;
01909 Attached = 0;
01910 Locked =
FALSE;
01911 NewTotalClaim = 0;
01912 NewTotalEstimatedAvailable = 0;
01913 status = STATUS_SUCCESS;
01914 LoopCount = 0;
01915
01916 CurrentProcess =
PsGetCurrentProcess ();
01917
01918
ASSERT (MiHydra == FALSE || MmIsAddressValid (MmSessionSpace) == FALSE);
01919
01920
LOCK_EXPANSION (OldIrql);
01921
01922
while (!IsListEmpty (&
MmWorkingSetExpansionHead.
ListHead)) {
01923
01924
01925
01926
01927
01928
01929 ListEntry = RemoveHeadList (&
MmWorkingSetExpansionHead.
ListHead);
01930
01931
ASSERT (MiHydra == FALSE || MmIsAddressValid (MmSessionSpace) == FALSE);
01932
01933
if (ListEntry == &
MmSystemCacheWs.
WorkingSetExpansionLinks) {
01934 VmSupport = &
MmSystemCacheWs;
01935 Process =
NULL;
01936
if (SystemCacheSeen !=
FALSE) {
01937
01938
01939
01940
01941
01942 FirstSeen = VmSupport;
01943 }
01944 SystemCacheSeen =
TRUE;
01945 }
01946
else {
01947 VmSupport = CONTAINING_RECORD(ListEntry,
01948
MMSUPPORT,
01949 WorkingSetExpansionLinks);
01950
01951
if (VmSupport->
u.Flags.SessionSpace == 0) {
01952
01953 Process = CONTAINING_RECORD(ListEntry,
01954
EPROCESS,
01955 Vm.WorkingSetExpansionLinks);
01956
ASSERT (Process->
AddressSpaceDeleted == 0);
01957
ASSERT (VmSupport->
VmWorkingSetList == MmWorkingSetList);
01958 }
01959
else {
01960
ASSERT (MiHydra == TRUE);
01961 SessionSpace = CONTAINING_RECORD(VmSupport,
01962
MM_SESSION_SPACE,
01963 Vm);
01964
01965 Process =
NULL;
01966 }
01967 }
01968
01969
ASSERT (VmSupport->
u.Flags.BeingTrimmed == 0);
01970
01971
if (VmSupport == FirstSeen) {
01972 InsertHeadList (&
MmWorkingSetExpansionHead.
ListHead,
01973 &VmSupport->
WorkingSetExpansionLinks);
01974
break;
01975 }
01976
01977 VmSupport->
u.Flags.BeingTrimmed = 1;
01978
01979
if (FirstSeen ==
NULL) {
01980 FirstSeen = VmSupport;
01981 }
01982
01983 VmSupport->
WorkingSetExpansionLinks.Flink =
MM_NO_WS_EXPANSION;
01984 VmSupport->
WorkingSetExpansionLinks.Blink =
01985
MM_WS_EXPANSION_IN_PROGRESS;
01986
UNLOCK_EXPANSION (OldIrql);
01987
01988 Locked =
FALSE;
01989
if (VmSupport == &
MmSystemCacheWs) {
01990
KeRaiseIrql (APC_LEVEL, &OldIrql);
01991
if (!
ExTryToAcquireResourceExclusiveLite (&MmSystemWsLock)) {
01992
KeLowerIrql (OldIrql);
01993
goto FailureBranch;
01994 }
01995
MmSystemLockOwner =
PsGetCurrentThread();
01996 Locked =
TRUE;
01997 }
01998
else if (VmSupport->
u.Flags.SessionSpace == 0) {
01999 InformSessionOfRelease =
FALSE;
02000
if (CurrentProcess != Process) {
02001 Attached =
KeForceAttachProcess(&Process->
Pcb);
02002
if (Attached == 0) {
02003
goto FailureBranch;
02004 }
02005
if (Process->
ProcessOutswapEnabled ==
TRUE) {
02006
ASSERT (Process->
ProcessOutswapped == FALSE);
02007
if (
MiHydra ==
TRUE && VmSupport->
u.Flags.ProcessInSession == 1 && VmSupport->
u.Flags.SessionLeader == 0) {
02008 InformSessionOfRelease =
TRUE;
02009 }
02010 }
02011 }
02012
if (ExTryToAcquireFastMutex(&Process->
WorkingSetLock) ==
FALSE) {
02013
02014
if (InformSessionOfRelease ==
TRUE) {
02015
LOCK_EXPANSION (OldIrql);
02016
ASSERT (Process->
ProcessOutswapEnabled == TRUE);
02017 Process->
ProcessOutswapEnabled =
FALSE;
02018
ASSERT (
MmSessionSpace->
ProcessOutSwapCount >= 1);
02019
MmSessionSpace->
ProcessOutSwapCount -= 1;
02020
UNLOCK_EXPANSION (OldIrql);
02021 InformSessionOfRelease =
FALSE;
02022 }
02023
02024
if (Attached) {
02025
KeDetachProcess ();
02026 Attached = 0;
02027 }
02028
goto FailureBranch;
02029 }
02030
02031 Locked =
TRUE;
02032 }
02033
else {
02034
02035
ASSERT (MiHydra == TRUE);
02036
02037
02038
02039
02040
02041
MiAttachSession (SessionSpace);
02042
02043
KeRaiseIrql (APC_LEVEL, &OldIrql);
02044
if (!
ExTryToAcquireResourceExclusiveLite (&SessionSpace->
WsLock)) {
02045
02046
02047
02048
02049
02050
02051
KeLowerIrql (OldIrql);
02052
02053
MiDetachSession ();
02054
02055
goto FailureBranch;
02056 }
02057
02058 Locked =
TRUE;
02059
02060
MM_SET_SESSION_RESOURCE_OWNER();
02061 }
02062
02063 FailureBranch:
02064
02065
if (Locked) {
02066 MiAgeAndEstimateAvailableInWorkingSet (VmSupport,
02067 TRUE,
02068 &NewTotalClaim,
02069 &NewTotalEstimatedAvailable
02070 );
02071
02072
if (VmSupport == &
MmSystemCacheWs) {
02073
ASSERT (VmSupport->
u.Flags.SessionSpace == 0);
02074
UNLOCK_SYSTEM_WS (OldIrql);
02075 }
02076
else if (VmSupport->
u.Flags.SessionSpace == 0) {
02077
02078
UNLOCK_WS (Process);
02079
02080
if (InformSessionOfRelease ==
TRUE) {
02081
LOCK_EXPANSION (OldIrql);
02082
ASSERT (Process->
ProcessOutswapEnabled == TRUE);
02083 Process->
ProcessOutswapEnabled =
FALSE;
02084
ASSERT (
MmSessionSpace->
ProcessOutSwapCount >= 1);
02085
MmSessionSpace->
ProcessOutSwapCount -= 1;
02086
UNLOCK_EXPANSION (OldIrql);
02087 InformSessionOfRelease =
FALSE;
02088 }
02089
02090
if (Attached) {
02091
KeDetachProcess ();
02092 Attached = 0;
02093 }
02094 }
02095
else {
02096
ASSERT (MiHydra == TRUE);
02097
UNLOCK_SESSION_SPACE_WS (OldIrql);
02098
02099
MiDetachSession ();
02100 }
02101 }
02102
02103
LOCK_EXPANSION (OldIrql);
02104
02105
ASSERT (VmSupport->
u.Flags.BeingTrimmed == 1);
02106 VmSupport->
u.Flags.BeingTrimmed = 0;
02107
02108
ASSERT (VmSupport->
WorkingSetExpansionLinks.Flink == MM_NO_WS_EXPANSION);
02109
if (VmSupport->
WorkingSetExpansionLinks.Blink ==
02110
MM_WS_EXPANSION_IN_PROGRESS) {
02111
02112
02113
02114
02115
02116
02117 InsertTailList (&
MmWorkingSetExpansionHead.
ListHead,
02118 &VmSupport->
WorkingSetExpansionLinks);
02119 }
02120
else {
02121
02122
02123
02124
02125
02126
02127
ASSERT (VmSupport != &MmSystemCacheWs);
02128
02129
KeSetEvent ((
PKEVENT)VmSupport->
WorkingSetExpansionLinks.Blink,
02130 0,
02131 FALSE);
02132 }
02133
02134
02135
02136
02137
02138
02139
02140
02141
02142 LoopCount += 1;
02143
if (LoopCount > 200) {
02144
if (
MmSystemCacheWs.
WorkingSetExpansionLinks.Blink ==
MM_WS_EXPANSION_IN_PROGRESS) {
02145
break;
02146 }
02147 }
02148 }
02149
02150
UNLOCK_EXPANSION(OldIrql);
02151
02152 MmTotalClaim = NewTotalClaim;
02153 MmTotalEstimatedAvailable = NewTotalEstimatedAvailable;
02154
02155 }
02156
02157
VOID
02158 MiAgeAndEstimateAvailableInWorkingSet(
02159 IN
PMMSUPPORT VmSupport,
02160 IN BOOLEAN DoAging,
02161 IN OUT PULONG TotalClaim,
02162 IN OUT PULONG TotalEstimatedAvailable
02163 )
02164
02165
02166
02167
02168
02169
02170
02171
02172
02173
02174
02175
02176
02177
02178
02179
02180
02181
02182
02183
02184
02185
02186
02187
02188
02189
02190
02191
02192
02193
02194
02195
02196
02197
02198
02199
02200 {
02201 ULONG LastEntry;
02202 ULONG StartEntry;
02203 ULONG FirstDynamic;
02204 ULONG CurrentEntry;
02205
PMMWSL WorkingSetList;
02206
PMMWSLE Wsle;
02207
PMMPTE PointerPte;
02208 ULONG NumberToExamine;
02209 ULONG Claim;
02210 ULONG Estimate;
02211 ULONG SampledAgeCounts[
MI_USE_AGE_COUNT] = {0};
02212
MI_NEXT_ESTIMATION_SLOT_CONST NextConst;
02213
02214 WorkingSetList = VmSupport->VmWorkingSetList;
02215 Wsle = WorkingSetList->
Wsle;
02216
02217
#if DBG
02218
if (VmSupport == &
MmSystemCacheWs) {
02219
MM_SYSTEM_WS_LOCK_ASSERT();
02220 }
02221
#endif //DBG
02222
02223 LastEntry = WorkingSetList->
LastEntry;
02224 FirstDynamic = WorkingSetList->
FirstDynamic;
02225
02226
if (DoAging ==
TRUE) {
02227
02228
02229
02230
02231
02232
02233
02234
02235
02236
if (VmSupport->WorkingSetSize > WorkingSetList->
FirstDynamic) {
02237 NumberToExamine = (VmSupport->WorkingSetSize - WorkingSetList->
FirstDynamic) >> MiAgingShift;
02238 }
02239
else {
02240 NumberToExamine = 0;
02241 }
02242
02243
if (NumberToExamine != 0) {
02244
02245 CurrentEntry = VmSupport->NextAgingSlot;
02246
02247
if (CurrentEntry > LastEntry || CurrentEntry < FirstDynamic) {
02248 CurrentEntry = FirstDynamic;
02249 }
02250
02251
if (Wsle[CurrentEntry].
u1.e1.Valid == 0) {
02252
MI_NEXT_VALID_AGING_SLOT(CurrentEntry, FirstDynamic, LastEntry, Wsle);
02253 }
02254
02255
while (NumberToExamine != 0) {
02256
02257 PointerPte =
MiGetPteAddress (Wsle[CurrentEntry].u1.VirtualAddress);
02258
02259
if (
MI_GET_ACCESSED_IN_PTE(PointerPte) == 1) {
02260
MI_SET_ACCESSED_IN_PTE(PointerPte, 0);
02261
MI_RESET_WSLE_AGE(PointerPte, &Wsle[CurrentEntry]);
02262 }
02263
else {
02264
MI_INC_WSLE_AGE(PointerPte, &Wsle[CurrentEntry]);
02265 }
02266
02267 NumberToExamine -= 1;
02268
MI_NEXT_VALID_AGING_SLOT(CurrentEntry, FirstDynamic, LastEntry, Wsle);
02269 }
02270
02271 VmSupport->NextAgingSlot = CurrentEntry + 1;
02272 }
02273 }
02274
02275
02276
02277
02278
02279
02280
02281
02282
02283 CurrentEntry = VmSupport->NextEstimationSlot;
02284
02285
if (CurrentEntry > LastEntry || CurrentEntry < FirstDynamic) {
02286 CurrentEntry = FirstDynamic;
02287 }
02288
02289
02290
02291
02292
02293
02294
if (VmSupport->WorkingSetSize > WorkingSetList->
FirstDynamic) {
02295 NumberToExamine = (VmSupport->WorkingSetSize - WorkingSetList->
FirstDynamic) >> MiEstimationShift;
02296 }
02297
else {
02298 NumberToExamine = 0;
02299 }
02300
02301
if (NumberToExamine != 0) {
02302
02303
MI_CALC_NEXT_ESTIMATION_SLOT_CONST(NextConst, WorkingSetList);
02304
02305 StartEntry = FirstDynamic;
02306
02307
if (Wsle[CurrentEntry].
u1.e1.Valid == 0) {
02308
02309
MI_NEXT_VALID_ESTIMATION_SLOT (CurrentEntry,
02310 StartEntry,
02311 FirstDynamic,
02312 LastEntry,
02313 NextConst,
02314 Wsle);
02315 }
02316
02317
while (NumberToExamine != 0) {
02318
02319 PointerPte =
MiGetPteAddress (Wsle[CurrentEntry].u1.VirtualAddress);
02320
02321
if (
MI_GET_ACCESSED_IN_PTE(PointerPte) == 0) {
02322
MI_UPDATE_USE_ESTIMATE(PointerPte,
02323 &Wsle[CurrentEntry],
02324 SampledAgeCounts
02325 );
02326 }
02327
02328 NumberToExamine -= 1;
02329
02330
MI_NEXT_VALID_ESTIMATION_SLOT (CurrentEntry,
02331 StartEntry,
02332 FirstDynamic,
02333 LastEntry,
02334 NextConst,
02335 Wsle);
02336 }
02337 }
02338
02339
02340
02341
02342
02343 VmSupport->NextEstimationSlot = CurrentEntry + 1;
02344
02345 Estimate =
MI_CALCULATE_USAGE_ESTIMATE(SampledAgeCounts);
02346
02347 Claim = VmSupport->Claim + MI_CLAIM_INCR;
02348
02349
if (Claim > Estimate) {
02350 Claim = Estimate;
02351 }
02352
02353 VmSupport->Claim = Claim;
02354 VmSupport->EstimatedAvailable = Estimate;
02355
02356
PERFINFO_WSMANAGE_DUMPWS(VmSupport, SampledAgeCounts);
02357
02358 VmSupport->GrowthSinceLastEstimate = 0;
02359 *TotalClaim += Claim >> ((VmSupport->MemoryPriority ==
MEMORY_PRIORITY_FOREGROUND)
02360 ?
MI_FOREGROUND_CLAIM_AVAILABLE_SHIFT
02361 :
MI_BACKGROUND_CLAIM_AVAILABLE_SHIFT);
02362
02363 *TotalEstimatedAvailable += Estimate;
02364
return;
02365 }
02366
02367 ULONG MiClaimAdjustmentThreshold[7] = { 0, 0, 0, 1000, 2000, 4000, 8000};
02368
02369
VOID
02370 MiAdjustClaimParameters(
02371 BOOLEAN EnoughPages
02372 )
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401
02402 {
02403 LARGE_INTEGER CurrentTime;
02404
02405
KeQuerySystemTime (&CurrentTime);
02406
02407
if (EnoughPages ==
TRUE) {
02408
02409
02410
02411
02412
02413
02414
if (((CurrentTime.QuadPart - MiLastAdjustmentOfClaimParams.QuadPart) >
02415 MmClaimParameterAdjustUpTime.QuadPart) &&
02416 (MiAgingShift < 7) &&
02417 ((MmTotalClaim +
MmAvailablePages) > MiClaimAdjustmentThreshold[MiAgingShift])) {
02418
02419
02420
02421
02422
02423 MiLastAdjustmentOfClaimParams.QuadPart = CurrentTime.QuadPart;
02424
02425 MiAgingShift += 1;
02426 MiEstimationShift += 1;
02427 }
02428 }
02429
else {
02430
02431
02432
02433
02434
02435
if ((CurrentTime.QuadPart - MiLastAdjustmentOfClaimParams.QuadPart) >
02436 MmClaimParameterAdjustDownTime.QuadPart) {
02437
02438
02439
02440
02441
02442
02443 MiLastAdjustmentOfClaimParams.QuadPart = CurrentTime.QuadPart;
02444
02445
02446
02447
02448
02449
if (MiAgingShift > 3) {
02450 MiAgingShift -= 1;
02451 MiEstimationShift -= 1;
02452 }
02453 }
02454 }
02455 }
02456
#endif
02457
02458 #define MM_WS_REORG_BUCKETS_MAX 7
02459
02460
#if DBG
02461
ULONG MiSessionIdleBuckets[
MM_WS_REORG_BUCKETS_MAX];
02462
#endif
02463
02464
VOID
02465 MiRearrangeWorkingSetExpansionList(
02466 VOID
02467 )
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495 {
02496 KIRQL OldIrql;
02497 PLIST_ENTRY ListEntry;
02498
PMMSUPPORT VmSupport;
02499
int Size;
02500
int PreviousNonEmpty;
02501
int NonEmpty;
02502 LIST_ENTRY ListHead[
MM_WS_REORG_BUCKETS_MAX];
02503 LARGE_INTEGER CurrentTime;
02504 LARGE_INTEGER SessionIdleTime;
02505 ULONG IdleTime;
02506
PMM_SESSION_SPACE SessionGlobal;
02507
02508
KeQuerySystemTime (&CurrentTime);
02509
02510
if (IsListEmpty(&
MmWorkingSetExpansionHead.
ListHead)) {
02511
return;
02512 }
02513
02514
for (
Size = 0 ;
Size <
MM_WS_REORG_BUCKETS_MAX;
Size++) {
02515 InitializeListHead(&ListHead[
Size]);
02516 }
02517
02518
LOCK_EXPANSION (OldIrql);
02519
02520
while (!IsListEmpty (&
MmWorkingSetExpansionHead.
ListHead)) {
02521 ListEntry = RemoveHeadList (&
MmWorkingSetExpansionHead.
ListHead);
02522
02523 VmSupport = CONTAINING_RECORD(ListEntry,
02524
MMSUPPORT,
02525 WorkingSetExpansionLinks);
02526
02527
if (VmSupport->
u.Flags.TrimHard == 1) {
02528
02529
ASSERT (
MiHydra ==
TRUE);
02530
ASSERT (VmSupport->
u.Flags.SessionSpace == 1);
02531
02532 SessionGlobal = CONTAINING_RECORD (VmSupport,
02533
MM_SESSION_SPACE,
02534 Vm);
02535
02536 SessionIdleTime.QuadPart = CurrentTime.QuadPart - SessionGlobal->
LastProcessSwappedOutTime.QuadPart;
02537
02538
#if DBG
02539
if (MmDebug &
MM_DBG_SESSIONS) {
02540
DbgPrint (
"Mm: Session %d heavily trim/aged - all its processes (%d) swapped out %d seconds ago\n",
02541 SessionGlobal->
SessionId,
02542 SessionGlobal->
ReferenceCount,
02543 (ULONG)(SessionIdleTime.QuadPart / 10000000));
02544 }
02545
#endif
02546
02547
if (SessionIdleTime.QuadPart < 0) {
02548
02549
02550
02551
02552
02553
02554 SessionIdleTime.QuadPart = 0;
02555
KeQuerySystemTime (&SessionGlobal->
LastProcessSwappedOutTime);
02556 }
02557
02558 IdleTime = (ULONG) (SessionIdleTime.QuadPart / 10000000);
02559 }
02560
else {
02561 IdleTime = 0;
02562 }
02563
02564
if (VmSupport->
MemoryPriority ==
MEMORY_PRIORITY_FOREGROUND) {
02565
02566
02567
02568
02569
02570
02571
Size = 6;
02572 }
02573
#ifdef _MI_USE_CLAIMS_
02574
else {
02575
02576
if (VmSupport->
Claim > 400) {
02577
Size = 0;
02578 }
else if (IdleTime > 30) {
02579
Size = 0;
02580
#if DBG
02581
MiSessionIdleBuckets[
Size] += 1;
02582
#endif
02583
}
else if (VmSupport->
Claim > 200) {
02584
Size = 1;
02585 }
else if (IdleTime > 20) {
02586
Size = 1;
02587
#if DBG
02588
MiSessionIdleBuckets[
Size] += 1;
02589
#endif
02590
}
else if (VmSupport->
Claim > 100) {
02591
Size = 2;
02592 }
else if (IdleTime > 10) {
02593
Size = 2;
02594
#if DBG
02595
MiSessionIdleBuckets[
Size] += 1;
02596
#endif
02597
}
else if (VmSupport->
Claim > 50) {
02598
Size = 3;
02599 }
else if (IdleTime) {
02600
Size = 3;
02601
#if DBG
02602
MiSessionIdleBuckets[
Size] += 1;
02603
#endif
02604
}
else if (VmSupport->
Claim > 25) {
02605
Size = 4;
02606 }
else {
02607
Size = 5;
02608
#if DBG
02609
if (VmSupport->
u.Flags.SessionSpace == 1) {
02610 MiSessionIdleBuckets[
Size] += 1;
02611 }
02612
#endif
02613
}
02614 }
02615
#else
02616
else {
02617
02618
02619
02620
02621
02622
02623
02624
if (IdleTime > 40) {
02625
Size = 0;
02626 }
else if (IdleTime > 30) {
02627
Size = 1;
02628 }
else if (IdleTime > 20) {
02629
Size = 2;
02630 }
else if (IdleTime > 10) {
02631
Size = 3;
02632 }
else if (IdleTime) {
02633
Size = 4;
02634 }
else {
02635 InsertTailList (&ListHead[5],
02636 &VmSupport->
WorkingSetExpansionLinks);
02637
continue;
02638 }
02639
#if DBG
02640
ASSERT (
MiHydra ==
TRUE);
02641
ASSERT (VmSupport->
u.Flags.SessionSpace == 1);
02642 MiSessionIdleBuckets[
Size] += 1;
02643
#endif
02644
}
02645
#endif
02646
02647
#if DBG
02648
if (MmDebug &
MM_DBG_WS_EXPANSION) {
02649
DbgPrint(
"MM-rearrange: TrimHard = %d, WS Size = 0x%x, Claim 0x%x, Bucket %d\n",
02650 VmSupport->
u.Flags.TrimHard,
02651 VmSupport->
WorkingSetSize,
02652 VmSupport->
Claim,
02653
Size);
02654 }
02655
#endif //DBG
02656
02657
02658
02659
02660
02661
02662
02663 InsertHeadList (&ListHead[
Size],
02664 &VmSupport->
WorkingSetExpansionLinks);
02665 }
02666
02667
02668
02669
02670
02671
for (NonEmpty = 0 ; NonEmpty <
MM_WS_REORG_BUCKETS_MAX ; NonEmpty += 1) {
02672
if (!IsListEmpty (&ListHead[NonEmpty])) {
02673
break;
02674 }
02675 }
02676
02677
02678
02679
02680
02681
02682
MmWorkingSetExpansionHead.
ListHead.Flink = ListHead[NonEmpty].Flink;
02683 ListHead[NonEmpty].Flink->Blink = &
MmWorkingSetExpansionHead.
ListHead;
02684
02685 PreviousNonEmpty = NonEmpty;
02686
02687
02688
02689
02690
02691
for (NonEmpty += 1; NonEmpty <
MM_WS_REORG_BUCKETS_MAX; NonEmpty += 1) {
02692
02693
if (!IsListEmpty (&ListHead[NonEmpty])) {
02694
02695 ListHead[PreviousNonEmpty].Blink->Flink = ListHead[NonEmpty].Flink;
02696 ListHead[NonEmpty].Flink->Blink = ListHead[PreviousNonEmpty].Blink;
02697 PreviousNonEmpty = NonEmpty;
02698 }
02699 }
02700
02701
02702
02703
02704
02705
MmWorkingSetExpansionHead.
ListHead.Blink = ListHead[PreviousNonEmpty].Blink;
02706 ListHead[PreviousNonEmpty].Blink->Flink = &
MmWorkingSetExpansionHead.
ListHead;
02707
02708
UNLOCK_EXPANSION (OldIrql);
02709
02710
return;
02711 }
02712
02713
02714
VOID
02715 MiEmptyAllWorkingSets (
02716 VOID
02717 )
02718
02719
02720
02721
02722
02723
02724
02725
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739
02740 {
02741 KIRQL OldIrql;
02742
02743
PAGED_CODE ();
02744
02745
MmLockPagableSectionByHandle (
ExPageLockHandle);
02746
02747
if (
MiHydra ==
FALSE) {
02748
MiEmptyAllWorkingSetsWorker ();
02749 }
02750
else {
02751
ASSERT (
PsGetCurrentThread () != MmWorkingSetThread);
02752
02753
02754
02755
02756
02757
02758
02759
02760
02761
02762
02763
02764
LOCK_EXPANSION (OldIrql);
02765
02766
if (
MiWaitingForWorkingSetEmpty ==
FALSE) {
02767
MiWaitingForWorkingSetEmpty =
TRUE;
02768
KeClearEvent (&
MiWaitForEmptyEvent);
02769 }
02770
02771
UNLOCK_EXPANSION (OldIrql);
02772
02773
KeSetEvent (&
MmWorkingSetManagerEvent, 0,
FALSE);
02774
02775
KeWaitForSingleObject (&
MiWaitForEmptyEvent,
02776
WrVirtualMemory,
02777
KernelMode,
02778
FALSE,
02779 (PLARGE_INTEGER)0);
02780 }
02781
02782
MmUnlockPagableImageSection (
ExPageLockHandle);
02783
02784
return;
02785 }
02786
02787
VOID
02788 MiEmptyAllWorkingSetsWorker (
02789 VOID
02790 )
02791
02792
02793
02794
02795
02796
02797
02798
02799
02800
02801
02802
02803
02804
02805
02806
02807
02808
02809
02810
02811
02812 {
02813
PMMSUPPORT VmSupport;
02814
PMMSUPPORT FirstSeen;
02815 ULONG SystemCacheSeen;
02816 KIRQL OldIrql;
02817 PLIST_ENTRY ListEntry;
02818
PEPROCESS ProcessToTrim;
02819
PMM_SESSION_SPACE SessionSpace;
02820 ULONG LoopCount;
02821
02822
PAGED_CODE ();
02823
02824 FirstSeen =
NULL;
02825 SystemCacheSeen =
FALSE;
02826 LoopCount = 0;
02827
02828
LOCK_EXPANSION (OldIrql);
02829
02830
while (!IsListEmpty (&
MmWorkingSetExpansionHead.
ListHead)) {
02831
02832
02833
02834
02835
02836 ListEntry = RemoveHeadList (&
MmWorkingSetExpansionHead.
ListHead);
02837
02838
if (ListEntry == &
MmSystemCacheWs.
WorkingSetExpansionLinks) {
02839 VmSupport = &
MmSystemCacheWs;
02840
ASSERT (VmSupport->
u.Flags.SessionSpace == 0);
02841 ProcessToTrim =
NULL;
02842
if (SystemCacheSeen !=
FALSE) {
02843
02844
02845
02846
02847
02848 FirstSeen = VmSupport;
02849 }
02850 SystemCacheSeen =
TRUE;
02851 }
02852
else {
02853 VmSupport = CONTAINING_RECORD(ListEntry,
02854
MMSUPPORT,
02855 WorkingSetExpansionLinks);
02856
02857
if (VmSupport->
u.Flags.SessionSpace == 0) {
02858 ProcessToTrim = CONTAINING_RECORD(VmSupport,
02859
EPROCESS,
02860 Vm);
02861
02862
ASSERT (VmSupport->
VmWorkingSetList ==
MmWorkingSetList);
02863
ASSERT (VmSupport == &ProcessToTrim->
Vm);
02864
ASSERT (ProcessToTrim->
AddressSpaceDeleted == 0);
02865
ASSERT (VmSupport->
u.Flags.SessionSpace == 0);
02866 }
02867
else {
02868
ASSERT (
MiHydra ==
TRUE);
02869 SessionSpace = CONTAINING_RECORD(VmSupport,
02870
MM_SESSION_SPACE,
02871 Vm);
02872
02873 ProcessToTrim =
NULL;
02874 }
02875 }
02876
02877
if (VmSupport == FirstSeen) {
02878 InsertHeadList (&
MmWorkingSetExpansionHead.
ListHead,
02879 &VmSupport->
WorkingSetExpansionLinks);
02880
break;
02881 }
02882
02883
ASSERT (VmSupport->
u.Flags.BeingTrimmed == 0);
02884 VmSupport->
u.Flags.BeingTrimmed = 1;
02885
02886 VmSupport->
WorkingSetExpansionLinks.Flink =
MM_NO_WS_EXPANSION;
02887 VmSupport->
WorkingSetExpansionLinks.Blink =
02888
MM_WS_EXPANSION_IN_PROGRESS;
02889
UNLOCK_EXPANSION (OldIrql);
02890
02891
if (FirstSeen ==
NULL) {
02892 FirstSeen = VmSupport;
02893 }
02894
02895
02896
02897
02898
02899
if (ProcessToTrim ==
NULL) {
02900
if (VmSupport->
u.Flags.SessionSpace == 0) {
02901
MiEmptyWorkingSet (VmSupport,
FALSE);
02902 }
02903
else {
02904
ASSERT (
MiHydra ==
TRUE);
02905
MiAttachSession (SessionSpace);
02906
MiEmptyWorkingSet (VmSupport,
FALSE);
02907
MiDetachSession ();
02908 }
02909 }
02910
else {
02911
02912
if (VmSupport->
WorkingSetSize > 4) {
02913
KeAttachProcess (&ProcessToTrim->
Pcb);
02914
MiEmptyWorkingSet (VmSupport,
FALSE);
02915
KeDetachProcess ();
02916 }
02917 }
02918
02919
02920
02921
02922
02923
LOCK_EXPANSION (OldIrql);
02924
ASSERT (VmSupport->
WorkingSetExpansionLinks.Flink ==
MM_NO_WS_EXPANSION);
02925
ASSERT (VmSupport->
u.Flags.BeingTrimmed == 1);
02926 VmSupport->
u.Flags.BeingTrimmed = 0;
02927
02928
ASSERT (VmSupport->
WorkingSetExpansionLinks.Flink ==
MM_NO_WS_EXPANSION);
02929
if (VmSupport->
WorkingSetExpansionLinks.Blink ==
02930
MM_WS_EXPANSION_IN_PROGRESS) {
02931
02932
02933
02934
02935
02936
02937 InsertTailList (&
MmWorkingSetExpansionHead.
ListHead,
02938 &VmSupport->
WorkingSetExpansionLinks);
02939 }
02940
else {
02941
02942
02943
02944
02945
02946
02947
ASSERT (VmSupport != &
MmSystemCacheWs);
02948
02949
KeSetEvent ((
PKEVENT)VmSupport->
WorkingSetExpansionLinks.Blink,
02950 0,
02951
FALSE);
02952 }
02953
02954
02955
02956
02957
02958
02959
02960
02961
02962 LoopCount += 1;
02963
if (LoopCount > 200) {
02964
if (
MmSystemCacheWs.
WorkingSetExpansionLinks.Blink ==
MM_WS_EXPANSION_IN_PROGRESS) {
02965
break;
02966 }
02967 }
02968 }
02969
02970
UNLOCK_EXPANSION (OldIrql);
02971
02972
return;
02973 }
02974
02975
02976
02977
02978
02979
02980 LONG
MiTrimInProgressCount = 1;
02981
02982 ULONG
MiTrimAllPageFaultCount;
02983
02984
02985 LOGICAL
02986 MmTrimAllSystemPagableMemory (
02987 IN LOGICAL PurgeTransition
02988 )
02989
02990
02991
02992
02993
02994
02995
02996
02997
02998
02999
03000
03001
03002
03003
03004
03005
03006
03007
03008
03009
03010
03011
03012
03013
03014
03015
03016
03017
03018
03019
03020
03021
03022 {
03023 KIRQL OldIrql;
03024 KIRQL OldIrql2;
03025 PLIST_ENTRY Next;
03026
PMMSUPPORT VmSupport;
03027
WSLE_NUMBER PagesInUse;
03028 PFN_NUMBER PageFrameIndex;
03029 LOGICAL LockAvailable;
03030
PMMPFN Pfn1;
03031
PETHREAD CurrentThread;
03032 ULONG flags;
03033
03034
03035
03036
03037
03038
if (
MiTrimAllPageFaultCount ==
MmSystemCacheWs.
PageFaultCount) {
03039
return FALSE;
03040 }
03041
03042
03043
03044
03045
03046
if (KeGetCurrentIrql() >
APC_LEVEL) {
03047
return FALSE;
03048 }
03049
03050
03051
03052
03053
03054
03055
if (InterlockedIncrement (&
MiTrimInProgressCount) > 1) {
03056 InterlockedDecrement (&
MiTrimInProgressCount);
03057
return FALSE;
03058 }
03059
03060
#if defined(_X86_)
03061
03062 _asm {
03063 pushfd
03064 pop flags
03065 }
03066
03067
if ((flags & EFLAGS_INTERRUPT_MASK) == 0) {
03068 InterlockedDecrement (&
MiTrimInProgressCount);
03069
return FALSE;
03070 }
03071
03072
#endif
03073
03074 LockAvailable =
KeTryToAcquireSpinLock (&
MmExpansionLock, &OldIrql);
03075
03076
if (LockAvailable ==
FALSE) {
03077 InterlockedDecrement (&
MiTrimInProgressCount);
03078
return FALSE;
03079 }
03080
03081
MM_SET_EXPANSION_OWNER ();
03082
03083 CurrentThread =
PsGetCurrentThread();
03084
03085
03086
03087
03088
03089
03090
03091
if ((CurrentThread ==
MmSystemLockOwner) ||
03092 (
ExTryToAcquireResourceExclusiveLite(&
MmSystemWsLock) ==
FALSE)) {
03093
UNLOCK_EXPANSION (OldIrql);
03094 InterlockedDecrement (&
MiTrimInProgressCount);
03095
return FALSE;
03096 }
03097
03098 Next =
MmWorkingSetExpansionHead.
ListHead.Flink;
03099
03100
while (Next != &
MmWorkingSetExpansionHead.
ListHead) {
03101
if (Next == &
MmSystemCacheWs.
WorkingSetExpansionLinks) {
03102
break;
03103 }
03104 Next = Next->Flink;
03105 }
03106
03107
if (Next != &
MmSystemCacheWs.
WorkingSetExpansionLinks) {
03108
ExReleaseResourceLite(&
MmSystemWsLock);
03109
UNLOCK_EXPANSION (OldIrql);
03110 InterlockedDecrement (&
MiTrimInProgressCount);
03111
return FALSE;
03112 }
03113
03114 RemoveEntryList (Next);
03115
03116 VmSupport = &
MmSystemCacheWs;
03117 VmSupport->
WorkingSetExpansionLinks.Flink =
MM_NO_WS_EXPANSION;
03118 VmSupport->
WorkingSetExpansionLinks.Blink =
MM_WS_EXPANSION_IN_PROGRESS;
03119
ASSERT (VmSupport->
u.Flags.BeingTrimmed == 0);
03120 VmSupport->
u.Flags.BeingTrimmed = 1;
03121
03122
MiTrimAllPageFaultCount = VmSupport->
PageFaultCount;
03123
03124 PagesInUse = VmSupport->
WorkingSetSize;
03125
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
MmSystemLockOwner =
PsGetCurrentThread ();
03141
03142
UNLOCK_EXPANSION (
APC_LEVEL);
03143
03144
MiEmptyWorkingSet (VmSupport,
FALSE);
03145
03146
LOCK_EXPANSION (OldIrql2);
03147
ASSERT (OldIrql2 ==
APC_LEVEL);
03148
03149
ASSERT (VmSupport->
WorkingSetExpansionLinks.Flink ==
MM_NO_WS_EXPANSION);
03150
03151
ASSERT (VmSupport->
u.Flags.BeingTrimmed == 1);
03152 VmSupport->
u.Flags.BeingTrimmed = 0;
03153
03154
ASSERT (VmSupport->
WorkingSetExpansionLinks.Blink ==
03155
MM_WS_EXPANSION_IN_PROGRESS);
03156
03157 InsertTailList (&
MmWorkingSetExpansionHead.
ListHead,
03158 &VmSupport->
WorkingSetExpansionLinks);
03159
03160
UNLOCK_EXPANSION (
APC_LEVEL);
03161
03162
03163
03164
03165
03166
03167
03168
03169
MmSystemLockOwner =
NULL;
03170
ExReleaseResourceLite (&
MmSystemWsLock);
03171
KeLowerIrql (OldIrql);
03172
ASSERT (KeGetCurrentIrql() <=
APC_LEVEL);
03173
03174
if (PurgeTransition ==
TRUE) {
03175
03176
03177
03178
03179
03180
03181
03182
LOCK_PFN (OldIrql);
03183
03184
while (
MmStandbyPageListHead.
Total != 0) {
03185
03186 PageFrameIndex =
MiRemovePageFromList (&
MmStandbyPageListHead);
03187
03188 Pfn1 =
MI_PFN_ELEMENT (PageFrameIndex);
03189
03190
ASSERT (Pfn1->
u2.ShareCount == 0);
03191
ASSERT (Pfn1->
u3.e2.ReferenceCount == 0);
03192
03193 Pfn1->
u3.e2.ReferenceCount += 1;
03194 Pfn1->
OriginalPte =
ZeroPte;
03195 Pfn1->
u3.e1.Modified = 0;
03196
MI_SET_PFN_DELETED (Pfn1);
03197
03198
MiDecrementReferenceCount (PageFrameIndex);
03199 }
03200
03201
UNLOCK_PFN (OldIrql);
03202 }
03203
03204 InterlockedDecrement (&
MiTrimInProgressCount);
03205
03206
return TRUE;
03207 }