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 "base/time_utils.h" 18 #include "space_test.h" 19 #include "large_object_space.h" 20 21 namespace art { 22 namespace gc { 23 namespace space { 24 25 class LargeObjectSpaceTest : public SpaceTest<CommonRuntimeTest> { 26 public: 27 void LargeObjectTest(); 28 29 static constexpr size_t kNumThreads = 10; 30 static constexpr size_t kNumIterations = 1000; 31 void RaceTest(); 32 }; 33 34 35 void LargeObjectSpaceTest::LargeObjectTest() { 36 size_t rand_seed = 0; 37 Thread* const self = Thread::Current(); 38 for (size_t i = 0; i < 2; ++i) { 39 LargeObjectSpace* los = nullptr; 40 if (i == 0) { 41 los = space::LargeObjectMapSpace::Create("large object space"); 42 } else { 43 los = space::FreeListSpace::Create("large object space", nullptr, 128 * MB); 44 } 45 46 static const size_t num_allocations = 64; 47 static const size_t max_allocation_size = 0x100000; 48 std::vector<std::pair<mirror::Object*, size_t>> requests; 49 50 for (size_t phase = 0; phase < 2; ++phase) { 51 while (requests.size() < num_allocations) { 52 size_t request_size = test_rand(&rand_seed) % max_allocation_size; 53 size_t allocation_size = 0; 54 size_t bytes_tl_bulk_allocated; 55 mirror::Object* obj = los->Alloc(self, request_size, &allocation_size, nullptr, 56 &bytes_tl_bulk_allocated); 57 ASSERT_TRUE(obj != nullptr); 58 ASSERT_EQ(allocation_size, los->AllocationSize(obj, nullptr)); 59 ASSERT_GE(allocation_size, request_size); 60 ASSERT_EQ(allocation_size, bytes_tl_bulk_allocated); 61 // Fill in our magic value. 62 uint8_t magic = (request_size & 0xFF) | 1; 63 memset(obj, magic, request_size); 64 requests.push_back(std::make_pair(obj, request_size)); 65 } 66 67 // "Randomly" shuffle the requests. 68 for (size_t k = 0; k < 10; ++k) { 69 for (size_t j = 0; j < requests.size(); ++j) { 70 std::swap(requests[j], requests[test_rand(&rand_seed) % requests.size()]); 71 } 72 } 73 74 // Check the zygote flag for the first phase. 75 if (phase == 0) { 76 for (const auto& pair : requests) { 77 mirror::Object* obj = pair.first; 78 ASSERT_FALSE(los->IsZygoteLargeObject(self, obj)); 79 } 80 los->SetAllLargeObjectsAsZygoteObjects(self); 81 for (const auto& pair : requests) { 82 mirror::Object* obj = pair.first; 83 ASSERT_TRUE(los->IsZygoteLargeObject(self, obj)); 84 } 85 } 86 87 // Free 1 / 2 the allocations the first phase, and all the second phase. 88 size_t limit = phase == 0 ? requests.size() / 2 : 0; 89 while (requests.size() > limit) { 90 mirror::Object* obj = requests.back().first; 91 size_t request_size = requests.back().second; 92 requests.pop_back(); 93 uint8_t magic = (request_size & 0xFF) | 1; 94 for (size_t k = 0; k < request_size; ++k) { 95 ASSERT_EQ(reinterpret_cast<const uint8_t*>(obj)[k], magic); 96 } 97 ASSERT_GE(los->Free(Thread::Current(), obj), request_size); 98 } 99 } 100 // Test that dump doesn't crash. 101 los->Dump(LOG(INFO)); 102 103 size_t bytes_allocated = 0, bytes_tl_bulk_allocated; 104 // Checks that the coalescing works. 105 mirror::Object* obj = los->Alloc(self, 100 * MB, &bytes_allocated, nullptr, 106 &bytes_tl_bulk_allocated); 107 EXPECT_TRUE(obj != nullptr); 108 los->Free(Thread::Current(), obj); 109 110 EXPECT_EQ(0U, los->GetBytesAllocated()); 111 EXPECT_EQ(0U, los->GetObjectsAllocated()); 112 delete los; 113 } 114 } 115 116 class AllocRaceTask : public Task { 117 public: 118 AllocRaceTask(size_t id, size_t iterations, size_t size, LargeObjectSpace* los) : 119 id_(id), iterations_(iterations), size_(size), los_(los) {} 120 121 void Run(Thread* self) { 122 for (size_t i = 0; i < iterations_ ; ++i) { 123 size_t alloc_size, bytes_tl_bulk_allocated; 124 mirror::Object* ptr = los_->Alloc(self, size_, &alloc_size, nullptr, 125 &bytes_tl_bulk_allocated); 126 127 NanoSleep((id_ + 3) * 1000); // (3+id) mu s 128 129 los_->Free(self, ptr); 130 } 131 } 132 133 virtual void Finalize() { 134 delete this; 135 } 136 137 private: 138 size_t id_; 139 size_t iterations_; 140 size_t size_; 141 LargeObjectSpace* los_; 142 }; 143 144 void LargeObjectSpaceTest::RaceTest() { 145 for (size_t los_type = 0; los_type < 2; ++los_type) { 146 LargeObjectSpace* los = nullptr; 147 if (los_type == 0) { 148 los = space::LargeObjectMapSpace::Create("large object space"); 149 } else { 150 los = space::FreeListSpace::Create("large object space", nullptr, 128 * MB); 151 } 152 153 Thread* self = Thread::Current(); 154 ThreadPool thread_pool("Large object space test thread pool", kNumThreads); 155 for (size_t i = 0; i < kNumThreads; ++i) { 156 thread_pool.AddTask(self, new AllocRaceTask(i, kNumIterations, 16 * KB, los)); 157 } 158 159 thread_pool.StartWorkers(self); 160 161 thread_pool.Wait(self, true, false); 162 163 delete los; 164 } 165 } 166 167 TEST_F(LargeObjectSpaceTest, LargeObjectTest) { 168 LargeObjectTest(); 169 } 170 171 TEST_F(LargeObjectSpaceTest, RaceTest) { 172 RaceTest(); 173 } 174 175 } // namespace space 176 } // namespace gc 177 } // namespace art 178