forked from OSchip/llvm-project
[scudo][standalone] Skip irrelevant regions during release
With the 'new' way of releasing on 32-bit, we iterate through all the regions in between `First` and `Last`, which covers regions that do not belong to the class size we are working with. This is effectively wasted cycles. With this change, we add a `SkipRegion` lambda to `releaseFreeMemoryToOS` that will allow the release function to know when to skip a region. For the 64-bit primary, since we are only working with 1 region, we never skip. Reviewed By: hctim Differential Revision: https://reviews.llvm.org/D86399
This commit is contained in:
parent
1dc57ada0c
commit
bd5ca4f0ed
|
@ -483,12 +483,15 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uptr TotalReleasedBytes = 0;
|
uptr TotalReleasedBytes = 0;
|
||||||
|
auto SkipRegion = [this, First, ClassId](uptr RegionIndex) {
|
||||||
|
return (PossibleRegions[First + RegionIndex] - 1U) != ClassId;
|
||||||
|
};
|
||||||
if (First && Last) {
|
if (First && Last) {
|
||||||
const uptr Base = First * RegionSize;
|
const uptr Base = First * RegionSize;
|
||||||
const uptr NumberOfRegions = Last - First + 1U;
|
const uptr NumberOfRegions = Last - First + 1U;
|
||||||
ReleaseRecorder Recorder(Base);
|
ReleaseRecorder Recorder(Base);
|
||||||
releaseFreeMemoryToOS(Sci->FreeList, Base, RegionSize, NumberOfRegions,
|
releaseFreeMemoryToOS(Sci->FreeList, Base, RegionSize, NumberOfRegions,
|
||||||
BlockSize, &Recorder);
|
BlockSize, &Recorder, SkipRegion);
|
||||||
if (Recorder.getReleasedRangesCount() > 0) {
|
if (Recorder.getReleasedRangesCount() > 0) {
|
||||||
Sci->ReleaseInfo.PushedBlocksAtLastRelease = Sci->Stats.PushedBlocks;
|
Sci->ReleaseInfo.PushedBlocksAtLastRelease = Sci->Stats.PushedBlocks;
|
||||||
Sci->ReleaseInfo.RangesReleased += Recorder.getReleasedRangesCount();
|
Sci->ReleaseInfo.RangesReleased += Recorder.getReleasedRangesCount();
|
||||||
|
|
|
@ -479,9 +479,11 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto SkipRegion = [](UNUSED uptr RegionIndex) { return false; };
|
||||||
ReleaseRecorder Recorder(Region->RegionBeg, &Region->Data);
|
ReleaseRecorder Recorder(Region->RegionBeg, &Region->Data);
|
||||||
releaseFreeMemoryToOS(Region->FreeList, Region->RegionBeg,
|
releaseFreeMemoryToOS(Region->FreeList, Region->RegionBeg,
|
||||||
Region->AllocatedUser, 1U, BlockSize, &Recorder);
|
Region->AllocatedUser, 1U, BlockSize, &Recorder,
|
||||||
|
SkipRegion);
|
||||||
|
|
||||||
if (Recorder.getReleasedRangesCount() > 0) {
|
if (Recorder.getReleasedRangesCount() > 0) {
|
||||||
Region->ReleaseInfo.PushedBlocksAtLastRelease =
|
Region->ReleaseInfo.PushedBlocksAtLastRelease =
|
||||||
|
|
|
@ -156,6 +156,11 @@ public:
|
||||||
CurrentPage++;
|
CurrentPage++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void skipPages(uptr N) {
|
||||||
|
closeOpenedRange();
|
||||||
|
CurrentPage += N;
|
||||||
|
}
|
||||||
|
|
||||||
void finish() { closeOpenedRange(); }
|
void finish() { closeOpenedRange(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -174,11 +179,11 @@ private:
|
||||||
uptr CurrentRangeStatePage = 0;
|
uptr CurrentRangeStatePage = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class TransferBatchT, class ReleaseRecorderT>
|
template <class TransferBatchT, class ReleaseRecorderT, typename SkipRegionT>
|
||||||
NOINLINE void
|
NOINLINE void
|
||||||
releaseFreeMemoryToOS(const IntrusiveList<TransferBatchT> &FreeList, uptr Base,
|
releaseFreeMemoryToOS(const IntrusiveList<TransferBatchT> &FreeList, uptr Base,
|
||||||
uptr RegionSize, uptr NumberOfRegions, uptr BlockSize,
|
uptr RegionSize, uptr NumberOfRegions, uptr BlockSize,
|
||||||
ReleaseRecorderT *Recorder) {
|
ReleaseRecorderT *Recorder, SkipRegionT SkipRegion) {
|
||||||
const uptr PageSize = getPageSizeCached();
|
const uptr PageSize = getPageSizeCached();
|
||||||
|
|
||||||
// Figure out the number of chunks per page and whether we can take a fast
|
// Figure out the number of chunks per page and whether we can take a fast
|
||||||
|
@ -283,10 +288,15 @@ releaseFreeMemoryToOS(const IntrusiveList<TransferBatchT> &FreeList, uptr Base,
|
||||||
FreePagesRangeTracker<ReleaseRecorderT> RangeTracker(Recorder);
|
FreePagesRangeTracker<ReleaseRecorderT> RangeTracker(Recorder);
|
||||||
if (SameBlockCountPerPage) {
|
if (SameBlockCountPerPage) {
|
||||||
// Fast path, every page has the same number of chunks affecting it.
|
// Fast path, every page has the same number of chunks affecting it.
|
||||||
for (uptr I = 0; I < NumberOfRegions; I++)
|
for (uptr I = 0; I < NumberOfRegions; I++) {
|
||||||
|
if (SkipRegion(I)) {
|
||||||
|
RangeTracker.skipPages(PagesCount);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (uptr J = 0; J < PagesCount; J++)
|
for (uptr J = 0; J < PagesCount; J++)
|
||||||
RangeTracker.processNextPage(Counters.get(I, J) ==
|
RangeTracker.processNextPage(Counters.get(I, J) ==
|
||||||
FullPagesBlockCountMax);
|
FullPagesBlockCountMax);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Slow path, go through the pages keeping count how many chunks affect
|
// Slow path, go through the pages keeping count how many chunks affect
|
||||||
// each page.
|
// each page.
|
||||||
|
@ -298,6 +308,10 @@ releaseFreeMemoryToOS(const IntrusiveList<TransferBatchT> &FreeList, uptr Base,
|
||||||
// up the number of chunks on the current page and checking on every step
|
// up the number of chunks on the current page and checking on every step
|
||||||
// whether the page boundary was crossed.
|
// whether the page boundary was crossed.
|
||||||
for (uptr I = 0; I < NumberOfRegions; I++) {
|
for (uptr I = 0; I < NumberOfRegions; I++) {
|
||||||
|
if (SkipRegion(I)) {
|
||||||
|
RangeTracker.skipPages(PagesCount);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
uptr PrevPageBoundary = 0;
|
uptr PrevPageBoundary = 0;
|
||||||
uptr CurrentBoundary = 0;
|
uptr CurrentBoundary = 0;
|
||||||
for (uptr J = 0; J < PagesCount; J++) {
|
for (uptr J = 0; J < PagesCount; J++) {
|
||||||
|
|
|
@ -190,9 +190,10 @@ template <class SizeClassMap> void testReleaseFreeMemoryToOS() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release the memory.
|
// Release the memory.
|
||||||
|
auto SkipRegion = [](UNUSED scudo::uptr RegionIndex) { return false; };
|
||||||
ReleasedPagesRecorder Recorder;
|
ReleasedPagesRecorder Recorder;
|
||||||
releaseFreeMemoryToOS(FreeList, 0, MaxBlocks * BlockSize, 1U, BlockSize,
|
releaseFreeMemoryToOS(FreeList, 0, MaxBlocks * BlockSize, 1U, BlockSize,
|
||||||
&Recorder);
|
&Recorder, SkipRegion);
|
||||||
|
|
||||||
// Verify that there are no released pages touched by used chunks and all
|
// Verify that there are no released pages touched by used chunks and all
|
||||||
// ranges of free chunks big enough to contain the entire memory pages had
|
// ranges of free chunks big enough to contain the entire memory pages had
|
||||||
|
|
Loading…
Reference in New Issue