mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[NTOS:MM] Implement shrinking big pool allocation table
Shrink when using 1/8 of its allocated capacity (thus use 25% of it at the end of the process) Expand when using 3/4 of its allocated capacity (thus use ~40% of it at the end of the process)
This commit is contained in:
parent
54354712e2
commit
f06b58925d
1 changed files with 64 additions and 21 deletions
|
@ -1446,14 +1446,14 @@ ExGetPoolTagInfo(IN PSYSTEM_POOLTAG_INFORMATION SystemInformation,
|
|||
}
|
||||
|
||||
_IRQL_requires_(DISPATCH_LEVEL)
|
||||
static
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
ExpExpandBigPageTable(
|
||||
_In_ _IRQL_restores_ KIRQL OldIrql)
|
||||
ExpReallocateBigPageTable(
|
||||
_In_ _IRQL_restores_ KIRQL OldIrql,
|
||||
_In_ BOOLEAN Shrink)
|
||||
{
|
||||
ULONG OldSize = PoolBigPageTableSize;
|
||||
ULONG NewSize = 2 * OldSize;
|
||||
ULONG NewSizeInBytes;
|
||||
SIZE_T OldSize = PoolBigPageTableSize;
|
||||
SIZE_T NewSize, NewSizeInBytes;
|
||||
PPOOL_TRACKER_BIG_PAGES NewTable;
|
||||
PPOOL_TRACKER_BIG_PAGES OldTable;
|
||||
ULONG i;
|
||||
|
@ -1465,11 +1465,41 @@ ExpExpandBigPageTable(
|
|||
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||||
|
||||
/* Make sure we don't overflow */
|
||||
if (!NT_SUCCESS(RtlULongMult(2,
|
||||
OldSize * sizeof(POOL_TRACKER_BIG_PAGES),
|
||||
&NewSizeInBytes)))
|
||||
if (Shrink)
|
||||
{
|
||||
DPRINT1("Overflow expanding big page table. Size=%lu\n", OldSize);
|
||||
NewSize = OldSize / 2;
|
||||
|
||||
/* Make sure we don't shrink too much. */
|
||||
ASSERT(NewSize >= ExpPoolBigEntriesInUse);
|
||||
|
||||
NewSize = ALIGN_UP_BY(NewSize, PAGE_SIZE / sizeof(POOL_TRACKER_BIG_PAGES));
|
||||
ASSERT(NewSize <= OldSize);
|
||||
|
||||
/* If there is only one page left, then keep it around. Not a failure either. */
|
||||
if (NewSize == OldSize)
|
||||
{
|
||||
ASSERT(NewSize == (PAGE_SIZE / sizeof(POOL_TRACKER_BIG_PAGES)));
|
||||
KeReleaseSpinLock(&ExpLargePoolTableLock, OldIrql);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!NT_SUCCESS(RtlSIZETMult(2, OldSize, &NewSize)))
|
||||
{
|
||||
DPRINT1("Overflow expanding big page table. Size=%lu\n", OldSize);
|
||||
KeReleaseSpinLock(&ExpLargePoolTableLock, OldIrql);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Make sure we don't stupidly waste pages */
|
||||
NewSize = ALIGN_DOWN_BY(NewSize, PAGE_SIZE / sizeof(POOL_TRACKER_BIG_PAGES));
|
||||
ASSERT(NewSize > OldSize);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(RtlSIZETMult(sizeof(POOL_TRACKER_BIG_PAGES), NewSize, &NewSizeInBytes)))
|
||||
{
|
||||
DPRINT1("Overflow while calculating big page table size. Size=%lu\n", OldSize);
|
||||
KeReleaseSpinLock(&ExpLargePoolTableLock, OldIrql);
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -1482,7 +1512,7 @@ ExpExpandBigPageTable(
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
DPRINT("Expanding big pool tracker table to %lu entries\n", NewSize);
|
||||
DPRINT("%s big pool tracker table to %lu entries\n", Shrink ? "Shrinking" : "Expanding", NewSize);
|
||||
|
||||
/* Initialize the new table */
|
||||
RtlZeroMemory(NewTable, NewSizeInBytes);
|
||||
|
@ -1503,15 +1533,16 @@ ExpExpandBigPageTable(
|
|||
}
|
||||
|
||||
/* Recalculate the hash due to the new table size */
|
||||
Hash = ExpComputePartialHashForAddress(OldTable[i].Va) & HashMask;
|
||||
Hash = ExpComputePartialHashForAddress(OldTable[i].Va) % HashMask;
|
||||
|
||||
/* Find the location in the new table */
|
||||
while (!((ULONG_PTR)NewTable[Hash].Va & POOL_BIG_TABLE_ENTRY_FREE))
|
||||
{
|
||||
Hash = (Hash + 1) & HashMask;
|
||||
if (++Hash == NewSize)
|
||||
Hash = 0;
|
||||
}
|
||||
|
||||
/* We just enlarged the table, so we must have space */
|
||||
/* We must have space */
|
||||
ASSERT((ULONG_PTR)NewTable[Hash].Va & POOL_BIG_TABLE_ENTRY_FREE);
|
||||
|
||||
/* Finally, copy the item */
|
||||
|
@ -1587,20 +1618,20 @@ Retry:
|
|||
|
||||
//
|
||||
// Add one more entry to the count, and see if we're getting within
|
||||
// 25% of the table size, at which point we'll do an expansion now
|
||||
// 75% of the table size, at which point we'll do an expansion now
|
||||
// to avoid blocking too hard later on.
|
||||
//
|
||||
// Note that we only do this if it's also been the 16th time that we
|
||||
// keep losing the race or that we are not finding a free entry anymore,
|
||||
// which implies a massive number of concurrent big pool allocations.
|
||||
//
|
||||
InterlockedIncrementUL(&ExpPoolBigEntriesInUse);
|
||||
if ((i >= 16) && (ExpPoolBigEntriesInUse > (TableSize / 4)))
|
||||
ExpPoolBigEntriesInUse++;
|
||||
if ((i >= 16) && (ExpPoolBigEntriesInUse > (TableSize * 3 / 4)))
|
||||
{
|
||||
DPRINT("Attempting expansion since we now have %lu entries\n",
|
||||
ExpPoolBigEntriesInUse);
|
||||
ASSERT(TableSize == PoolBigPageTableSize);
|
||||
ExpExpandBigPageTable(OldIrql);
|
||||
ExpReallocateBigPageTable(OldIrql, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1626,7 +1657,7 @@ Retry:
|
|||
// to attempt expanding the table
|
||||
//
|
||||
ASSERT(TableSize == PoolBigPageTableSize);
|
||||
if (ExpExpandBigPageTable(OldIrql))
|
||||
if (ExpReallocateBigPageTable(OldIrql, FALSE))
|
||||
{
|
||||
goto Retry;
|
||||
}
|
||||
|
@ -1704,8 +1735,20 @@ ExpFindAndRemoveTagBigPages(IN PVOID Va,
|
|||
// the lock and return the tag that was located
|
||||
//
|
||||
InterlockedIncrement((PLONG)&Entry->Va);
|
||||
InterlockedDecrementUL(&ExpPoolBigEntriesInUse);
|
||||
KeReleaseSpinLock(&ExpLargePoolTableLock, OldIrql);
|
||||
|
||||
ExpPoolBigEntriesInUse--;
|
||||
|
||||
/* If reaching 12.5% of the size (or whatever integer rounding gets us to),
|
||||
* halve the allocation size, which will get us to 25% of space used. */
|
||||
if (ExpPoolBigEntriesInUse < (PoolBigPageTableSize / 8))
|
||||
{
|
||||
/* Shrink the table. */
|
||||
ExpReallocateBigPageTable(OldIrql, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
KeReleaseSpinLock(&ExpLargePoolTableLock, OldIrql);
|
||||
}
|
||||
return PoolTag;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue