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 "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 {
     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