blob: ad38724e7dba76350c5f866a3c384cc52b9db459 [file] [log] [blame]
Andreas Gampea7433512014-02-21 13:19:23 -08001/*
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
Vladimir Marko41b175a2015-05-19 18:08:00 +010017#include "base/time_utils.h"
Andreas Gampea7433512014-02-21 13:19:23 -080018#include "space_test.h"
19#include "large_object_space.h"
20
21namespace art {
22namespace gc {
23namespace space {
24
Mathieu Chartier28b1cf72016-01-15 16:44:57 -080025class LargeObjectSpaceTest : public SpaceTest<CommonRuntimeTest> {
Andreas Gampea7433512014-02-21 13:19:23 -080026 public:
27 void LargeObjectTest();
Andreas Gampeb8708232014-05-30 14:42:59 -070028
29 static constexpr size_t kNumThreads = 10;
30 static constexpr size_t kNumIterations = 1000;
31 void RaceTest();
Andreas Gampea7433512014-02-21 13:19:23 -080032};
33
34
35void LargeObjectSpaceTest::LargeObjectTest() {
36 size_t rand_seed = 0;
Mathieu Chartier8f236202015-06-03 13:32:15 -070037 Thread* const self = Thread::Current();
Andreas Gampea7433512014-02-21 13:19:23 -080038 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;
Ian Rogers700a4022014-05-19 16:49:03 -070048 std::vector<std::pair<mirror::Object*, size_t>> requests;
Andreas Gampea7433512014-02-21 13:19:23 -080049
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;
Hiroshi Yamauchi4460a842015-03-09 11:57:48 -070054 size_t bytes_tl_bulk_allocated;
Mathieu Chartier8f236202015-06-03 13:32:15 -070055 mirror::Object* obj = los->Alloc(self, request_size, &allocation_size, nullptr,
56 &bytes_tl_bulk_allocated);
Andreas Gampea7433512014-02-21 13:19:23 -080057 ASSERT_TRUE(obj != nullptr);
Ian Rogers6fac4472014-02-25 17:01:10 -080058 ASSERT_EQ(allocation_size, los->AllocationSize(obj, nullptr));
Andreas Gampea7433512014-02-21 13:19:23 -080059 ASSERT_GE(allocation_size, request_size);
Hiroshi Yamauchi4460a842015-03-09 11:57:48 -070060 ASSERT_EQ(allocation_size, bytes_tl_bulk_allocated);
Andreas Gampea7433512014-02-21 13:19:23 -080061 // Fill in our magic value.
Ian Rogers13735952014-10-08 12:43:28 -070062 uint8_t magic = (request_size & 0xFF) | 1;
Andreas Gampea7433512014-02-21 13:19:23 -080063 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
Mathieu Chartier8f236202015-06-03 13:32:15 -070074 // 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
Andreas Gampea7433512014-02-21 13:19:23 -080087 // Free 1 / 2 the allocations the first phase, and all the second phase.
Mathieu Chartier8f236202015-06-03 13:32:15 -070088 size_t limit = phase == 0 ? requests.size() / 2 : 0;
Andreas Gampea7433512014-02-21 13:19:23 -080089 while (requests.size() > limit) {
90 mirror::Object* obj = requests.back().first;
91 size_t request_size = requests.back().second;
92 requests.pop_back();
Ian Rogers13735952014-10-08 12:43:28 -070093 uint8_t magic = (request_size & 0xFF) | 1;
Andreas Gampea7433512014-02-21 13:19:23 -080094 for (size_t k = 0; k < request_size; ++k) {
Ian Rogers13735952014-10-08 12:43:28 -070095 ASSERT_EQ(reinterpret_cast<const uint8_t*>(obj)[k], magic);
Andreas Gampea7433512014-02-21 13:19:23 -080096 }
97 ASSERT_GE(los->Free(Thread::Current(), obj), request_size);
98 }
99 }
Mathieu Chartieraf4edbd2014-09-08 17:42:48 -0700100 // Test that dump doesn't crash.
101 los->Dump(LOG(INFO));
Andreas Gampea7433512014-02-21 13:19:23 -0800102
Hiroshi Yamauchi4460a842015-03-09 11:57:48 -0700103 size_t bytes_allocated = 0, bytes_tl_bulk_allocated;
Andreas Gampea7433512014-02-21 13:19:23 -0800104 // Checks that the coalescing works.
Mathieu Chartier8f236202015-06-03 13:32:15 -0700105 mirror::Object* obj = los->Alloc(self, 100 * MB, &bytes_allocated, nullptr,
Hiroshi Yamauchi4460a842015-03-09 11:57:48 -0700106 &bytes_tl_bulk_allocated);
Andreas Gampea7433512014-02-21 13:19:23 -0800107 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
Andreas Gampeb8708232014-05-30 14:42:59 -0700116class 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) {
Hiroshi Yamauchi4460a842015-03-09 11:57:48 -0700123 size_t alloc_size, bytes_tl_bulk_allocated;
124 mirror::Object* ptr = los_->Alloc(self, size_, &alloc_size, nullptr,
125 &bytes_tl_bulk_allocated);
Andreas Gampeb8708232014-05-30 14:42:59 -0700126
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
144void 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}
Andreas Gampea7433512014-02-21 13:19:23 -0800166
167TEST_F(LargeObjectSpaceTest, LargeObjectTest) {
168 LargeObjectTest();
169}
170
Andreas Gampeb8708232014-05-30 14:42:59 -0700171TEST_F(LargeObjectSpaceTest, RaceTest) {
172 RaceTest();
173}
174
Andreas Gampea7433512014-02-21 13:19:23 -0800175} // namespace space
176} // namespace gc
177} // namespace art