@@ -191,21 +191,38 @@ template <typename Config> class SizeClassAllocator32 {
191
191
return BlockSize > PageSize;
192
192
}
193
193
194
+ // Note that the `MaxBlockCount` will be used when we support arbitrary blocks
195
+ // count. Now it's the same as the number of blocks stored in the
196
+ // `TransferBatch`.
194
197
u16 popBlocks (CacheT *C, uptr ClassId, CompactPtrT *ToArray,
195
- const u16 MaxBlockCount) {
198
+ UNUSED const u16 MaxBlockCount) {
199
+ TransferBatchT *B = popBatch (C, ClassId);
200
+ if (!B)
201
+ return 0 ;
202
+
203
+ const u16 Count = B->getCount ();
204
+ DCHECK_GT (Count, 0U );
205
+ B->moveToArray (ToArray);
206
+
207
+ if (ClassId != SizeClassMap::BatchClassId)
208
+ C->deallocate (SizeClassMap::BatchClassId, B);
209
+
210
+ return Count;
211
+ }
212
+
213
+ TransferBatchT *popBatch (CacheT *C, uptr ClassId) {
196
214
DCHECK_LT (ClassId, NumClasses);
197
215
SizeClassInfo *Sci = getSizeClassInfo (ClassId);
198
216
ScopedLock L (Sci->Mutex );
199
-
200
- u16 PopCount = popBlocksImpl (C, ClassId, Sci, ToArray, MaxBlockCount);
201
- if (UNLIKELY (PopCount == 0 )) {
217
+ TransferBatchT *B = popBatchImpl (C, ClassId, Sci);
218
+ if (UNLIKELY (!B)) {
202
219
if (UNLIKELY (!populateFreeList (C, ClassId, Sci)))
203
- return 0U ;
204
- PopCount = popBlocksImpl (C, ClassId, Sci, ToArray, MaxBlockCount);
205
- DCHECK_NE (PopCount, 0U );
220
+ return nullptr ;
221
+ B = popBatchImpl (C, ClassId, Sci);
222
+ // if `populateFreeList` succeeded, we are supposed to get free blocks.
223
+ DCHECK_NE (B, nullptr );
206
224
}
207
-
208
- return PopCount;
225
+ return B;
209
226
}
210
227
211
228
// Push the array of free blocks to the designated batch group.
@@ -493,7 +510,7 @@ template <typename Config> class SizeClassAllocator32 {
493
510
// by TransferBatch is also free for use. We don't need to recycle the
494
511
// TransferBatch. Note that the correctness is maintained by the invariant,
495
512
//
496
- // Each popBlocks () request returns the entire TransferBatch. Returning
513
+ // The unit of each popBatch () request is entire TransferBatch. Return
497
514
// part of the blocks in a TransferBatch is invalid.
498
515
//
499
516
// This ensures that TransferBatch won't leak the address itself while it's
@@ -617,7 +634,7 @@ template <typename Config> class SizeClassAllocator32 {
617
634
BG->Batches .push_front (TB);
618
635
BG->PushedBlocks = 0 ;
619
636
BG->BytesInBGAtLastCheckpoint = 0 ;
620
- BG->MaxCachedPerBatch = TransferBatchT::MaxNumCached ;
637
+ BG->MaxCachedPerBatch = CacheT::getMaxCached ( getSizeByClassId (ClassId)) ;
621
638
622
639
return BG;
623
640
};
@@ -709,11 +726,14 @@ template <typename Config> class SizeClassAllocator32 {
709
726
InsertBlocks (Cur, Array + Size - Count, Count);
710
727
}
711
728
712
- u16 popBlocksImpl (CacheT *C, uptr ClassId, SizeClassInfo *Sci,
713
- CompactPtrT *ToArray, const u16 MaxBlockCount)
729
+ // Pop one TransferBatch from a BatchGroup. The BatchGroup with the smallest
730
+ // group id will be considered first.
731
+ //
732
+ // The region mutex needs to be held while calling this method.
733
+ TransferBatchT *popBatchImpl (CacheT *C, uptr ClassId, SizeClassInfo *Sci)
714
734
REQUIRES(Sci->Mutex) {
715
735
if (Sci->FreeListInfo .BlockList .empty ())
716
- return 0U ;
736
+ return nullptr ;
717
737
718
738
SinglyLinkedList<TransferBatchT> &Batches =
719
739
Sci->FreeListInfo .BlockList .front ()->Batches ;
@@ -726,57 +746,33 @@ template <typename Config> class SizeClassAllocator32 {
726
746
// Block used by `BatchGroup` is from BatchClassId. Turn the block into
727
747
// `TransferBatch` with single block.
728
748
TransferBatchT *TB = reinterpret_cast <TransferBatchT *>(BG);
729
- ToArray[0 ] =
730
- compactPtr (SizeClassMap::BatchClassId, reinterpret_cast <uptr>(TB));
749
+ TB->clear ();
750
+ TB->add (
751
+ compactPtr (SizeClassMap::BatchClassId, reinterpret_cast <uptr>(TB)));
731
752
Sci->FreeListInfo .PoppedBlocks += 1 ;
732
- return 1U ;
753
+ return TB ;
733
754
}
734
755
735
- // So far, instead of always filling the blocks to `MaxBlockCount`, we only
736
- // examine single `TransferBatch` to minimize the time spent on the primary
737
- // allocator. Besides, the sizes of `TransferBatch` and
738
- // `CacheT::getMaxCached()` may also impact the time spent on accessing the
739
- // primary allocator.
740
- // TODO(chiahungduan): Evaluate if we want to always prepare `MaxBlockCount`
741
- // blocks and/or adjust the size of `TransferBatch` according to
742
- // `CacheT::getMaxCached()`.
743
756
TransferBatchT *B = Batches.front ();
757
+ Batches.pop_front ();
744
758
DCHECK_NE (B, nullptr );
745
759
DCHECK_GT (B->getCount (), 0U );
746
760
747
- // BachClassId should always take all blocks in the TransferBatch. Read the
748
- // comment in `pushBatchClassBlocks()` for more details.
749
- const u16 PopCount = ClassId == SizeClassMap::BatchClassId
750
- ? B->getCount ()
751
- : Min (MaxBlockCount, B->getCount ());
752
- B->moveNToArray (ToArray, PopCount);
753
-
754
- // TODO(chiahungduan): The deallocation of unused BatchClassId blocks can be
755
- // done without holding `Mutex`.
756
- if (B->empty ()) {
757
- Batches.pop_front ();
758
- // `TransferBatch` of BatchClassId is self-contained, no need to
759
- // deallocate. Read the comment in `pushBatchClassBlocks()` for more
760
- // details.
761
+ if (Batches.empty ()) {
762
+ BatchGroupT *BG = Sci->FreeListInfo .BlockList .front ();
763
+ Sci->FreeListInfo .BlockList .pop_front ();
764
+
765
+ // We don't keep BatchGroup with zero blocks to avoid empty-checking while
766
+ // allocating. Note that block used by constructing BatchGroup is recorded
767
+ // as free blocks in the last element of BatchGroup::Batches. Which means,
768
+ // once we pop the last TransferBatch, the block is implicitly
769
+ // deallocated.
761
770
if (ClassId != SizeClassMap::BatchClassId)
762
- C->deallocate (SizeClassMap::BatchClassId, B);
763
-
764
- if (Batches.empty ()) {
765
- BatchGroupT *BG = Sci->FreeListInfo .BlockList .front ();
766
- Sci->FreeListInfo .BlockList .pop_front ();
767
-
768
- // We don't keep BatchGroup with zero blocks to avoid empty-checking
769
- // while allocating. Note that block used for constructing BatchGroup is
770
- // recorded as free blocks in the last element of BatchGroup::Batches.
771
- // Which means, once we pop the last TransferBatch, the block is
772
- // implicitly deallocated.
773
- if (ClassId != SizeClassMap::BatchClassId)
774
- C->deallocate (SizeClassMap::BatchClassId, BG);
775
- }
771
+ C->deallocate (SizeClassMap::BatchClassId, BG);
776
772
}
777
773
778
- Sci->FreeListInfo .PoppedBlocks += PopCount ;
779
- return PopCount ;
774
+ Sci->FreeListInfo .PoppedBlocks += B-> getCount () ;
775
+ return B ;
780
776
}
781
777
782
778
NOINLINE bool populateFreeList (CacheT *C, uptr ClassId, SizeClassInfo *Sci)
0 commit comments