1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "large_object_space.h" 18 19#include "base/time_utils.h" 20#include "space_test.h" 21 22namespace art { 23namespace gc { 24namespace space { 25 26class LargeObjectSpaceTest : public SpaceTest<CommonRuntimeTest> { 27 public: 28 void LargeObjectTest(); 29 30 static constexpr size_t kNumThreads = 10; 31 static constexpr size_t kNumIterations = 1000; 32 void RaceTest(); 33}; 34 35 36void LargeObjectSpaceTest::LargeObjectTest() { 37 size_t rand_seed = 0; 38 Thread* const self = Thread::Current(); 39 for (size_t i = 0; i < 2; ++i) { 40 LargeObjectSpace* los = nullptr; 41 const size_t capacity = 128 * MB; 42 if (i == 0) { 43 los = space::LargeObjectMapSpace::Create("large object space"); 44 } else { 45 los = space::FreeListSpace::Create("large object space", nullptr, capacity); 46 } 47 48 // Make sure the bitmap is not empty and actually covers at least how much we expect. 49 CHECK_LT(static_cast<uintptr_t>(los->GetLiveBitmap()->HeapBegin()), 50 static_cast<uintptr_t>(los->GetLiveBitmap()->HeapLimit())); 51 CHECK_LE(static_cast<uintptr_t>(los->GetLiveBitmap()->HeapBegin() + capacity), 52 static_cast<uintptr_t>(los->GetLiveBitmap()->HeapLimit())); 53 54 static const size_t num_allocations = 64; 55 static const size_t max_allocation_size = 0x100000; 56 std::vector<std::pair<mirror::Object*, size_t>> requests; 57 58 for (size_t phase = 0; phase < 2; ++phase) { 59 while (requests.size() < num_allocations) { 60 size_t request_size = test_rand(&rand_seed) % max_allocation_size; 61 size_t allocation_size = 0; 62 size_t bytes_tl_bulk_allocated; 63 mirror::Object* obj = los->Alloc(self, request_size, &allocation_size, nullptr, 64 &bytes_tl_bulk_allocated); 65 ASSERT_TRUE(obj != nullptr); 66 ASSERT_EQ(allocation_size, los->AllocationSize(obj, nullptr)); 67 ASSERT_GE(allocation_size, request_size); 68 ASSERT_EQ(allocation_size, bytes_tl_bulk_allocated); 69 // Fill in our magic value. 70 uint8_t magic = (request_size & 0xFF) | 1; 71 memset(obj, magic, request_size); 72 requests.push_back(std::make_pair(obj, request_size)); 73 } 74 75 // "Randomly" shuffle the requests. 76 for (size_t k = 0; k < 10; ++k) { 77 for (size_t j = 0; j < requests.size(); ++j) { 78 std::swap(requests[j], requests[test_rand(&rand_seed) % requests.size()]); 79 } 80 } 81 82 // Check the zygote flag for the first phase. 83 if (phase == 0) { 84 for (const auto& pair : requests) { 85 mirror::Object* obj = pair.first; 86 ASSERT_FALSE(los->IsZygoteLargeObject(self, obj)); 87 } 88 los->SetAllLargeObjectsAsZygoteObjects(self); 89 for (const auto& pair : requests) { 90 mirror::Object* obj = pair.first; 91 ASSERT_TRUE(los->IsZygoteLargeObject(self, obj)); 92 } 93 } 94 95 // Free 1 / 2 the allocations the first phase, and all the second phase. 96 size_t limit = phase == 0 ? requests.size() / 2 : 0; 97 while (requests.size() > limit) { 98 mirror::Object* obj = requests.back().first; 99 size_t request_size = requests.back().second; 100 requests.pop_back(); 101 uint8_t magic = (request_size & 0xFF) | 1; 102 for (size_t k = 0; k < request_size; ++k) { 103 ASSERT_EQ(reinterpret_cast<const uint8_t*>(obj)[k], magic); 104 } 105 ASSERT_GE(los->Free(Thread::Current(), obj), request_size); 106 } 107 } 108 // Test that dump doesn't crash. 109 std::ostringstream oss; 110 los->Dump(oss); 111 LOG(INFO) << oss.str(); 112 113 size_t bytes_allocated = 0, bytes_tl_bulk_allocated; 114 // Checks that the coalescing works. 115 mirror::Object* obj = los->Alloc(self, 100 * MB, &bytes_allocated, nullptr, 116 &bytes_tl_bulk_allocated); 117 EXPECT_TRUE(obj != nullptr); 118 los->Free(Thread::Current(), obj); 119 120 EXPECT_EQ(0U, los->GetBytesAllocated()); 121 EXPECT_EQ(0U, los->GetObjectsAllocated()); 122 delete los; 123 } 124} 125 126class AllocRaceTask : public Task { 127 public: 128 AllocRaceTask(size_t id, size_t iterations, size_t size, LargeObjectSpace* los) : 129 id_(id), iterations_(iterations), size_(size), los_(los) {} 130 131 void Run(Thread* self) { 132 for (size_t i = 0; i < iterations_ ; ++i) { 133 size_t alloc_size, bytes_tl_bulk_allocated; 134 mirror::Object* ptr = los_->Alloc(self, size_, &alloc_size, nullptr, 135 &bytes_tl_bulk_allocated); 136 137 NanoSleep((id_ + 3) * 1000); // (3+id) mu s 138 139 los_->Free(self, ptr); 140 } 141 } 142 143 virtual void Finalize() { 144 delete this; 145 } 146 147 private: 148 size_t id_; 149 size_t iterations_; 150 size_t size_; 151 LargeObjectSpace* los_; 152}; 153 154void LargeObjectSpaceTest::RaceTest() { 155 for (size_t los_type = 0; los_type < 2; ++los_type) { 156 LargeObjectSpace* los = nullptr; 157 if (los_type == 0) { 158 los = space::LargeObjectMapSpace::Create("large object space"); 159 } else { 160 los = space::FreeListSpace::Create("large object space", nullptr, 128 * MB); 161 } 162 163 Thread* self = Thread::Current(); 164 ThreadPool thread_pool("Large object space test thread pool", kNumThreads); 165 for (size_t i = 0; i < kNumThreads; ++i) { 166 thread_pool.AddTask(self, new AllocRaceTask(i, kNumIterations, 16 * KB, los)); 167 } 168 169 thread_pool.StartWorkers(self); 170 171 thread_pool.Wait(self, true, false); 172 173 delete los; 174 } 175} 176 177TEST_F(LargeObjectSpaceTest, LargeObjectTest) { 178 LargeObjectTest(); 179} 180 181TEST_F(LargeObjectSpaceTest, RaceTest) { 182 RaceTest(); 183} 184 185} // namespace space 186} // namespace gc 187} // namespace art 188