Skip to content

Commit

Permalink
[scudo] Add fragmentation info for each memory group (llvm#107475)
Browse files Browse the repository at this point in the history
This information helps with tuning the heuristic of selecting memory
groups to release the unused pages.
  • Loading branch information
ChiaHungDuan authored and VitaNuo committed Sep 12, 2024
1 parent 7e1b382 commit 2438660
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 0 deletions.
6 changes: 6 additions & 0 deletions compiler-rt/lib/scudo/standalone/primary32.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,12 @@ template <typename Config> class SizeClassAllocator32 {
}
}

void getMemoryGroupFragmentationInfo(ScopedString *Str) {
// Each region is also a memory group because region size is the same as
// group size.
getFragmentationInfo(Str);
}

bool setOption(Option O, sptr Value) {
if (O == Option::ReleaseInterval) {
const s32 Interval = Max(
Expand Down
56 changes: 56 additions & 0 deletions compiler-rt/lib/scudo/standalone/primary64.h
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,18 @@ template <typename Config> class SizeClassAllocator64 {
}
}

void getMemoryGroupFragmentationInfo(ScopedString *Str) {
Str->append(
"Fragmentation Stats: SizeClassAllocator64: page size = %zu bytes\n",
getPageSizeCached());

for (uptr I = 1; I < NumClasses; I++) {
RegionInfo *Region = getRegionInfo(I);
ScopedLock L(Region->MMLock);
getMemoryGroupFragmentationInfoInRegion(Region, I, Str);
}
}

bool setOption(Option O, sptr Value) {
if (O == Option::ReleaseInterval) {
const s32 Interval = Max(
Expand Down Expand Up @@ -1193,6 +1205,50 @@ template <typename Config> class SizeClassAllocator64 {
AllocatedPagesCount, InUseBytes >> 10, Integral, Fractional);
}

void getMemoryGroupFragmentationInfoInRegion(RegionInfo *Region, uptr ClassId,
ScopedString *Str)
REQUIRES(Region->MMLock) {
const uptr BlockSize = getSizeByClassId(ClassId);
const uptr AllocatedUserEnd =
Region->MemMapInfo.AllocatedUser + Region->RegionBeg;

SinglyLinkedList<BatchGroupT> GroupsToRelease;
{
ScopedLock L(Region->FLLock);
GroupsToRelease = Region->FreeListInfo.BlockList;
Region->FreeListInfo.BlockList.clear();
}

constexpr uptr GroupSize = (1UL << GroupSizeLog);
constexpr uptr MaxNumGroups = RegionSize / GroupSize;

MemoryGroupFragmentationRecorder<GroupSize, MaxNumGroups> Recorder;
if (!GroupsToRelease.empty()) {
PageReleaseContext Context =
markFreeBlocks(Region, BlockSize, AllocatedUserEnd,
getCompactPtrBaseByClassId(ClassId), GroupsToRelease);
auto SkipRegion = [](UNUSED uptr RegionIndex) { return false; };
releaseFreeMemoryToOS(Context, Recorder, SkipRegion);

mergeGroupsToReleaseBack(Region, GroupsToRelease);
}

Str->append("MemoryGroupFragmentationInfo in Region %zu (%zu)\n", ClassId,
BlockSize);

const uptr MaxNumGroupsInUse =
roundUp(Region->MemMapInfo.AllocatedUser, GroupSize) / GroupSize;
for (uptr I = 0; I < MaxNumGroupsInUse; ++I) {
uptr Integral;
uptr Fractional;
computePercentage(Recorder.NumPagesInOneGroup -
Recorder.getNumFreePages(I),
Recorder.NumPagesInOneGroup, &Integral, &Fractional);
Str->append("MemoryGroup #%zu (0x%zx): util: %3zu.%02zu%%\n", I,
Region->RegionBeg + I * GroupSize, Integral, Fractional);
}
}

NOINLINE uptr releaseToOSMaybe(RegionInfo *Region, uptr ClassId,
ReleaseToOS ReleaseType = ReleaseToOS::Normal)
REQUIRES(Region->MMLock) EXCLUDES(Region->FLLock) {
Expand Down
16 changes: 16 additions & 0 deletions compiler-rt/lib/scudo/standalone/release.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,22 @@ class FragmentationRecorder {
uptr ReleasedPagesCount = 0;
};

template <uptr GroupSize, uptr NumGroups>
class MemoryGroupFragmentationRecorder {
public:
const uptr NumPagesInOneGroup = GroupSize / getPageSizeCached();

void releasePageRangeToOS(uptr From, uptr To) {
for (uptr I = From / getPageSizeCached(); I < To / getPageSizeCached(); ++I)
++FreePagesCount[I / NumPagesInOneGroup];
}

uptr getNumFreePages(uptr GroupId) { return FreePagesCount[GroupId]; }

private:
uptr FreePagesCount[NumGroups] = {};
};

// A buffer pool which holds a fixed number of static buffers of `uptr` elements
// for fast buffer allocation. If the request size is greater than
// `StaticBufferNumElements` or if all the static buffers are in use, it'll
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/scudo/standalone/tests/primary_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ SCUDO_TYPED_TEST(ScudoPrimaryTest, PrimaryThreaded) {
scudo::ScopedString Str;
Allocator->getStats(&Str);
Allocator->getFragmentationInfo(&Str);
Allocator->getMemoryGroupFragmentationInfo(&Str);
Str.output();
}

Expand Down

0 comments on commit 2438660

Please sign in to comment.