Skip to content

Commit 4634a48

Browse files
authored
[scudo] Add a method to use a hard-coded page size (#106646)
Currently, only Android supports using a hard-code page size. Make this a bit more generic so any platform that wants to can use this. In addition, add a getPageSizeLogCached() function since this value is used in release.h and can avoid keeping this value around in objects. Finally, change some of the release.h page size multiplies to shifts using the new page size log value.
1 parent 52dca6f commit 4634a48

File tree

6 files changed

+63
-18
lines changed

6 files changed

+63
-18
lines changed

compiler-rt/lib/scudo/standalone/combined.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ class Allocator {
140140
typedef typename QuarantineT::CacheT QuarantineCacheT;
141141

142142
void init() {
143+
// Make sure that the page size is initialized if it's not a constant.
144+
CHECK_NE(getPageSizeCached(), 0U);
145+
143146
performSanityChecks();
144147

145148
// Check if hardware CRC32 is supported in the binary and by the platform,

compiler-rt/lib/scudo/standalone/common.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,21 @@
1212

1313
namespace scudo {
1414

15-
uptr PageSizeCached;
15+
#if !defined(SCUDO_PAGE_SIZE)
16+
uptr PageSizeCached = 0;
17+
uptr PageSizeLogCached = 0;
18+
19+
// Must be defined in platform specific code.
1620
uptr getPageSize();
1721

22+
// This must be called in the init path or there could be a race if multiple
23+
// threads try to set the cached values.
1824
uptr getPageSizeSlow() {
1925
PageSizeCached = getPageSize();
2026
CHECK_NE(PageSizeCached, 0);
27+
PageSizeLogCached = getLog2(PageSizeCached);
2128
return PageSizeCached;
2229
}
30+
#endif
2331

2432
} // namespace scudo

compiler-rt/lib/scudo/standalone/common.h

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,18 +133,40 @@ inline void computePercentage(uptr Numerator, uptr Denominator, uptr *Integral,
133133

134134
// Platform specific functions.
135135

136+
#if defined(SCUDO_PAGE_SIZE)
137+
138+
inline constexpr uptr getPageSizeCached() { return SCUDO_PAGE_SIZE; }
139+
140+
inline constexpr uptr getPageSizeSlow() { return getPageSizeCached(); }
141+
142+
inline constexpr uptr getPageSizeLogCached() {
143+
return static_cast<uptr>(__builtin_ctzl(SCUDO_PAGE_SIZE));
144+
}
145+
146+
#else
147+
136148
extern uptr PageSizeCached;
149+
extern uptr PageSizeLogCached;
150+
137151
uptr getPageSizeSlow();
152+
138153
inline uptr getPageSizeCached() {
139-
#if SCUDO_ANDROID && defined(PAGE_SIZE)
140-
// Most Android builds have a build-time constant page size.
141-
return PAGE_SIZE;
142-
#endif
143154
if (LIKELY(PageSizeCached))
144155
return PageSizeCached;
145156
return getPageSizeSlow();
146157
}
147158

159+
inline uptr getPageSizeLogCached() {
160+
if (LIKELY(PageSizeLogCached))
161+
return PageSizeLogCached;
162+
// PageSizeLogCached and PageSizeCached are both set in getPageSizeSlow()
163+
getPageSizeSlow();
164+
DCHECK_NE(PageSizeLogCached, 0);
165+
return PageSizeLogCached;
166+
}
167+
168+
#endif
169+
148170
// Returns 0 if the number of CPUs could not be determined.
149171
u32 getNumberOfCPUs();
150172

compiler-rt/lib/scudo/standalone/linux.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@
4040

4141
namespace scudo {
4242

43+
#if !defined(SCUDO_PAGE_SIZE)
44+
// This function is only used when page size is not hard-coded.
4345
uptr getPageSize() { return static_cast<uptr>(sysconf(_SC_PAGESIZE)); }
46+
#endif
4447

4548
void NORETURN die() { abort(); }
4649

compiler-rt/lib/scudo/standalone/platform.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
// See https://android.googlesource.com/platform/bionic/+/master/docs/defines.md
2222
#if defined(__BIONIC__)
2323
#define SCUDO_ANDROID 1
24+
// Transitive includes of unistd.h will get PAGE_SIZE if it is defined.
25+
#include <unistd.h>
26+
#if defined(PAGE_SIZE)
27+
#define SCUDO_PAGE_SIZE PAGE_SIZE
28+
#endif
2429
#else
2530
#define SCUDO_ANDROID 0
2631
#endif

compiler-rt/lib/scudo/standalone/release.h

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class FragmentationRecorder {
8888

8989
void releasePageRangeToOS(uptr From, uptr To) {
9090
DCHECK_EQ((To - From) % getPageSizeCached(), 0U);
91-
ReleasedPagesCount += (To - From) / getPageSizeCached();
91+
ReleasedPagesCount += (To - From) >> getPageSizeLogCached();
9292
}
9393

9494
private:
@@ -348,7 +348,7 @@ class RegionPageMap {
348348
template <class ReleaseRecorderT> class FreePagesRangeTracker {
349349
public:
350350
explicit FreePagesRangeTracker(ReleaseRecorderT &Recorder)
351-
: Recorder(Recorder), PageSizeLog(getLog2(getPageSizeCached())) {}
351+
: Recorder(Recorder) {}
352352

353353
void processNextPage(bool Released) {
354354
if (Released) {
@@ -372,14 +372,14 @@ template <class ReleaseRecorderT> class FreePagesRangeTracker {
372372
private:
373373
void closeOpenedRange() {
374374
if (InRange) {
375+
const uptr PageSizeLog = getPageSizeLogCached();
375376
Recorder.releasePageRangeToOS((CurrentRangeStatePage << PageSizeLog),
376377
(CurrentPage << PageSizeLog));
377378
InRange = false;
378379
}
379380
}
380381

381382
ReleaseRecorderT &Recorder;
382-
const uptr PageSizeLog;
383383
bool InRange = false;
384384
uptr CurrentPage = 0;
385385
uptr CurrentRangeStatePage = 0;
@@ -389,7 +389,7 @@ struct PageReleaseContext {
389389
PageReleaseContext(uptr BlockSize, uptr NumberOfRegions, uptr ReleaseSize,
390390
uptr ReleaseOffset = 0)
391391
: BlockSize(BlockSize), NumberOfRegions(NumberOfRegions) {
392-
PageSize = getPageSizeCached();
392+
const uptr PageSize = getPageSizeCached();
393393
if (BlockSize <= PageSize) {
394394
if (PageSize % BlockSize == 0) {
395395
// Same number of chunks per page, no cross overs.
@@ -408,7 +408,7 @@ struct PageReleaseContext {
408408
SameBlockCountPerPage = false;
409409
}
410410
} else {
411-
if (BlockSize % PageSize == 0) {
411+
if ((BlockSize & (PageSize - 1)) == 0) {
412412
// One chunk covers multiple pages, no cross overs.
413413
FullPagesBlockCountMax = 1;
414414
SameBlockCountPerPage = true;
@@ -427,8 +427,8 @@ struct PageReleaseContext {
427427
if (NumberOfRegions != 1)
428428
DCHECK_EQ(ReleaseOffset, 0U);
429429

430-
PagesCount = roundUp(ReleaseSize, PageSize) / PageSize;
431-
PageSizeLog = getLog2(PageSize);
430+
const uptr PageSizeLog = getPageSizeLogCached();
431+
PagesCount = roundUp(ReleaseSize, PageSize) >> PageSizeLog;
432432
ReleasePageOffset = ReleaseOffset >> PageSizeLog;
433433
}
434434

@@ -451,6 +451,7 @@ struct PageReleaseContext {
451451
// RegionSize, it's not necessary to be aligned with page size.
452452
bool markRangeAsAllCounted(uptr From, uptr To, uptr Base,
453453
const uptr RegionIndex, const uptr RegionSize) {
454+
const uptr PageSize = getPageSizeCached();
454455
DCHECK_LT(From, To);
455456
DCHECK_LE(To, Base + RegionSize);
456457
DCHECK_EQ(From % PageSize, 0U);
@@ -544,6 +545,7 @@ struct PageReleaseContext {
544545
if (!ensurePageMapAllocated())
545546
return false;
546547

548+
const uptr PageSize = getPageSizeCached();
547549
if (MayContainLastBlockInRegion) {
548550
const uptr LastBlockInRegion =
549551
((RegionSize / BlockSize) - 1U) * BlockSize;
@@ -605,17 +607,19 @@ struct PageReleaseContext {
605607
return true;
606608
}
607609

608-
uptr getPageIndex(uptr P) { return (P >> PageSizeLog) - ReleasePageOffset; }
609-
uptr getReleaseOffset() { return ReleasePageOffset << PageSizeLog; }
610+
uptr getPageIndex(uptr P) {
611+
return (P >> getPageSizeLogCached()) - ReleasePageOffset;
612+
}
613+
uptr getReleaseOffset() {
614+
return ReleasePageOffset << getPageSizeLogCached();
615+
}
610616

611617
uptr BlockSize;
612618
uptr NumberOfRegions;
613619
// For partial region marking, some pages in front are not needed to be
614620
// counted.
615621
uptr ReleasePageOffset;
616-
uptr PageSize;
617622
uptr PagesCount;
618-
uptr PageSizeLog;
619623
uptr FullPagesBlockCountMax;
620624
bool SameBlockCountPerPage;
621625
RegionPageMap PageMap;
@@ -628,7 +632,7 @@ template <class ReleaseRecorderT, typename SkipRegionT>
628632
NOINLINE void
629633
releaseFreeMemoryToOS(PageReleaseContext &Context,
630634
ReleaseRecorderT &Recorder, SkipRegionT SkipRegion) {
631-
const uptr PageSize = Context.PageSize;
635+
const uptr PageSize = getPageSizeCached();
632636
const uptr BlockSize = Context.BlockSize;
633637
const uptr PagesCount = Context.PagesCount;
634638
const uptr NumberOfRegions = Context.NumberOfRegions;
@@ -671,7 +675,7 @@ releaseFreeMemoryToOS(PageReleaseContext &Context,
671675
uptr PrevPageBoundary = 0;
672676
uptr CurrentBoundary = 0;
673677
if (ReleasePageOffset > 0) {
674-
PrevPageBoundary = ReleasePageOffset * PageSize;
678+
PrevPageBoundary = ReleasePageOffset << getPageSizeLogCached();
675679
CurrentBoundary = roundUpSlow(PrevPageBoundary, BlockSize);
676680
}
677681
for (uptr J = 0; J < PagesCount; J++) {

0 commit comments

Comments
 (0)