Home | History | Annotate | Download | only in space
      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 
     22 namespace art {
     23 namespace gc {
     24 namespace space {
     25 
     26 class 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 
     36 void 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 
    126 class 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 
    154 void 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 
    177 TEST_F(LargeObjectSpaceTest, LargeObjectTest) {
    178   LargeObjectTest();
    179 }
    180 
    181 TEST_F(LargeObjectSpaceTest, RaceTest) {
    182   RaceTest();
    183 }
    184 
    185 }  // namespace space
    186 }  // namespace gc
    187 }  // namespace art
    188