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