@@ -49,7 +49,10 @@ class ReleaseRecorder {
49
49
// incremented past MaxValue.
50
50
class PackedCounterArray {
51
51
public:
52
- PackedCounterArray (uptr NumCounters, uptr MaxValue) : N(NumCounters) {
52
+ PackedCounterArray (uptr NumberOfRegions, uptr CountersPerRegion,
53
+ uptr MaxValue)
54
+ : Regions(NumberOfRegions), NumCounters(CountersPerRegion) {
55
+ CHECK_GT (Regions, 0 );
53
56
CHECK_GT (NumCounters, 0 );
54
57
CHECK_GT (MaxValue, 0 );
55
58
constexpr uptr MaxCounterBits = sizeof (*Buffer) * 8UL ;
@@ -66,9 +69,10 @@ class PackedCounterArray {
66
69
PackingRatioLog = getLog2 (PackingRatio);
67
70
BitOffsetMask = PackingRatio - 1 ;
68
71
69
- BufferSize = (roundUpTo (N, static_cast <uptr>(1U ) << PackingRatioLog) >>
70
- PackingRatioLog) *
71
- sizeof (*Buffer);
72
+ SizePerRegion =
73
+ roundUpTo (NumCounters, static_cast <uptr>(1U ) << PackingRatioLog) >>
74
+ PackingRatioLog;
75
+ BufferSize = SizePerRegion * sizeof (*Buffer) * Regions;
72
76
if (BufferSize <= (StaticBufferCount * sizeof (Buffer[0 ])) &&
73
77
Mutex.tryLock ()) {
74
78
Buffer = &StaticBuffer[0 ];
@@ -89,41 +93,45 @@ class PackedCounterArray {
89
93
90
94
bool isAllocated () const { return !!Buffer; }
91
95
92
- uptr getCount () const { return N ; }
96
+ uptr getCount () const { return NumCounters ; }
93
97
94
- uptr get (uptr I) const {
95
- DCHECK_LT (I, N);
98
+ uptr get (uptr Region, uptr I) const {
99
+ DCHECK_LT (Region, Regions);
100
+ DCHECK_LT (I, NumCounters);
96
101
const uptr Index = I >> PackingRatioLog;
97
102
const uptr BitOffset = (I & BitOffsetMask) << CounterSizeBitsLog;
98
- return (Buffer[Index] >> BitOffset) & CounterMask;
103
+ return (Buffer[Region * SizePerRegion + Index] >> BitOffset) & CounterMask;
99
104
}
100
105
101
- void inc (uptr I) const {
102
- DCHECK_LT (get (I), CounterMask);
106
+ void inc (uptr Region, uptr I) const {
107
+ DCHECK_LT (get (Region, I), CounterMask);
103
108
const uptr Index = I >> PackingRatioLog;
104
109
const uptr BitOffset = (I & BitOffsetMask) << CounterSizeBitsLog;
105
110
DCHECK_LT (BitOffset, SCUDO_WORDSIZE);
106
- Buffer[Index] += static_cast <uptr>(1U ) << BitOffset;
111
+ Buffer[Region * SizePerRegion + Index] += static_cast <uptr>(1U )
112
+ << BitOffset;
107
113
}
108
114
109
- void incRange (uptr From, uptr To) const {
115
+ void incRange (uptr Region, uptr From, uptr To) const {
110
116
DCHECK_LE (From, To);
111
- const uptr Top = Min (To + 1 , N );
117
+ const uptr Top = Min (To + 1 , NumCounters );
112
118
for (uptr I = From; I < Top; I++)
113
- inc (I);
119
+ inc (Region, I);
114
120
}
115
121
116
122
uptr getBufferSize () const { return BufferSize; }
117
123
118
- static const uptr StaticBufferCount = 1024U ;
124
+ static const uptr StaticBufferCount = 2048U ;
119
125
120
126
private:
121
- const uptr N;
127
+ const uptr Regions;
128
+ const uptr NumCounters;
122
129
uptr CounterSizeBitsLog;
123
130
uptr CounterMask;
124
131
uptr PackingRatioLog;
125
132
uptr BitOffsetMask;
126
133
134
+ uptr SizePerRegion;
127
135
uptr BufferSize;
128
136
uptr *Buffer;
129
137
@@ -169,7 +177,8 @@ template <class ReleaseRecorderT> class FreePagesRangeTracker {
169
177
template <class TransferBatchT , class ReleaseRecorderT >
170
178
NOINLINE void
171
179
releaseFreeMemoryToOS (const IntrusiveList<TransferBatchT> &FreeList, uptr Base,
172
- uptr Size, uptr BlockSize, ReleaseRecorderT *Recorder) {
180
+ uptr RegionSize, uptr NumberOfRegions, uptr BlockSize,
181
+ ReleaseRecorderT *Recorder) {
173
182
const uptr PageSize = getPageSizeCached ();
174
183
175
184
// Figure out the number of chunks per page and whether we can take a fast
@@ -206,13 +215,15 @@ releaseFreeMemoryToOS(const IntrusiveList<TransferBatchT> &FreeList, uptr Base,
206
215
}
207
216
}
208
217
209
- const uptr PagesCount = roundUpTo (Size, PageSize) / PageSize;
210
- PackedCounterArray Counters (PagesCount, FullPagesBlockCountMax);
218
+ const uptr PagesCount = roundUpTo (RegionSize, PageSize) / PageSize;
219
+ PackedCounterArray Counters (NumberOfRegions, PagesCount,
220
+ FullPagesBlockCountMax);
211
221
if (!Counters.isAllocated ())
212
222
return ;
213
223
214
224
const uptr PageSizeLog = getLog2 (PageSize);
215
- const uptr RoundedSize = PagesCount << PageSizeLog;
225
+ const uptr RoundedRegionSize = PagesCount << PageSizeLog;
226
+ const uptr RoundedSize = NumberOfRegions * RoundedRegionSize;
216
227
217
228
// Iterate over free chunks and count how many free chunks affect each
218
229
// allocated page.
@@ -228,14 +239,17 @@ releaseFreeMemoryToOS(const IntrusiveList<TransferBatchT> &FreeList, uptr Base,
228
239
for (u32 I = IsTransferBatch ? 1 : 0 ; I < It.getCount (); I++) {
229
240
const uptr P = reinterpret_cast <uptr>(It.get (I)) - Base;
230
241
// This takes care of P < Base and P >= Base + RoundedSize.
231
- if (P < RoundedSize)
232
- Counters.inc (P >> PageSizeLog);
242
+ if (P < RoundedSize) {
243
+ const uptr RegionIndex = NumberOfRegions == 1U ? 0 : P / RegionSize;
244
+ const uptr PInRegion = P - RegionIndex * RegionSize;
245
+ Counters.inc (RegionIndex, PInRegion >> PageSizeLog);
246
+ }
233
247
}
234
248
}
235
- for (uptr P = Size; P < RoundedSize; P += BlockSize)
236
- Counters.inc (P >> PageSizeLog);
237
249
} else {
238
250
// In all other cases chunks might affect more than one page.
251
+ DCHECK_GE (RegionSize, BlockSize);
252
+ const uptr LastBlockInRegion = ((RegionSize / BlockSize) - 1U ) * BlockSize;
239
253
for (const auto &It : FreeList) {
240
254
// See TransferBatch comment above.
241
255
const bool IsTransferBatch =
@@ -244,22 +258,35 @@ releaseFreeMemoryToOS(const IntrusiveList<TransferBatchT> &FreeList, uptr Base,
244
258
for (u32 I = IsTransferBatch ? 1 : 0 ; I < It.getCount (); I++) {
245
259
const uptr P = reinterpret_cast <uptr>(It.get (I)) - Base;
246
260
// This takes care of P < Base and P >= Base + RoundedSize.
247
- if (P < RoundedSize)
248
- Counters.incRange (P >> PageSizeLog,
249
- (P + BlockSize - 1 ) >> PageSizeLog);
261
+ if (P < RoundedSize) {
262
+ const uptr RegionIndex = NumberOfRegions == 1U ? 0 : P / RegionSize;
263
+ uptr PInRegion = P - RegionIndex * RegionSize;
264
+ Counters.incRange (RegionIndex, PInRegion >> PageSizeLog,
265
+ (PInRegion + BlockSize - 1 ) >> PageSizeLog);
266
+ // The last block in a region might straddle a page, so if it's
267
+ // free, we mark the following "pretend" memory block(s) as free.
268
+ if (PInRegion == LastBlockInRegion) {
269
+ PInRegion += BlockSize;
270
+ while (PInRegion < RoundedRegionSize) {
271
+ Counters.incRange (RegionIndex, PInRegion >> PageSizeLog,
272
+ (PInRegion + BlockSize - 1 ) >> PageSizeLog);
273
+ PInRegion += BlockSize;
274
+ }
275
+ }
276
+ }
250
277
}
251
278
}
252
- for (uptr P = Size; P < RoundedSize; P += BlockSize)
253
- Counters.incRange (P >> PageSizeLog, (P + BlockSize - 1 ) >> PageSizeLog);
254
279
}
255
280
256
281
// Iterate over pages detecting ranges of pages with chunk Counters equal
257
282
// to the expected number of chunks for the particular page.
258
283
FreePagesRangeTracker<ReleaseRecorderT> RangeTracker (Recorder);
259
284
if (SameBlockCountPerPage) {
260
285
// Fast path, every page has the same number of chunks affecting it.
261
- for (uptr I = 0 ; I < Counters.getCount (); I++)
262
- RangeTracker.processNextPage (Counters.get (I) == FullPagesBlockCountMax);
286
+ for (uptr I = 0 ; I < NumberOfRegions; I++)
287
+ for (uptr J = 0 ; J < PagesCount; J++)
288
+ RangeTracker.processNextPage (Counters.get (I, J) ==
289
+ FullPagesBlockCountMax);
263
290
} else {
264
291
// Slow path, go through the pages keeping count how many chunks affect
265
292
// each page.
@@ -270,23 +297,25 @@ releaseFreeMemoryToOS(const IntrusiveList<TransferBatchT> &FreeList, uptr Base,
270
297
// except the first and the last one) and then the last chunk size, adding
271
298
// up the number of chunks on the current page and checking on every step
272
299
// whether the page boundary was crossed.
273
- uptr PrevPageBoundary = 0 ;
274
- uptr CurrentBoundary = 0 ;
275
- for (uptr I = 0 ; I < Counters.getCount (); I++) {
276
- const uptr PageBoundary = PrevPageBoundary + PageSize;
277
- uptr BlocksPerPage = Pn;
278
- if (CurrentBoundary < PageBoundary) {
279
- if (CurrentBoundary > PrevPageBoundary)
280
- BlocksPerPage++;
281
- CurrentBoundary += Pnc;
300
+ for (uptr I = 0 ; I < NumberOfRegions; I++) {
301
+ uptr PrevPageBoundary = 0 ;
302
+ uptr CurrentBoundary = 0 ;
303
+ for (uptr J = 0 ; J < PagesCount; J++) {
304
+ const uptr PageBoundary = PrevPageBoundary + PageSize;
305
+ uptr BlocksPerPage = Pn;
282
306
if (CurrentBoundary < PageBoundary) {
283
- BlocksPerPage++;
284
- CurrentBoundary += BlockSize;
307
+ if (CurrentBoundary > PrevPageBoundary)
308
+ BlocksPerPage++;
309
+ CurrentBoundary += Pnc;
310
+ if (CurrentBoundary < PageBoundary) {
311
+ BlocksPerPage++;
312
+ CurrentBoundary += BlockSize;
313
+ }
285
314
}
286
- }
287
- PrevPageBoundary = PageBoundary;
315
+ PrevPageBoundary = PageBoundary;
288
316
289
- RangeTracker.processNextPage (Counters.get (I) == BlocksPerPage);
317
+ RangeTracker.processNextPage (Counters.get (I, J) == BlocksPerPage);
318
+ }
290
319
}
291
320
}
292
321
RangeTracker.finish ();
0 commit comments