@@ -22,6 +22,74 @@ template <class SizeClassAllocator> struct SizeClassAllocatorLocalCache {
22
22
typedef typename SizeClassAllocator::SizeClassMap SizeClassMap;
23
23
typedef typename SizeClassAllocator::CompactPtrT CompactPtrT;
24
24
25
+ struct TransferBatch {
26
+ static const u16 MaxNumCached = SizeClassMap::MaxNumCachedHint;
27
+ void setFromArray (CompactPtrT *Array, u16 N) {
28
+ DCHECK_LE (N, MaxNumCached);
29
+ Count = N;
30
+ memcpy (Batch, Array, sizeof (Batch[0 ]) * Count);
31
+ }
32
+ void appendFromArray (CompactPtrT *Array, u16 N) {
33
+ DCHECK_LE (N, MaxNumCached - Count);
34
+ memcpy (Batch + Count, Array, sizeof (Batch[0 ]) * N);
35
+ // u16 will be promoted to int by arithmetic type conversion.
36
+ Count = static_cast <u16>(Count + N);
37
+ }
38
+ void appendFromTransferBatch (TransferBatch *B, u16 N) {
39
+ DCHECK_LE (N, MaxNumCached - Count);
40
+ DCHECK_GE (B->Count , N);
41
+ // Append from the back of `B`.
42
+ memcpy (Batch + Count, B->Batch + (B->Count - N), sizeof (Batch[0 ]) * N);
43
+ // u16 will be promoted to int by arithmetic type conversion.
44
+ Count = static_cast <u16>(Count + N);
45
+ B->Count = static_cast <u16>(B->Count - N);
46
+ }
47
+ void clear () { Count = 0 ; }
48
+ void add (CompactPtrT P) {
49
+ DCHECK_LT (Count, MaxNumCached);
50
+ Batch[Count++] = P;
51
+ }
52
+ void copyToArray (CompactPtrT *Array) const {
53
+ memcpy (Array, Batch, sizeof (Batch[0 ]) * Count);
54
+ }
55
+ u16 getCount () const { return Count; }
56
+ bool isEmpty () const { return Count == 0U ; }
57
+ CompactPtrT get (u16 I) const {
58
+ DCHECK_LE (I, Count);
59
+ return Batch[I];
60
+ }
61
+ static u16 getMaxCached (uptr Size ) {
62
+ return Min (MaxNumCached, SizeClassMap::getMaxCachedHint (Size ));
63
+ }
64
+ TransferBatch *Next;
65
+
66
+ private:
67
+ CompactPtrT Batch[MaxNumCached];
68
+ u16 Count;
69
+ };
70
+
71
+ // A BatchGroup is used to collect blocks. Each group has a group id to
72
+ // identify the group kind of contained blocks.
73
+ struct BatchGroup {
74
+ // `Next` is used by IntrusiveList.
75
+ BatchGroup *Next;
76
+ // The compact base address of each group
77
+ uptr CompactPtrGroupBase;
78
+ // Cache value of TransferBatch::getMaxCached()
79
+ u16 MaxCachedPerBatch;
80
+ // Number of blocks pushed into this group. This is an increment-only
81
+ // counter.
82
+ uptr PushedBlocks;
83
+ // This is used to track how many bytes are not in-use since last time we
84
+ // tried to release pages.
85
+ uptr BytesInBGAtLastCheckpoint;
86
+ // Blocks are managed by TransferBatch in a list.
87
+ SinglyLinkedList<TransferBatch> Batches;
88
+ };
89
+
90
+ static_assert (sizeof (BatchGroup) <= sizeof (TransferBatch),
91
+ " BatchGroup uses the same class size as TransferBatch" );
92
+
25
93
void init (GlobalStats *S, SizeClassAllocator *A) {
26
94
DCHECK (isEmpty ());
27
95
Stats.init ();
@@ -83,7 +151,7 @@ template <class SizeClassAllocator> struct SizeClassAllocatorLocalCache {
83
151
}
84
152
85
153
void drain () {
86
- // Drain BatchClassId last as it may be needed while draining normal blocks .
154
+ // Drain BatchClassId last as createBatch can refill it .
87
155
for (uptr I = 0 ; I < NumClasses; ++I) {
88
156
if (I == BatchClassId)
89
157
continue ;
@@ -95,11 +163,19 @@ template <class SizeClassAllocator> struct SizeClassAllocatorLocalCache {
95
163
DCHECK (isEmpty ());
96
164
}
97
165
98
- void *getBatchClassBlock () {
99
- void *B = allocate (BatchClassId);
166
+ TransferBatch *createBatch (uptr ClassId, void *B) {
167
+ if (ClassId != BatchClassId)
168
+ B = allocate (BatchClassId);
100
169
if (UNLIKELY (!B))
101
170
reportOutOfMemory (SizeClassAllocator::getSizeByClassId (BatchClassId));
102
- return B;
171
+ return reinterpret_cast <TransferBatch *>(B);
172
+ }
173
+
174
+ BatchGroup *createGroup () {
175
+ void *Ptr = allocate (BatchClassId);
176
+ if (UNLIKELY (!Ptr ))
177
+ reportOutOfMemory (SizeClassAllocator::getSizeByClassId (BatchClassId));
178
+ return reinterpret_cast <BatchGroup *>(Ptr );
103
179
}
104
180
105
181
LocalStats &getStats () { return Stats; }
@@ -127,11 +203,6 @@ template <class SizeClassAllocator> struct SizeClassAllocatorLocalCache {
127
203
Str->append (" No block is cached.\n " );
128
204
}
129
205
130
- static u16 getMaxCached (uptr Size ) {
131
- return Min (SizeClassMap::MaxNumCachedHint,
132
- SizeClassMap::getMaxCachedHint (Size ));
133
- }
134
-
135
206
private:
136
207
static const uptr NumClasses = SizeClassMap::NumClasses;
137
208
static const uptr BatchClassId = SizeClassMap::BatchClassId;
@@ -140,7 +211,7 @@ template <class SizeClassAllocator> struct SizeClassAllocatorLocalCache {
140
211
u16 MaxCount;
141
212
// Note: ClassSize is zero for the transfer batch.
142
213
uptr ClassSize;
143
- CompactPtrT Chunks[2 * SizeClassMap::MaxNumCachedHint ];
214
+ CompactPtrT Chunks[2 * TransferBatch::MaxNumCached ];
144
215
};
145
216
PerClass PerClassArray[NumClasses] = {};
146
217
LocalStats Stats;
@@ -157,7 +228,7 @@ template <class SizeClassAllocator> struct SizeClassAllocatorLocalCache {
157
228
for (uptr I = 0 ; I < NumClasses; I++) {
158
229
PerClass *P = &PerClassArray[I];
159
230
const uptr Size = SizeClassAllocator::getSizeByClassId (I);
160
- P->MaxCount = static_cast <u16>(2 * getMaxCached (Size ));
231
+ P->MaxCount = static_cast <u16>(2 * TransferBatch:: getMaxCached (Size ));
161
232
if (I != BatchClassId) {
162
233
P->ClassSize = Size ;
163
234
} else {
@@ -175,14 +246,15 @@ template <class SizeClassAllocator> struct SizeClassAllocatorLocalCache {
175
246
176
247
NOINLINE bool refill (PerClass *C, uptr ClassId) {
177
248
initCacheMaybe (C);
178
-
179
- // TODO(chiahungduan): Pass the max number cached for each size class.
180
- const u16 NumBlocksRefilled =
181
- Allocator->popBlocks (this , ClassId, C->Chunks );
182
- DCHECK_LE (NumBlocksRefilled,
183
- getMaxCached (SizeClassAllocator::getSizeByClassId (ClassId)));
184
- C->Count += NumBlocksRefilled;
185
- return NumBlocksRefilled != 0 ;
249
+ TransferBatch *B = Allocator->popBatch (this , ClassId);
250
+ if (UNLIKELY (!B))
251
+ return false ;
252
+ DCHECK_GT (B->getCount (), 0 );
253
+ C->Count = B->getCount ();
254
+ B->copyToArray (C->Chunks );
255
+ B->clear ();
256
+ destroyBatch (ClassId, B);
257
+ return true ;
186
258
}
187
259
188
260
NOINLINE void drain (PerClass *C, uptr ClassId) {
0 commit comments