xref: /aosp_15_r20/art/runtime/gc/space/space_test.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_RUNTIME_GC_SPACE_SPACE_TEST_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_RUNTIME_GC_SPACE_SPACE_TEST_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <stdint.h>
21*795d594fSAndroid Build Coastguard Worker #include <memory>
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker #include "common_runtime_test.h"
24*795d594fSAndroid Build Coastguard Worker #include "handle_scope-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
27*795d594fSAndroid Build Coastguard Worker #include "mirror/class_loader.h"
28*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
29*795d594fSAndroid Build Coastguard Worker #include "runtime_globals.h"
30*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
31*795d594fSAndroid Build Coastguard Worker #include "thread_list.h"
32*795d594fSAndroid Build Coastguard Worker #include "zygote_space.h"
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
35*795d594fSAndroid Build Coastguard Worker namespace gc {
36*795d594fSAndroid Build Coastguard Worker namespace space {
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker template <class Super>
39*795d594fSAndroid Build Coastguard Worker class SpaceTest : public Super {
40*795d594fSAndroid Build Coastguard Worker  public:
41*795d594fSAndroid Build Coastguard Worker   jobject byte_array_class_ = nullptr;
42*795d594fSAndroid Build Coastguard Worker 
43*795d594fSAndroid Build Coastguard Worker   void AddSpace(ContinuousSpace* space, bool revoke = true) {
44*795d594fSAndroid Build Coastguard Worker     Heap* heap = Runtime::Current()->GetHeap();
45*795d594fSAndroid Build Coastguard Worker     if (revoke) {
46*795d594fSAndroid Build Coastguard Worker       heap->RevokeAllThreadLocalBuffers();
47*795d594fSAndroid Build Coastguard Worker     }
48*795d594fSAndroid Build Coastguard Worker     {
49*795d594fSAndroid Build Coastguard Worker       ScopedThreadStateChange sts(Thread::Current(), ThreadState::kSuspended);
50*795d594fSAndroid Build Coastguard Worker       ScopedSuspendAll ssa("Add image space");
51*795d594fSAndroid Build Coastguard Worker       heap->AddSpace(space);
52*795d594fSAndroid Build Coastguard Worker     }
53*795d594fSAndroid Build Coastguard Worker     heap->SetSpaceAsDefault(space);
54*795d594fSAndroid Build Coastguard Worker   }
55*795d594fSAndroid Build Coastguard Worker 
GetByteArrayClass(Thread * self)56*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Class> GetByteArrayClass(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
57*795d594fSAndroid Build Coastguard Worker     if (byte_array_class_ == nullptr) {
58*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::Class> byte_array_class =
59*795d594fSAndroid Build Coastguard Worker           Runtime::Current()->GetClassLinker()->FindSystemClass(self, "[B");
60*795d594fSAndroid Build Coastguard Worker       EXPECT_TRUE(byte_array_class != nullptr);
61*795d594fSAndroid Build Coastguard Worker       byte_array_class_ = self->GetJniEnv()->NewLocalRef(byte_array_class.Ptr());
62*795d594fSAndroid Build Coastguard Worker       EXPECT_TRUE(byte_array_class_ != nullptr);
63*795d594fSAndroid Build Coastguard Worker     }
64*795d594fSAndroid Build Coastguard Worker     return self->DecodeJObject(byte_array_class_)->AsClass();
65*795d594fSAndroid Build Coastguard Worker   }
66*795d594fSAndroid Build Coastguard Worker 
Alloc(space::MallocSpace * alloc_space,Thread * self,size_t bytes,size_t * bytes_allocated,size_t * usable_size,size_t * bytes_tl_bulk_allocated)67*795d594fSAndroid Build Coastguard Worker   mirror::Object* Alloc(space::MallocSpace* alloc_space,
68*795d594fSAndroid Build Coastguard Worker                         Thread* self,
69*795d594fSAndroid Build Coastguard Worker                         size_t bytes,
70*795d594fSAndroid Build Coastguard Worker                         size_t* bytes_allocated,
71*795d594fSAndroid Build Coastguard Worker                         size_t* usable_size,
72*795d594fSAndroid Build Coastguard Worker                         size_t* bytes_tl_bulk_allocated)
73*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
74*795d594fSAndroid Build Coastguard Worker     StackHandleScope<1> hs(self);
75*795d594fSAndroid Build Coastguard Worker     Handle<mirror::Class> byte_array_class(hs.NewHandle(GetByteArrayClass(self)));
76*795d594fSAndroid Build Coastguard Worker     mirror::Object* obj = alloc_space->Alloc(self,
77*795d594fSAndroid Build Coastguard Worker                                              bytes,
78*795d594fSAndroid Build Coastguard Worker                                              bytes_allocated,
79*795d594fSAndroid Build Coastguard Worker                                              usable_size,
80*795d594fSAndroid Build Coastguard Worker                                              bytes_tl_bulk_allocated);
81*795d594fSAndroid Build Coastguard Worker     if (obj != nullptr) {
82*795d594fSAndroid Build Coastguard Worker       InstallClass(obj, byte_array_class.Get(), bytes);
83*795d594fSAndroid Build Coastguard Worker     }
84*795d594fSAndroid Build Coastguard Worker     return obj;
85*795d594fSAndroid Build Coastguard Worker   }
86*795d594fSAndroid Build Coastguard Worker 
AllocWithGrowth(space::MallocSpace * alloc_space,Thread * self,size_t bytes,size_t * bytes_allocated,size_t * usable_size,size_t * bytes_tl_bulk_allocated)87*795d594fSAndroid Build Coastguard Worker   mirror::Object* AllocWithGrowth(space::MallocSpace* alloc_space,
88*795d594fSAndroid Build Coastguard Worker                                   Thread* self,
89*795d594fSAndroid Build Coastguard Worker                                   size_t bytes,
90*795d594fSAndroid Build Coastguard Worker                                   size_t* bytes_allocated,
91*795d594fSAndroid Build Coastguard Worker                                   size_t* usable_size,
92*795d594fSAndroid Build Coastguard Worker                                   size_t* bytes_tl_bulk_allocated)
93*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
94*795d594fSAndroid Build Coastguard Worker     StackHandleScope<1> hs(self);
95*795d594fSAndroid Build Coastguard Worker     Handle<mirror::Class> byte_array_class(hs.NewHandle(GetByteArrayClass(self)));
96*795d594fSAndroid Build Coastguard Worker     mirror::Object* obj = alloc_space->AllocWithGrowth(self, bytes, bytes_allocated, usable_size,
97*795d594fSAndroid Build Coastguard Worker                                                        bytes_tl_bulk_allocated);
98*795d594fSAndroid Build Coastguard Worker     if (obj != nullptr) {
99*795d594fSAndroid Build Coastguard Worker       InstallClass(obj, byte_array_class.Get(), bytes);
100*795d594fSAndroid Build Coastguard Worker     }
101*795d594fSAndroid Build Coastguard Worker     return obj;
102*795d594fSAndroid Build Coastguard Worker   }
103*795d594fSAndroid Build Coastguard Worker 
InstallClass(mirror::Object * o,mirror::Class * byte_array_class,size_t size)104*795d594fSAndroid Build Coastguard Worker   void InstallClass(mirror::Object* o, mirror::Class* byte_array_class, size_t size)
105*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
106*795d594fSAndroid Build Coastguard Worker     // Note the minimum size, which is the size of a zero-length byte array.
107*795d594fSAndroid Build Coastguard Worker     EXPECT_GE(size, SizeOfZeroLengthByteArray());
108*795d594fSAndroid Build Coastguard Worker     EXPECT_TRUE(byte_array_class != nullptr);
109*795d594fSAndroid Build Coastguard Worker     o->SetClass(byte_array_class);
110*795d594fSAndroid Build Coastguard Worker     if (kUseBakerReadBarrier) {
111*795d594fSAndroid Build Coastguard Worker       // Like the proper heap object allocation, install and verify
112*795d594fSAndroid Build Coastguard Worker       // the correct read barrier state.
113*795d594fSAndroid Build Coastguard Worker       o->AssertReadBarrierState();
114*795d594fSAndroid Build Coastguard Worker     }
115*795d594fSAndroid Build Coastguard Worker     ObjPtr<mirror::Array> arr = o->AsArray<kVerifyNone>();
116*795d594fSAndroid Build Coastguard Worker     size_t header_size = SizeOfZeroLengthByteArray();
117*795d594fSAndroid Build Coastguard Worker     int32_t length = size - header_size;
118*795d594fSAndroid Build Coastguard Worker     arr->SetLength(length);
119*795d594fSAndroid Build Coastguard Worker     EXPECT_EQ(arr->SizeOf<kVerifyNone>(), size);
120*795d594fSAndroid Build Coastguard Worker   }
121*795d594fSAndroid Build Coastguard Worker 
SizeOfZeroLengthByteArray()122*795d594fSAndroid Build Coastguard Worker   static size_t SizeOfZeroLengthByteArray() {
123*795d594fSAndroid Build Coastguard Worker     return mirror::Array::DataOffset(Primitive::ComponentSize(Primitive::kPrimByte)).Uint32Value();
124*795d594fSAndroid Build Coastguard Worker   }
125*795d594fSAndroid Build Coastguard Worker 
126*795d594fSAndroid Build Coastguard Worker   typedef MallocSpace* (*CreateSpaceFn)(const std::string& name,
127*795d594fSAndroid Build Coastguard Worker                                         size_t initial_size,
128*795d594fSAndroid Build Coastguard Worker                                         size_t growth_limit,
129*795d594fSAndroid Build Coastguard Worker                                         size_t capacity);
130*795d594fSAndroid Build Coastguard Worker 
131*795d594fSAndroid Build Coastguard Worker   void SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t object_size,
132*795d594fSAndroid Build Coastguard Worker                                            int round, size_t growth_limit);
133*795d594fSAndroid Build Coastguard Worker   void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, CreateSpaceFn create_space);
134*795d594fSAndroid Build Coastguard Worker };
135*795d594fSAndroid Build Coastguard Worker 
test_rand(size_t * seed)136*795d594fSAndroid Build Coastguard Worker static inline size_t test_rand(size_t* seed) {
137*795d594fSAndroid Build Coastguard Worker   *seed = *seed * 1103515245 + 12345;
138*795d594fSAndroid Build Coastguard Worker   return *seed;
139*795d594fSAndroid Build Coastguard Worker }
140*795d594fSAndroid Build Coastguard Worker 
141*795d594fSAndroid Build Coastguard Worker template <class Super>
SizeFootPrintGrowthLimitAndTrimBody(MallocSpace * space,intptr_t object_size,int round,size_t growth_limit)142*795d594fSAndroid Build Coastguard Worker void SpaceTest<Super>::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space,
143*795d594fSAndroid Build Coastguard Worker                                                            intptr_t object_size,
144*795d594fSAndroid Build Coastguard Worker                                                            int round,
145*795d594fSAndroid Build Coastguard Worker                                                            size_t growth_limit) {
146*795d594fSAndroid Build Coastguard Worker   if (((object_size > 0 && object_size >= static_cast<intptr_t>(growth_limit))) ||
147*795d594fSAndroid Build Coastguard Worker       ((object_size < 0 && -object_size >= static_cast<intptr_t>(growth_limit)))) {
148*795d594fSAndroid Build Coastguard Worker     // No allocation can succeed
149*795d594fSAndroid Build Coastguard Worker     return;
150*795d594fSAndroid Build Coastguard Worker   }
151*795d594fSAndroid Build Coastguard Worker 
152*795d594fSAndroid Build Coastguard Worker   // The space's footprint equals amount of resources requested from system
153*795d594fSAndroid Build Coastguard Worker   size_t footprint = space->GetFootprint();
154*795d594fSAndroid Build Coastguard Worker 
155*795d594fSAndroid Build Coastguard Worker   // The space must at least have its book keeping allocated
156*795d594fSAndroid Build Coastguard Worker   EXPECT_GT(footprint, 0u);
157*795d594fSAndroid Build Coastguard Worker 
158*795d594fSAndroid Build Coastguard Worker   // But it shouldn't exceed the initial size
159*795d594fSAndroid Build Coastguard Worker   EXPECT_LE(footprint, growth_limit);
160*795d594fSAndroid Build Coastguard Worker 
161*795d594fSAndroid Build Coastguard Worker   // space's size shouldn't exceed the initial size
162*795d594fSAndroid Build Coastguard Worker   EXPECT_LE(space->Size(), growth_limit);
163*795d594fSAndroid Build Coastguard Worker 
164*795d594fSAndroid Build Coastguard Worker   // this invariant should always hold or else the space has grown to be larger than what the
165*795d594fSAndroid Build Coastguard Worker   // space believes its size is (which will break invariants)
166*795d594fSAndroid Build Coastguard Worker   EXPECT_GE(space->Size(), footprint);
167*795d594fSAndroid Build Coastguard Worker 
168*795d594fSAndroid Build Coastguard Worker   // Fill the space with lots of small objects up to the growth limit
169*795d594fSAndroid Build Coastguard Worker   size_t max_objects = (growth_limit / (object_size > 0 ? object_size : 8)) + 1;
170*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<mirror::Object*[]> lots_of_objects(new mirror::Object*[max_objects]);
171*795d594fSAndroid Build Coastguard Worker   size_t last_object = 0;  // last object for which allocation succeeded
172*795d594fSAndroid Build Coastguard Worker   size_t amount_allocated = 0;  // amount of space allocated
173*795d594fSAndroid Build Coastguard Worker   Thread* self = Thread::Current();
174*795d594fSAndroid Build Coastguard Worker   ScopedObjectAccess soa(self);
175*795d594fSAndroid Build Coastguard Worker   size_t rand_seed = 123456789;
176*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < max_objects; i++) {
177*795d594fSAndroid Build Coastguard Worker     size_t alloc_fails = 0;  // number of failed allocations
178*795d594fSAndroid Build Coastguard Worker     size_t max_fails = 30;  // number of times we fail allocation before giving up
179*795d594fSAndroid Build Coastguard Worker     for (; alloc_fails < max_fails; alloc_fails++) {
180*795d594fSAndroid Build Coastguard Worker       size_t alloc_size;
181*795d594fSAndroid Build Coastguard Worker       if (object_size > 0) {
182*795d594fSAndroid Build Coastguard Worker         alloc_size = object_size;
183*795d594fSAndroid Build Coastguard Worker       } else {
184*795d594fSAndroid Build Coastguard Worker         alloc_size = test_rand(&rand_seed) % static_cast<size_t>(-object_size);
185*795d594fSAndroid Build Coastguard Worker         // Note the minimum size, which is the size of a zero-length byte array.
186*795d594fSAndroid Build Coastguard Worker         size_t size_of_zero_length_byte_array = SizeOfZeroLengthByteArray();
187*795d594fSAndroid Build Coastguard Worker         if (alloc_size < size_of_zero_length_byte_array) {
188*795d594fSAndroid Build Coastguard Worker           alloc_size = size_of_zero_length_byte_array;
189*795d594fSAndroid Build Coastguard Worker         }
190*795d594fSAndroid Build Coastguard Worker       }
191*795d594fSAndroid Build Coastguard Worker       StackHandleScope<1> hs(soa.Self());
192*795d594fSAndroid Build Coastguard Worker       auto object(hs.NewHandle<mirror::Object>(nullptr));
193*795d594fSAndroid Build Coastguard Worker       size_t bytes_allocated = 0;
194*795d594fSAndroid Build Coastguard Worker       size_t bytes_tl_bulk_allocated;
195*795d594fSAndroid Build Coastguard Worker       if (round <= 1) {
196*795d594fSAndroid Build Coastguard Worker         object.Assign(Alloc(space, self, alloc_size, &bytes_allocated, nullptr,
197*795d594fSAndroid Build Coastguard Worker                             &bytes_tl_bulk_allocated));
198*795d594fSAndroid Build Coastguard Worker       } else {
199*795d594fSAndroid Build Coastguard Worker         object.Assign(AllocWithGrowth(space, self, alloc_size, &bytes_allocated, nullptr,
200*795d594fSAndroid Build Coastguard Worker                                       &bytes_tl_bulk_allocated));
201*795d594fSAndroid Build Coastguard Worker       }
202*795d594fSAndroid Build Coastguard Worker       footprint = space->GetFootprint();
203*795d594fSAndroid Build Coastguard Worker       EXPECT_GE(space->Size(), footprint);  // invariant
204*795d594fSAndroid Build Coastguard Worker       if (object != nullptr) {  // allocation succeeded
205*795d594fSAndroid Build Coastguard Worker         lots_of_objects[i] = object.Get();
206*795d594fSAndroid Build Coastguard Worker         size_t allocation_size = space->AllocationSize(object.Get(), nullptr);
207*795d594fSAndroid Build Coastguard Worker         EXPECT_EQ(bytes_allocated, allocation_size);
208*795d594fSAndroid Build Coastguard Worker         if (object_size > 0) {
209*795d594fSAndroid Build Coastguard Worker           EXPECT_GE(allocation_size, static_cast<size_t>(object_size));
210*795d594fSAndroid Build Coastguard Worker         } else {
211*795d594fSAndroid Build Coastguard Worker           EXPECT_GE(allocation_size, 8u);
212*795d594fSAndroid Build Coastguard Worker         }
213*795d594fSAndroid Build Coastguard Worker         EXPECT_TRUE(bytes_tl_bulk_allocated == 0 ||
214*795d594fSAndroid Build Coastguard Worker                     bytes_tl_bulk_allocated >= allocation_size);
215*795d594fSAndroid Build Coastguard Worker         amount_allocated += allocation_size;
216*795d594fSAndroid Build Coastguard Worker         break;
217*795d594fSAndroid Build Coastguard Worker       }
218*795d594fSAndroid Build Coastguard Worker     }
219*795d594fSAndroid Build Coastguard Worker     if (alloc_fails == max_fails) {
220*795d594fSAndroid Build Coastguard Worker       last_object = i;
221*795d594fSAndroid Build Coastguard Worker       break;
222*795d594fSAndroid Build Coastguard Worker     }
223*795d594fSAndroid Build Coastguard Worker   }
224*795d594fSAndroid Build Coastguard Worker   CHECK_NE(last_object, 0u);  // we should have filled the space
225*795d594fSAndroid Build Coastguard Worker   EXPECT_GT(amount_allocated, 0u);
226*795d594fSAndroid Build Coastguard Worker 
227*795d594fSAndroid Build Coastguard Worker   // We shouldn't have gone past the growth_limit
228*795d594fSAndroid Build Coastguard Worker   EXPECT_LE(amount_allocated, growth_limit);
229*795d594fSAndroid Build Coastguard Worker   EXPECT_LE(footprint, growth_limit);
230*795d594fSAndroid Build Coastguard Worker   EXPECT_LE(space->Size(), growth_limit);
231*795d594fSAndroid Build Coastguard Worker 
232*795d594fSAndroid Build Coastguard Worker   // footprint and size should agree with amount allocated
233*795d594fSAndroid Build Coastguard Worker   EXPECT_GE(footprint, amount_allocated);
234*795d594fSAndroid Build Coastguard Worker   EXPECT_GE(space->Size(), amount_allocated);
235*795d594fSAndroid Build Coastguard Worker 
236*795d594fSAndroid Build Coastguard Worker   // Release storage in a semi-adhoc manner
237*795d594fSAndroid Build Coastguard Worker   size_t free_increment = 96;
238*795d594fSAndroid Build Coastguard Worker   while (true) {
239*795d594fSAndroid Build Coastguard Worker     {
240*795d594fSAndroid Build Coastguard Worker       ScopedThreadStateChange tsc(self, ThreadState::kNative);
241*795d594fSAndroid Build Coastguard Worker       // Give the space a haircut.
242*795d594fSAndroid Build Coastguard Worker       space->Trim();
243*795d594fSAndroid Build Coastguard Worker     }
244*795d594fSAndroid Build Coastguard Worker 
245*795d594fSAndroid Build Coastguard Worker     // Bounds consistency check.
246*795d594fSAndroid Build Coastguard Worker     footprint = space->GetFootprint();
247*795d594fSAndroid Build Coastguard Worker     EXPECT_LE(amount_allocated, growth_limit);
248*795d594fSAndroid Build Coastguard Worker     EXPECT_GE(footprint, amount_allocated);
249*795d594fSAndroid Build Coastguard Worker     EXPECT_LE(footprint, growth_limit);
250*795d594fSAndroid Build Coastguard Worker     EXPECT_GE(space->Size(), amount_allocated);
251*795d594fSAndroid Build Coastguard Worker     EXPECT_LE(space->Size(), growth_limit);
252*795d594fSAndroid Build Coastguard Worker 
253*795d594fSAndroid Build Coastguard Worker     if (free_increment == 0) {
254*795d594fSAndroid Build Coastguard Worker       break;
255*795d594fSAndroid Build Coastguard Worker     }
256*795d594fSAndroid Build Coastguard Worker 
257*795d594fSAndroid Build Coastguard Worker     // Free some objects
258*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < last_object; i += free_increment) {
259*795d594fSAndroid Build Coastguard Worker       mirror::Object* object = lots_of_objects.get()[i];
260*795d594fSAndroid Build Coastguard Worker       if (object == nullptr) {
261*795d594fSAndroid Build Coastguard Worker         continue;
262*795d594fSAndroid Build Coastguard Worker       }
263*795d594fSAndroid Build Coastguard Worker       size_t allocation_size = space->AllocationSize(object, nullptr);
264*795d594fSAndroid Build Coastguard Worker       if (object_size > 0) {
265*795d594fSAndroid Build Coastguard Worker         EXPECT_GE(allocation_size, static_cast<size_t>(object_size));
266*795d594fSAndroid Build Coastguard Worker       } else {
267*795d594fSAndroid Build Coastguard Worker         EXPECT_GE(allocation_size, 8u);
268*795d594fSAndroid Build Coastguard Worker       }
269*795d594fSAndroid Build Coastguard Worker       space->Free(self, object);
270*795d594fSAndroid Build Coastguard Worker       lots_of_objects.get()[i] = nullptr;
271*795d594fSAndroid Build Coastguard Worker       amount_allocated -= allocation_size;
272*795d594fSAndroid Build Coastguard Worker       footprint = space->GetFootprint();
273*795d594fSAndroid Build Coastguard Worker       EXPECT_GE(space->Size(), footprint);  // invariant
274*795d594fSAndroid Build Coastguard Worker     }
275*795d594fSAndroid Build Coastguard Worker 
276*795d594fSAndroid Build Coastguard Worker     free_increment >>= 1;
277*795d594fSAndroid Build Coastguard Worker   }
278*795d594fSAndroid Build Coastguard Worker 
279*795d594fSAndroid Build Coastguard Worker   // The space has become empty here before allocating a large object
280*795d594fSAndroid Build Coastguard Worker   // below. For RosAlloc, revoke thread-local runs, which are kept
281*795d594fSAndroid Build Coastguard Worker   // even when empty for a performance reason, so that they won't
282*795d594fSAndroid Build Coastguard Worker   // cause the following large object allocation to fail due to
283*795d594fSAndroid Build Coastguard Worker   // potential fragmentation. Note they are normally revoked at each
284*795d594fSAndroid Build Coastguard Worker   // GC (but no GC here.)
285*795d594fSAndroid Build Coastguard Worker   space->RevokeAllThreadLocalBuffers();
286*795d594fSAndroid Build Coastguard Worker 
287*795d594fSAndroid Build Coastguard Worker   // All memory was released, try a large allocation to check freed memory is being coalesced
288*795d594fSAndroid Build Coastguard Worker   StackHandleScope<1> hs(soa.Self());
289*795d594fSAndroid Build Coastguard Worker   auto large_object(hs.NewHandle<mirror::Object>(nullptr));
290*795d594fSAndroid Build Coastguard Worker   size_t three_quarters_space = (growth_limit / 2) + (growth_limit / 4);
291*795d594fSAndroid Build Coastguard Worker   size_t bytes_allocated = 0;
292*795d594fSAndroid Build Coastguard Worker   size_t bytes_tl_bulk_allocated;
293*795d594fSAndroid Build Coastguard Worker   if (round <= 1) {
294*795d594fSAndroid Build Coastguard Worker     large_object.Assign(Alloc(space, self, three_quarters_space, &bytes_allocated, nullptr,
295*795d594fSAndroid Build Coastguard Worker                               &bytes_tl_bulk_allocated));
296*795d594fSAndroid Build Coastguard Worker   } else {
297*795d594fSAndroid Build Coastguard Worker     large_object.Assign(AllocWithGrowth(space, self, three_quarters_space, &bytes_allocated,
298*795d594fSAndroid Build Coastguard Worker                                         nullptr, &bytes_tl_bulk_allocated));
299*795d594fSAndroid Build Coastguard Worker   }
300*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(large_object != nullptr);
301*795d594fSAndroid Build Coastguard Worker 
302*795d594fSAndroid Build Coastguard Worker   // Consistency check of the footprint.
303*795d594fSAndroid Build Coastguard Worker   footprint = space->GetFootprint();
304*795d594fSAndroid Build Coastguard Worker   EXPECT_LE(footprint, growth_limit);
305*795d594fSAndroid Build Coastguard Worker   EXPECT_GE(space->Size(), footprint);
306*795d594fSAndroid Build Coastguard Worker   EXPECT_LE(space->Size(), growth_limit);
307*795d594fSAndroid Build Coastguard Worker 
308*795d594fSAndroid Build Coastguard Worker   // Clean up.
309*795d594fSAndroid Build Coastguard Worker   space->Free(self, large_object.Assign(nullptr));
310*795d594fSAndroid Build Coastguard Worker 
311*795d594fSAndroid Build Coastguard Worker   // Consistency check of the footprint.
312*795d594fSAndroid Build Coastguard Worker   footprint = space->GetFootprint();
313*795d594fSAndroid Build Coastguard Worker   EXPECT_LE(footprint, growth_limit);
314*795d594fSAndroid Build Coastguard Worker   EXPECT_GE(space->Size(), footprint);
315*795d594fSAndroid Build Coastguard Worker   EXPECT_LE(space->Size(), growth_limit);
316*795d594fSAndroid Build Coastguard Worker }
317*795d594fSAndroid Build Coastguard Worker 
318*795d594fSAndroid Build Coastguard Worker template <class Super>
SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size,CreateSpaceFn create_space)319*795d594fSAndroid Build Coastguard Worker void SpaceTest<Super>::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size,
320*795d594fSAndroid Build Coastguard Worker                                                              CreateSpaceFn create_space) {
321*795d594fSAndroid Build Coastguard Worker   if (object_size < SizeOfZeroLengthByteArray()) {
322*795d594fSAndroid Build Coastguard Worker     // Too small for the object layout/model.
323*795d594fSAndroid Build Coastguard Worker     return;
324*795d594fSAndroid Build Coastguard Worker   }
325*795d594fSAndroid Build Coastguard Worker   size_t initial_size = 4 * MB;
326*795d594fSAndroid Build Coastguard Worker   size_t growth_limit = 8 * MB;
327*795d594fSAndroid Build Coastguard Worker   size_t capacity = 16 * MB;
328*795d594fSAndroid Build Coastguard Worker   MallocSpace* space(create_space("test", initial_size, growth_limit, capacity));
329*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(space != nullptr);
330*795d594fSAndroid Build Coastguard Worker 
331*795d594fSAndroid Build Coastguard Worker   // Basic consistency check.
332*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(space->Capacity(), growth_limit);
333*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(space->NonGrowthLimitCapacity(), capacity);
334*795d594fSAndroid Build Coastguard Worker 
335*795d594fSAndroid Build Coastguard Worker   // Make space findable to the heap, will also delete space when runtime is cleaned up
336*795d594fSAndroid Build Coastguard Worker   AddSpace(space);
337*795d594fSAndroid Build Coastguard Worker 
338*795d594fSAndroid Build Coastguard Worker   // In this round we don't allocate with growth and therefore can't grow past the initial size.
339*795d594fSAndroid Build Coastguard Worker   // This effectively makes the growth_limit the initial_size, so assert this.
340*795d594fSAndroid Build Coastguard Worker   SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 1, initial_size);
341*795d594fSAndroid Build Coastguard Worker   SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 2, growth_limit);
342*795d594fSAndroid Build Coastguard Worker   // Remove growth limit
343*795d594fSAndroid Build Coastguard Worker   space->ClearGrowthLimit();
344*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(space->Capacity(), capacity);
345*795d594fSAndroid Build Coastguard Worker   SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 3, capacity);
346*795d594fSAndroid Build Coastguard Worker }
347*795d594fSAndroid Build Coastguard Worker 
348*795d594fSAndroid Build Coastguard Worker #define TEST_SizeFootPrintGrowthLimitAndTrimStatic(name, spaceName, spaceFn, size) \
349*795d594fSAndroid Build Coastguard Worker   TEST_F(spaceName##StaticTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name) { \
350*795d594fSAndroid Build Coastguard Worker     SizeFootPrintGrowthLimitAndTrimDriver(size, spaceFn); \
351*795d594fSAndroid Build Coastguard Worker   }
352*795d594fSAndroid Build Coastguard Worker 
353*795d594fSAndroid Build Coastguard Worker #define TEST_SizeFootPrintGrowthLimitAndTrimRandom(name, spaceName, spaceFn, size) \
354*795d594fSAndroid Build Coastguard Worker   TEST_F(spaceName##RandomTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name) { \
355*795d594fSAndroid Build Coastguard Worker     SizeFootPrintGrowthLimitAndTrimDriver(-(size), spaceFn); \
356*795d594fSAndroid Build Coastguard Worker   }
357*795d594fSAndroid Build Coastguard Worker 
358*795d594fSAndroid Build Coastguard Worker #define TEST_SPACE_CREATE_FN_STATIC(spaceName, spaceFn) \
359*795d594fSAndroid Build Coastguard Worker   class spaceName##StaticTest : public SpaceTest<CommonRuntimeTest> { \
360*795d594fSAndroid Build Coastguard Worker   }; \
361*795d594fSAndroid Build Coastguard Worker   \
362*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimStatic(12B, spaceName, spaceFn, 12) \
363*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimStatic(16B, spaceName, spaceFn, 16) \
364*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimStatic(24B, spaceName, spaceFn, 24) \
365*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimStatic(32B, spaceName, spaceFn, 32) \
366*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimStatic(64B, spaceName, spaceFn, 64) \
367*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimStatic(128B, spaceName, spaceFn, 128) \
368*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimStatic(1KB, spaceName, spaceFn, 1 * KB) \
369*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimStatic(4KB, spaceName, spaceFn, 4 * KB) \
370*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimStatic(1MB, spaceName, spaceFn, 1 * MB) \
371*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimStatic(4MB, spaceName, spaceFn, 4 * MB) \
372*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimStatic(8MB, spaceName, spaceFn, 8 * MB)
373*795d594fSAndroid Build Coastguard Worker 
374*795d594fSAndroid Build Coastguard Worker #define TEST_SPACE_CREATE_FN_RANDOM(spaceName, spaceFn) \
375*795d594fSAndroid Build Coastguard Worker   class spaceName##RandomTest : public SpaceTest<CommonRuntimeTest> { \
376*795d594fSAndroid Build Coastguard Worker   }; \
377*795d594fSAndroid Build Coastguard Worker   \
378*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimRandom(16B, spaceName, spaceFn, 16) \
379*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimRandom(24B, spaceName, spaceFn, 24) \
380*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimRandom(32B, spaceName, spaceFn, 32) \
381*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimRandom(64B, spaceName, spaceFn, 64) \
382*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimRandom(128B, spaceName, spaceFn, 128) \
383*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimRandom(1KB, spaceName, spaceFn, 1 * KB) \
384*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimRandom(4KB, spaceName, spaceFn, 4 * KB) \
385*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimRandom(1MB, spaceName, spaceFn, 1 * MB) \
386*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimRandom(4MB, spaceName, spaceFn, 4 * MB) \
387*795d594fSAndroid Build Coastguard Worker   TEST_SizeFootPrintGrowthLimitAndTrimRandom(8MB, spaceName, spaceFn, 8 * MB)
388*795d594fSAndroid Build Coastguard Worker 
389*795d594fSAndroid Build Coastguard Worker }  // namespace space
390*795d594fSAndroid Build Coastguard Worker }  // namespace gc
391*795d594fSAndroid Build Coastguard Worker }  // namespace art
392*795d594fSAndroid Build Coastguard Worker 
393*795d594fSAndroid Build Coastguard Worker #endif  // ART_RUNTIME_GC_SPACE_SPACE_TEST_H_
394