diff options
| -rw-r--r-- | build/Android.gtest.mk | 5 | ||||
| -rw-r--r-- | runtime/gc/heap.h | 2 | ||||
| -rw-r--r-- | runtime/gc/space/dlmalloc_space_base_test.cc | 36 | ||||
| -rw-r--r-- | runtime/gc/space/large_object_space_test.cc | 2 | ||||
| -rw-r--r-- | runtime/gc/space/rosalloc_space_base_test.cc | 34 | ||||
| -rw-r--r-- | runtime/gc/space/space_create_test.cc | 360 | ||||
| -rw-r--r-- | runtime/gc/space/space_test.h | 333 |
7 files changed, 390 insertions, 382 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index d38cd633a2..e3f0c24414 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -194,13 +194,12 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ runtime/gc/collector/immune_spaces_test.cc \ runtime/gc/heap_test.cc \ runtime/gc/reference_queue_test.cc \ - runtime/gc/space/dlmalloc_space_base_test.cc \ runtime/gc/space/dlmalloc_space_static_test.cc \ runtime/gc/space/dlmalloc_space_random_test.cc \ - runtime/gc/space/rosalloc_space_base_test.cc \ + runtime/gc/space/large_object_space_test.cc \ runtime/gc/space/rosalloc_space_static_test.cc \ runtime/gc/space/rosalloc_space_random_test.cc \ - runtime/gc/space/large_object_space_test.cc \ + runtime/gc/space/space_create_test.cc \ runtime/gc/task_processor_test.cc \ runtime/gtest_test.cc \ runtime/handle_scope_test.cc \ diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index e7ea983410..7b531ba322 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -89,7 +89,6 @@ namespace space { class RegionSpace; class RosAllocSpace; class Space; - class SpaceTest; class ZygoteSpace; } // namespace space @@ -1335,7 +1334,6 @@ class Heap { friend class VerifyReferenceCardVisitor; friend class VerifyReferenceVisitor; friend class VerifyObjectVisitor; - friend class space::SpaceTest; DISALLOW_IMPLICIT_CONSTRUCTORS(Heap); }; diff --git a/runtime/gc/space/dlmalloc_space_base_test.cc b/runtime/gc/space/dlmalloc_space_base_test.cc deleted file mode 100644 index 93fe1559a0..0000000000 --- a/runtime/gc/space/dlmalloc_space_base_test.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "space_test.h" - -#include "dlmalloc_space.h" -#include "scoped_thread_state_change.h" - -namespace art { -namespace gc { -namespace space { - -MallocSpace* CreateDlMallocSpace(const std::string& name, size_t initial_size, size_t growth_limit, - size_t capacity, uint8_t* requested_begin) { - return DlMallocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin, false); -} - -TEST_SPACE_CREATE_FN_BASE(DlMallocSpace, CreateDlMallocSpace) - - -} // namespace space -} // namespace gc -} // namespace art diff --git a/runtime/gc/space/large_object_space_test.cc b/runtime/gc/space/large_object_space_test.cc index 05b484af07..ad38724e7d 100644 --- a/runtime/gc/space/large_object_space_test.cc +++ b/runtime/gc/space/large_object_space_test.cc @@ -22,7 +22,7 @@ namespace art { namespace gc { namespace space { -class LargeObjectSpaceTest : public SpaceTest { +class LargeObjectSpaceTest : public SpaceTest<CommonRuntimeTest> { public: void LargeObjectTest(); diff --git a/runtime/gc/space/rosalloc_space_base_test.cc b/runtime/gc/space/rosalloc_space_base_test.cc deleted file mode 100644 index 0c5be03180..0000000000 --- a/runtime/gc/space/rosalloc_space_base_test.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "space_test.h" - -namespace art { -namespace gc { -namespace space { - -MallocSpace* CreateRosAllocSpace(const std::string& name, size_t initial_size, size_t growth_limit, - size_t capacity, uint8_t* requested_begin) { - return RosAllocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin, - Runtime::Current()->GetHeap()->IsLowMemoryMode(), false); -} - -TEST_SPACE_CREATE_FN_BASE(RosAllocSpace, CreateRosAllocSpace) - - -} // namespace space -} // namespace gc -} // namespace art diff --git a/runtime/gc/space/space_create_test.cc b/runtime/gc/space/space_create_test.cc new file mode 100644 index 0000000000..aea2d9f895 --- /dev/null +++ b/runtime/gc/space/space_create_test.cc @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "space_test.h" + +#include "dlmalloc_space.h" +#include "rosalloc_space.h" +#include "scoped_thread_state_change.h" + +namespace art { +namespace gc { +namespace space { + +enum MallocSpaceType { + kMallocSpaceDlMalloc, + kMallocSpaceRosAlloc, +}; + +class SpaceCreateTest : public SpaceTest<CommonRuntimeTestWithParam<MallocSpaceType>> { + public: + MallocSpace* CreateSpace(const std::string& name, + size_t initial_size, + size_t growth_limit, + size_t capacity, + uint8_t* requested_begin) { + const MallocSpaceType type = GetParam(); + if (type == kMallocSpaceDlMalloc) { + return DlMallocSpace::Create(name, + initial_size, + growth_limit, + capacity, + requested_begin, + false); + } + DCHECK_EQ(static_cast<uint32_t>(type), static_cast<uint32_t>(kMallocSpaceRosAlloc)); + return RosAllocSpace::Create(name, + initial_size, + growth_limit, + capacity, + requested_begin, + Runtime::Current()->GetHeap()->IsLowMemoryMode(), + false); + } +}; + +TEST_P(SpaceCreateTest, InitTestBody) { + // This will lead to error messages in the log. + ScopedLogSeverity sls(LogSeverity::FATAL); + + { + // Init < max == growth + std::unique_ptr<Space> space(CreateSpace("test", 16 * MB, 32 * MB, 32 * MB, nullptr)); + EXPECT_TRUE(space != nullptr); + // Init == max == growth + space.reset(CreateSpace("test", 16 * MB, 16 * MB, 16 * MB, nullptr)); + EXPECT_TRUE(space != nullptr); + // Init > max == growth + space.reset(CreateSpace("test", 32 * MB, 16 * MB, 16 * MB, nullptr)); + EXPECT_TRUE(space == nullptr); + // Growth == init < max + space.reset(CreateSpace("test", 16 * MB, 16 * MB, 32 * MB, nullptr)); + EXPECT_TRUE(space != nullptr); + // Growth < init < max + space.reset(CreateSpace("test", 16 * MB, 8 * MB, 32 * MB, nullptr)); + EXPECT_TRUE(space == nullptr); + // Init < growth < max + space.reset(CreateSpace("test", 8 * MB, 16 * MB, 32 * MB, nullptr)); + EXPECT_TRUE(space != nullptr); + // Init < max < growth + space.reset(CreateSpace("test", 8 * MB, 32 * MB, 16 * MB, nullptr)); + EXPECT_TRUE(space == nullptr); + } +} + +// TODO: This test is not very good, we should improve it. +// The test should do more allocations before the creation of the ZygoteSpace, and then do +// allocations after the ZygoteSpace is created. The test should also do some GCs to ensure that +// the GC works with the ZygoteSpace. +TEST_P(SpaceCreateTest, ZygoteSpaceTestBody) { + size_t dummy; + MallocSpace* space(CreateSpace("test", 4 * MB, 16 * MB, 16 * MB, nullptr)); + ASSERT_TRUE(space != nullptr); + + // Make space findable to the heap, will also delete space when runtime is cleaned up + AddSpace(space); + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + + // Succeeds, fits without adjusting the footprint limit. + size_t ptr1_bytes_allocated, ptr1_usable_size, ptr1_bytes_tl_bulk_allocated; + StackHandleScope<3> hs(soa.Self()); + MutableHandle<mirror::Object> ptr1(hs.NewHandle(Alloc(space, + self, + 1 * MB, + &ptr1_bytes_allocated, + &ptr1_usable_size, + &ptr1_bytes_tl_bulk_allocated))); + EXPECT_TRUE(ptr1.Get() != nullptr); + EXPECT_LE(1U * MB, ptr1_bytes_allocated); + EXPECT_LE(1U * MB, ptr1_usable_size); + EXPECT_LE(ptr1_usable_size, ptr1_bytes_allocated); + EXPECT_EQ(ptr1_bytes_tl_bulk_allocated, ptr1_bytes_allocated); + + // Fails, requires a higher footprint limit. + mirror::Object* ptr2 = Alloc(space, self, 8 * MB, &dummy, nullptr, &dummy); + EXPECT_TRUE(ptr2 == nullptr); + + // Succeeds, adjusts the footprint. + size_t ptr3_bytes_allocated, ptr3_usable_size, ptr3_bytes_tl_bulk_allocated; + MutableHandle<mirror::Object> ptr3(hs.NewHandle(AllocWithGrowth(space, + self, + 8 * MB, + &ptr3_bytes_allocated, + &ptr3_usable_size, + &ptr3_bytes_tl_bulk_allocated))); + EXPECT_TRUE(ptr3.Get() != nullptr); + EXPECT_LE(8U * MB, ptr3_bytes_allocated); + EXPECT_LE(8U * MB, ptr3_usable_size); + EXPECT_LE(ptr3_usable_size, ptr3_bytes_allocated); + EXPECT_EQ(ptr3_bytes_tl_bulk_allocated, ptr3_bytes_allocated); + + // Fails, requires a higher footprint limit. + mirror::Object* ptr4 = space->Alloc(self, 8 * MB, &dummy, nullptr, &dummy); + EXPECT_TRUE(ptr4 == nullptr); + + // Also fails, requires a higher allowed footprint. + mirror::Object* ptr5 = space->AllocWithGrowth(self, 8 * MB, &dummy, nullptr, &dummy); + EXPECT_TRUE(ptr5 == nullptr); + + // Release some memory. + size_t free3 = space->AllocationSize(ptr3.Get(), nullptr); + EXPECT_EQ(free3, ptr3_bytes_allocated); + EXPECT_EQ(free3, space->Free(self, ptr3.Assign(nullptr))); + EXPECT_LE(8U * MB, free3); + + // Succeeds, now that memory has been freed. + size_t ptr6_bytes_allocated, ptr6_usable_size, ptr6_bytes_tl_bulk_allocated; + Handle<mirror::Object> ptr6(hs.NewHandle(AllocWithGrowth(space, + self, + 9 * MB, + &ptr6_bytes_allocated, + &ptr6_usable_size, + &ptr6_bytes_tl_bulk_allocated))); + EXPECT_TRUE(ptr6.Get() != nullptr); + EXPECT_LE(9U * MB, ptr6_bytes_allocated); + EXPECT_LE(9U * MB, ptr6_usable_size); + EXPECT_LE(ptr6_usable_size, ptr6_bytes_allocated); + EXPECT_EQ(ptr6_bytes_tl_bulk_allocated, ptr6_bytes_allocated); + + // Final clean up. + size_t free1 = space->AllocationSize(ptr1.Get(), nullptr); + space->Free(self, ptr1.Assign(nullptr)); + EXPECT_LE(1U * MB, free1); + + // Make sure that the zygote space isn't directly at the start of the space. + EXPECT_TRUE(space->Alloc(self, 1U * MB, &dummy, nullptr, &dummy) != nullptr); + + gc::Heap* heap = Runtime::Current()->GetHeap(); + space::Space* old_space = space; + heap->RemoveSpace(old_space); + heap->RevokeAllThreadLocalBuffers(); + space::ZygoteSpace* zygote_space = space->CreateZygoteSpace("alloc space", + heap->IsLowMemoryMode(), + &space); + delete old_space; + // Add the zygote space. + AddSpace(zygote_space, false); + + // Make space findable to the heap, will also delete space when runtime is cleaned up + AddSpace(space, false); + + // Succeeds, fits without adjusting the footprint limit. + ptr1.Assign(Alloc(space, + self, + 1 * MB, + &ptr1_bytes_allocated, + &ptr1_usable_size, + &ptr1_bytes_tl_bulk_allocated)); + EXPECT_TRUE(ptr1.Get() != nullptr); + EXPECT_LE(1U * MB, ptr1_bytes_allocated); + EXPECT_LE(1U * MB, ptr1_usable_size); + EXPECT_LE(ptr1_usable_size, ptr1_bytes_allocated); + EXPECT_EQ(ptr1_bytes_tl_bulk_allocated, ptr1_bytes_allocated); + + // Fails, requires a higher footprint limit. + ptr2 = Alloc(space, self, 8 * MB, &dummy, nullptr, &dummy); + EXPECT_TRUE(ptr2 == nullptr); + + // Succeeds, adjusts the footprint. + ptr3.Assign(AllocWithGrowth(space, + self, + 2 * MB, + &ptr3_bytes_allocated, + &ptr3_usable_size, + &ptr3_bytes_tl_bulk_allocated)); + EXPECT_TRUE(ptr3.Get() != nullptr); + EXPECT_LE(2U * MB, ptr3_bytes_allocated); + EXPECT_LE(2U * MB, ptr3_usable_size); + EXPECT_LE(ptr3_usable_size, ptr3_bytes_allocated); + EXPECT_EQ(ptr3_bytes_tl_bulk_allocated, ptr3_bytes_allocated); + space->Free(self, ptr3.Assign(nullptr)); + + // Final clean up. + free1 = space->AllocationSize(ptr1.Get(), nullptr); + space->Free(self, ptr1.Assign(nullptr)); + EXPECT_LE(1U * MB, free1); +} + +TEST_P(SpaceCreateTest, AllocAndFreeTestBody) { + size_t dummy = 0; + MallocSpace* space(CreateSpace("test", 4 * MB, 16 * MB, 16 * MB, nullptr)); + ASSERT_TRUE(space != nullptr); + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + + // Make space findable to the heap, will also delete space when runtime is cleaned up + AddSpace(space); + + // Succeeds, fits without adjusting the footprint limit. + size_t ptr1_bytes_allocated, ptr1_usable_size, ptr1_bytes_tl_bulk_allocated; + StackHandleScope<3> hs(soa.Self()); + MutableHandle<mirror::Object> ptr1(hs.NewHandle(Alloc(space, + self, + 1 * MB, + &ptr1_bytes_allocated, + &ptr1_usable_size, + &ptr1_bytes_tl_bulk_allocated))); + EXPECT_TRUE(ptr1.Get() != nullptr); + EXPECT_LE(1U * MB, ptr1_bytes_allocated); + EXPECT_LE(1U * MB, ptr1_usable_size); + EXPECT_LE(ptr1_usable_size, ptr1_bytes_allocated); + EXPECT_EQ(ptr1_bytes_tl_bulk_allocated, ptr1_bytes_allocated); + + // Fails, requires a higher footprint limit. + mirror::Object* ptr2 = Alloc(space, self, 8 * MB, &dummy, nullptr, &dummy); + EXPECT_TRUE(ptr2 == nullptr); + + // Succeeds, adjusts the footprint. + size_t ptr3_bytes_allocated, ptr3_usable_size, ptr3_bytes_tl_bulk_allocated; + MutableHandle<mirror::Object> ptr3(hs.NewHandle(AllocWithGrowth(space, + self, + 8 * MB, + &ptr3_bytes_allocated, + &ptr3_usable_size, + &ptr3_bytes_tl_bulk_allocated))); + EXPECT_TRUE(ptr3.Get() != nullptr); + EXPECT_LE(8U * MB, ptr3_bytes_allocated); + EXPECT_LE(8U * MB, ptr3_usable_size); + EXPECT_LE(ptr3_usable_size, ptr3_bytes_allocated); + EXPECT_EQ(ptr3_bytes_tl_bulk_allocated, ptr3_bytes_allocated); + + // Fails, requires a higher footprint limit. + mirror::Object* ptr4 = Alloc(space, self, 8 * MB, &dummy, nullptr, &dummy); + EXPECT_TRUE(ptr4 == nullptr); + + // Also fails, requires a higher allowed footprint. + mirror::Object* ptr5 = AllocWithGrowth(space, self, 8 * MB, &dummy, nullptr, &dummy); + EXPECT_TRUE(ptr5 == nullptr); + + // Release some memory. + size_t free3 = space->AllocationSize(ptr3.Get(), nullptr); + EXPECT_EQ(free3, ptr3_bytes_allocated); + space->Free(self, ptr3.Assign(nullptr)); + EXPECT_LE(8U * MB, free3); + + // Succeeds, now that memory has been freed. + size_t ptr6_bytes_allocated, ptr6_usable_size, ptr6_bytes_tl_bulk_allocated; + Handle<mirror::Object> ptr6(hs.NewHandle(AllocWithGrowth(space, + self, + 9 * MB, + &ptr6_bytes_allocated, + &ptr6_usable_size, + &ptr6_bytes_tl_bulk_allocated))); + EXPECT_TRUE(ptr6.Get() != nullptr); + EXPECT_LE(9U * MB, ptr6_bytes_allocated); + EXPECT_LE(9U * MB, ptr6_usable_size); + EXPECT_LE(ptr6_usable_size, ptr6_bytes_allocated); + EXPECT_EQ(ptr6_bytes_tl_bulk_allocated, ptr6_bytes_allocated); + + // Final clean up. + size_t free1 = space->AllocationSize(ptr1.Get(), nullptr); + space->Free(self, ptr1.Assign(nullptr)); + EXPECT_LE(1U * MB, free1); +} + +TEST_P(SpaceCreateTest, AllocAndFreeListTestBody) { + MallocSpace* space(CreateSpace("test", 4 * MB, 16 * MB, 16 * MB, nullptr)); + ASSERT_TRUE(space != nullptr); + + // Make space findable to the heap, will also delete space when runtime is cleaned up + AddSpace(space); + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + + // Succeeds, fits without adjusting the max allowed footprint. + mirror::Object* lots_of_objects[1024]; + for (size_t i = 0; i < arraysize(lots_of_objects); i++) { + size_t allocation_size, usable_size, bytes_tl_bulk_allocated; + size_t size_of_zero_length_byte_array = SizeOfZeroLengthByteArray(); + lots_of_objects[i] = Alloc(space, + self, + size_of_zero_length_byte_array, + &allocation_size, + &usable_size, + &bytes_tl_bulk_allocated); + EXPECT_TRUE(lots_of_objects[i] != nullptr); + size_t computed_usable_size; + EXPECT_EQ(allocation_size, space->AllocationSize(lots_of_objects[i], &computed_usable_size)); + EXPECT_EQ(usable_size, computed_usable_size); + EXPECT_TRUE(bytes_tl_bulk_allocated == 0 || + bytes_tl_bulk_allocated >= allocation_size); + } + + // Release memory. + space->FreeList(self, arraysize(lots_of_objects), lots_of_objects); + + // Succeeds, fits by adjusting the max allowed footprint. + for (size_t i = 0; i < arraysize(lots_of_objects); i++) { + size_t allocation_size, usable_size, bytes_tl_bulk_allocated; + lots_of_objects[i] = AllocWithGrowth(space, + self, + 1024, + &allocation_size, + &usable_size, + &bytes_tl_bulk_allocated); + EXPECT_TRUE(lots_of_objects[i] != nullptr); + size_t computed_usable_size; + EXPECT_EQ(allocation_size, space->AllocationSize(lots_of_objects[i], &computed_usable_size)); + EXPECT_EQ(usable_size, computed_usable_size); + EXPECT_TRUE(bytes_tl_bulk_allocated == 0 || + bytes_tl_bulk_allocated >= allocation_size); + } + + // Release memory. + space->FreeList(self, arraysize(lots_of_objects), lots_of_objects); +} + +INSTANTIATE_TEST_CASE_P(CreateRosAllocSpace, + SpaceCreateTest, + testing::Values(kMallocSpaceRosAlloc)); +INSTANTIATE_TEST_CASE_P(CreateDlMallocSpace, + SpaceCreateTest, + testing::Values(kMallocSpaceDlMalloc)); + +} // namespace space +} // namespace gc +} // namespace art diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h index 4d2db11ac2..e588eb3efa 100644 --- a/runtime/gc/space/space_test.h +++ b/runtime/gc/space/space_test.h @@ -33,12 +33,10 @@ namespace art { namespace gc { namespace space { -class SpaceTest : public CommonRuntimeTest { +template <class Super> +class SpaceTest : public Super { public: - jobject byte_array_class_; - - SpaceTest() : byte_array_class_(nullptr) { - } + jobject byte_array_class_ = nullptr; void AddSpace(ContinuousSpace* space, bool revoke = true) { Heap* heap = Runtime::Current()->GetHeap(); @@ -62,13 +60,19 @@ class SpaceTest : public CommonRuntimeTest { return reinterpret_cast<mirror::Class*>(self->DecodeJObject(byte_array_class_)); } - mirror::Object* Alloc(space::MallocSpace* alloc_space, Thread* self, size_t bytes, - size_t* bytes_allocated, size_t* usable_size, + mirror::Object* Alloc(space::MallocSpace* alloc_space, + Thread* self, + size_t bytes, + size_t* bytes_allocated, + size_t* usable_size, size_t* bytes_tl_bulk_allocated) SHARED_REQUIRES(Locks::mutator_lock_) { StackHandleScope<1> hs(self); Handle<mirror::Class> byte_array_class(hs.NewHandle(GetByteArrayClass(self))); - mirror::Object* obj = alloc_space->Alloc(self, bytes, bytes_allocated, usable_size, + mirror::Object* obj = alloc_space->Alloc(self, + bytes, + bytes_allocated, + usable_size, bytes_tl_bulk_allocated); if (obj != nullptr) { InstallClass(obj, byte_array_class.Get(), bytes); @@ -76,8 +80,11 @@ class SpaceTest : public CommonRuntimeTest { return obj; } - mirror::Object* AllocWithGrowth(space::MallocSpace* alloc_space, Thread* self, size_t bytes, - size_t* bytes_allocated, size_t* usable_size, + mirror::Object* AllocWithGrowth(space::MallocSpace* alloc_space, + Thread* self, + size_t bytes, + size_t* bytes_allocated, + size_t* usable_size, size_t* bytes_tl_bulk_allocated) SHARED_REQUIRES(Locks::mutator_lock_) { StackHandleScope<1> hs(self); @@ -117,10 +124,6 @@ class SpaceTest : public CommonRuntimeTest { typedef MallocSpace* (*CreateSpaceFn)(const std::string& name, size_t initial_size, size_t growth_limit, size_t capacity, uint8_t* requested_begin); - void InitTestBody(CreateSpaceFn create_space); - void ZygoteSpaceTestBody(CreateSpaceFn create_space); - void AllocAndFreeTestBody(CreateSpaceFn create_space); - void AllocAndFreeListTestBody(CreateSpaceFn create_space); void SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t object_size, int round, size_t growth_limit); @@ -132,278 +135,11 @@ static inline size_t test_rand(size_t* seed) { return *seed; } -void SpaceTest::InitTestBody(CreateSpaceFn create_space) { - // This will lead to error messages in the log. - ScopedLogSeverity sls(LogSeverity::FATAL); - - { - // Init < max == growth - std::unique_ptr<Space> space(create_space("test", 16 * MB, 32 * MB, 32 * MB, nullptr)); - EXPECT_TRUE(space.get() != nullptr); - } - { - // Init == max == growth - std::unique_ptr<Space> space(create_space("test", 16 * MB, 16 * MB, 16 * MB, nullptr)); - EXPECT_TRUE(space.get() != nullptr); - } - { - // Init > max == growth - std::unique_ptr<Space> space(create_space("test", 32 * MB, 16 * MB, 16 * MB, nullptr)); - EXPECT_TRUE(space.get() == nullptr); - } - { - // Growth == init < max - std::unique_ptr<Space> space(create_space("test", 16 * MB, 16 * MB, 32 * MB, nullptr)); - EXPECT_TRUE(space.get() != nullptr); - } - { - // Growth < init < max - std::unique_ptr<Space> space(create_space("test", 16 * MB, 8 * MB, 32 * MB, nullptr)); - EXPECT_TRUE(space.get() == nullptr); - } - { - // Init < growth < max - std::unique_ptr<Space> space(create_space("test", 8 * MB, 16 * MB, 32 * MB, nullptr)); - EXPECT_TRUE(space.get() != nullptr); - } - { - // Init < max < growth - std::unique_ptr<Space> space(create_space("test", 8 * MB, 32 * MB, 16 * MB, nullptr)); - EXPECT_TRUE(space.get() == nullptr); - } -} - -// TODO: This test is not very good, we should improve it. -// The test should do more allocations before the creation of the ZygoteSpace, and then do -// allocations after the ZygoteSpace is created. The test should also do some GCs to ensure that -// the GC works with the ZygoteSpace. -void SpaceTest::ZygoteSpaceTestBody(CreateSpaceFn create_space) { - size_t dummy; - MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, nullptr)); - ASSERT_TRUE(space != nullptr); - - // Make space findable to the heap, will also delete space when runtime is cleaned up - AddSpace(space); - Thread* self = Thread::Current(); - ScopedObjectAccess soa(self); - - // Succeeds, fits without adjusting the footprint limit. - size_t ptr1_bytes_allocated, ptr1_usable_size, ptr1_bytes_tl_bulk_allocated; - StackHandleScope<3> hs(soa.Self()); - MutableHandle<mirror::Object> ptr1( - hs.NewHandle(Alloc(space, self, 1 * MB, &ptr1_bytes_allocated, &ptr1_usable_size, - &ptr1_bytes_tl_bulk_allocated))); - EXPECT_TRUE(ptr1.Get() != nullptr); - EXPECT_LE(1U * MB, ptr1_bytes_allocated); - EXPECT_LE(1U * MB, ptr1_usable_size); - EXPECT_LE(ptr1_usable_size, ptr1_bytes_allocated); - EXPECT_EQ(ptr1_bytes_tl_bulk_allocated, ptr1_bytes_allocated); - - // Fails, requires a higher footprint limit. - mirror::Object* ptr2 = Alloc(space, self, 8 * MB, &dummy, nullptr, &dummy); - EXPECT_TRUE(ptr2 == nullptr); - - // Succeeds, adjusts the footprint. - size_t ptr3_bytes_allocated, ptr3_usable_size, ptr3_bytes_tl_bulk_allocated; - MutableHandle<mirror::Object> ptr3( - hs.NewHandle(AllocWithGrowth(space, self, 8 * MB, &ptr3_bytes_allocated, &ptr3_usable_size, - &ptr3_bytes_tl_bulk_allocated))); - EXPECT_TRUE(ptr3.Get() != nullptr); - EXPECT_LE(8U * MB, ptr3_bytes_allocated); - EXPECT_LE(8U * MB, ptr3_usable_size); - EXPECT_LE(ptr3_usable_size, ptr3_bytes_allocated); - EXPECT_EQ(ptr3_bytes_tl_bulk_allocated, ptr3_bytes_allocated); - - // Fails, requires a higher footprint limit. - mirror::Object* ptr4 = space->Alloc(self, 8 * MB, &dummy, nullptr, &dummy); - EXPECT_TRUE(ptr4 == nullptr); - - // Also fails, requires a higher allowed footprint. - mirror::Object* ptr5 = space->AllocWithGrowth(self, 8 * MB, &dummy, nullptr, &dummy); - EXPECT_TRUE(ptr5 == nullptr); - - // Release some memory. - size_t free3 = space->AllocationSize(ptr3.Get(), nullptr); - EXPECT_EQ(free3, ptr3_bytes_allocated); - EXPECT_EQ(free3, space->Free(self, ptr3.Assign(nullptr))); - EXPECT_LE(8U * MB, free3); - - // Succeeds, now that memory has been freed. - size_t ptr6_bytes_allocated, ptr6_usable_size, ptr6_bytes_tl_bulk_allocated; - Handle<mirror::Object> ptr6( - hs.NewHandle(AllocWithGrowth(space, self, 9 * MB, &ptr6_bytes_allocated, &ptr6_usable_size, - &ptr6_bytes_tl_bulk_allocated))); - EXPECT_TRUE(ptr6.Get() != nullptr); - EXPECT_LE(9U * MB, ptr6_bytes_allocated); - EXPECT_LE(9U * MB, ptr6_usable_size); - EXPECT_LE(ptr6_usable_size, ptr6_bytes_allocated); - EXPECT_EQ(ptr6_bytes_tl_bulk_allocated, ptr6_bytes_allocated); - - // Final clean up. - size_t free1 = space->AllocationSize(ptr1.Get(), nullptr); - space->Free(self, ptr1.Assign(nullptr)); - EXPECT_LE(1U * MB, free1); - - // Make sure that the zygote space isn't directly at the start of the space. - EXPECT_TRUE(space->Alloc(self, 1U * MB, &dummy, nullptr, &dummy) != nullptr); - - gc::Heap* heap = Runtime::Current()->GetHeap(); - space::Space* old_space = space; - heap->RemoveSpace(old_space); - heap->RevokeAllThreadLocalBuffers(); - space::ZygoteSpace* zygote_space = space->CreateZygoteSpace("alloc space", - heap->IsLowMemoryMode(), - &space); - delete old_space; - // Add the zygote space. - AddSpace(zygote_space, false); - - // Make space findable to the heap, will also delete space when runtime is cleaned up - AddSpace(space, false); - - // Succeeds, fits without adjusting the footprint limit. - ptr1.Assign(Alloc(space, self, 1 * MB, &ptr1_bytes_allocated, &ptr1_usable_size, - &ptr1_bytes_tl_bulk_allocated)); - EXPECT_TRUE(ptr1.Get() != nullptr); - EXPECT_LE(1U * MB, ptr1_bytes_allocated); - EXPECT_LE(1U * MB, ptr1_usable_size); - EXPECT_LE(ptr1_usable_size, ptr1_bytes_allocated); - EXPECT_EQ(ptr1_bytes_tl_bulk_allocated, ptr1_bytes_allocated); - - // Fails, requires a higher footprint limit. - ptr2 = Alloc(space, self, 8 * MB, &dummy, nullptr, &dummy); - EXPECT_TRUE(ptr2 == nullptr); - - // Succeeds, adjusts the footprint. - ptr3.Assign(AllocWithGrowth(space, self, 2 * MB, &ptr3_bytes_allocated, &ptr3_usable_size, - &ptr3_bytes_tl_bulk_allocated)); - EXPECT_TRUE(ptr3.Get() != nullptr); - EXPECT_LE(2U * MB, ptr3_bytes_allocated); - EXPECT_LE(2U * MB, ptr3_usable_size); - EXPECT_LE(ptr3_usable_size, ptr3_bytes_allocated); - EXPECT_EQ(ptr3_bytes_tl_bulk_allocated, ptr3_bytes_allocated); - space->Free(self, ptr3.Assign(nullptr)); - - // Final clean up. - free1 = space->AllocationSize(ptr1.Get(), nullptr); - space->Free(self, ptr1.Assign(nullptr)); - EXPECT_LE(1U * MB, free1); -} - -void SpaceTest::AllocAndFreeTestBody(CreateSpaceFn create_space) { - size_t dummy = 0; - MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, nullptr)); - ASSERT_TRUE(space != nullptr); - Thread* self = Thread::Current(); - ScopedObjectAccess soa(self); - - // Make space findable to the heap, will also delete space when runtime is cleaned up - AddSpace(space); - - // Succeeds, fits without adjusting the footprint limit. - size_t ptr1_bytes_allocated, ptr1_usable_size, ptr1_bytes_tl_bulk_allocated; - StackHandleScope<3> hs(soa.Self()); - MutableHandle<mirror::Object> ptr1( - hs.NewHandle(Alloc(space, self, 1 * MB, &ptr1_bytes_allocated, &ptr1_usable_size, - &ptr1_bytes_tl_bulk_allocated))); - EXPECT_TRUE(ptr1.Get() != nullptr); - EXPECT_LE(1U * MB, ptr1_bytes_allocated); - EXPECT_LE(1U * MB, ptr1_usable_size); - EXPECT_LE(ptr1_usable_size, ptr1_bytes_allocated); - EXPECT_EQ(ptr1_bytes_tl_bulk_allocated, ptr1_bytes_allocated); - - // Fails, requires a higher footprint limit. - mirror::Object* ptr2 = Alloc(space, self, 8 * MB, &dummy, nullptr, &dummy); - EXPECT_TRUE(ptr2 == nullptr); - - // Succeeds, adjusts the footprint. - size_t ptr3_bytes_allocated, ptr3_usable_size, ptr3_bytes_tl_bulk_allocated; - MutableHandle<mirror::Object> ptr3( - hs.NewHandle(AllocWithGrowth(space, self, 8 * MB, &ptr3_bytes_allocated, &ptr3_usable_size, - &ptr3_bytes_tl_bulk_allocated))); - EXPECT_TRUE(ptr3.Get() != nullptr); - EXPECT_LE(8U * MB, ptr3_bytes_allocated); - EXPECT_LE(8U * MB, ptr3_usable_size); - EXPECT_LE(ptr3_usable_size, ptr3_bytes_allocated); - EXPECT_EQ(ptr3_bytes_tl_bulk_allocated, ptr3_bytes_allocated); - - // Fails, requires a higher footprint limit. - mirror::Object* ptr4 = Alloc(space, self, 8 * MB, &dummy, nullptr, &dummy); - EXPECT_TRUE(ptr4 == nullptr); - - // Also fails, requires a higher allowed footprint. - mirror::Object* ptr5 = AllocWithGrowth(space, self, 8 * MB, &dummy, nullptr, &dummy); - EXPECT_TRUE(ptr5 == nullptr); - - // Release some memory. - size_t free3 = space->AllocationSize(ptr3.Get(), nullptr); - EXPECT_EQ(free3, ptr3_bytes_allocated); - space->Free(self, ptr3.Assign(nullptr)); - EXPECT_LE(8U * MB, free3); - - // Succeeds, now that memory has been freed. - size_t ptr6_bytes_allocated, ptr6_usable_size, ptr6_bytes_tl_bulk_allocated; - Handle<mirror::Object> ptr6( - hs.NewHandle(AllocWithGrowth(space, self, 9 * MB, &ptr6_bytes_allocated, &ptr6_usable_size, - &ptr6_bytes_tl_bulk_allocated))); - EXPECT_TRUE(ptr6.Get() != nullptr); - EXPECT_LE(9U * MB, ptr6_bytes_allocated); - EXPECT_LE(9U * MB, ptr6_usable_size); - EXPECT_LE(ptr6_usable_size, ptr6_bytes_allocated); - EXPECT_EQ(ptr6_bytes_tl_bulk_allocated, ptr6_bytes_allocated); - - // Final clean up. - size_t free1 = space->AllocationSize(ptr1.Get(), nullptr); - space->Free(self, ptr1.Assign(nullptr)); - EXPECT_LE(1U * MB, free1); -} - -void SpaceTest::AllocAndFreeListTestBody(CreateSpaceFn create_space) { - MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, nullptr)); - ASSERT_TRUE(space != nullptr); - - // Make space findable to the heap, will also delete space when runtime is cleaned up - AddSpace(space); - Thread* self = Thread::Current(); - ScopedObjectAccess soa(self); - - // Succeeds, fits without adjusting the max allowed footprint. - mirror::Object* lots_of_objects[1024]; - for (size_t i = 0; i < arraysize(lots_of_objects); i++) { - size_t allocation_size, usable_size, bytes_tl_bulk_allocated; - size_t size_of_zero_length_byte_array = SizeOfZeroLengthByteArray(); - lots_of_objects[i] = Alloc(space, self, size_of_zero_length_byte_array, &allocation_size, - &usable_size, &bytes_tl_bulk_allocated); - EXPECT_TRUE(lots_of_objects[i] != nullptr); - size_t computed_usable_size; - EXPECT_EQ(allocation_size, space->AllocationSize(lots_of_objects[i], &computed_usable_size)); - EXPECT_EQ(usable_size, computed_usable_size); - EXPECT_TRUE(bytes_tl_bulk_allocated == 0 || - bytes_tl_bulk_allocated >= allocation_size); - } - - // Release memory. - space->FreeList(self, arraysize(lots_of_objects), lots_of_objects); - - // Succeeds, fits by adjusting the max allowed footprint. - for (size_t i = 0; i < arraysize(lots_of_objects); i++) { - size_t allocation_size, usable_size, bytes_tl_bulk_allocated; - lots_of_objects[i] = AllocWithGrowth(space, self, 1024, &allocation_size, &usable_size, - &bytes_tl_bulk_allocated); - EXPECT_TRUE(lots_of_objects[i] != nullptr); - size_t computed_usable_size; - EXPECT_EQ(allocation_size, space->AllocationSize(lots_of_objects[i], &computed_usable_size)); - EXPECT_EQ(usable_size, computed_usable_size); - EXPECT_TRUE(bytes_tl_bulk_allocated == 0 || - bytes_tl_bulk_allocated >= allocation_size); - } - - // Release memory. - space->FreeList(self, arraysize(lots_of_objects), lots_of_objects); -} - -void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t object_size, - int round, size_t growth_limit) { +template <class Super> +void SpaceTest<Super>::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, + intptr_t object_size, + int round, + size_t growth_limit) { if (((object_size > 0 && object_size >= static_cast<intptr_t>(growth_limit))) || ((object_size < 0 && -object_size >= static_cast<intptr_t>(growth_limit)))) { // No allocation can succeed @@ -576,7 +312,9 @@ void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t EXPECT_LE(space->Size(), growth_limit); } -void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, CreateSpaceFn create_space) { +template <class Super> +void SpaceTest<Super>::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, + CreateSpaceFn create_space) { if (object_size < SizeOfZeroLengthByteArray()) { // Too small for the object layout/model. return; @@ -614,25 +352,8 @@ void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, Create SizeFootPrintGrowthLimitAndTrimDriver(-size, spaceFn); \ } -#define TEST_SPACE_CREATE_FN_BASE(spaceName, spaceFn) \ - class spaceName##BaseTest : public SpaceTest { \ - }; \ - \ - TEST_F(spaceName##BaseTest, Init) { \ - InitTestBody(spaceFn); \ - } \ - TEST_F(spaceName##BaseTest, ZygoteSpace) { \ - ZygoteSpaceTestBody(spaceFn); \ - } \ - TEST_F(spaceName##BaseTest, AllocAndFree) { \ - AllocAndFreeTestBody(spaceFn); \ - } \ - TEST_F(spaceName##BaseTest, AllocAndFreeList) { \ - AllocAndFreeListTestBody(spaceFn); \ - } - #define TEST_SPACE_CREATE_FN_STATIC(spaceName, spaceFn) \ - class spaceName##StaticTest : public SpaceTest { \ + class spaceName##StaticTest : public SpaceTest<CommonRuntimeTest> { \ }; \ \ TEST_SizeFootPrintGrowthLimitAndTrimStatic(12B, spaceName, spaceFn, 12) \ @@ -648,7 +369,7 @@ void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, Create TEST_SizeFootPrintGrowthLimitAndTrimStatic(8MB, spaceName, spaceFn, 8 * MB) #define TEST_SPACE_CREATE_FN_RANDOM(spaceName, spaceFn) \ - class spaceName##RandomTest : public SpaceTest { \ + class spaceName##RandomTest : public SpaceTest<CommonRuntimeTest> { \ }; \ \ TEST_SizeFootPrintGrowthLimitAndTrimRandom(16B, spaceName, spaceFn, 16) \ |