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 
LargeObjectTest()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:
AllocRaceTask(size_t id,size_t iterations,size_t size,LargeObjectSpace * los)118   AllocRaceTask(size_t id, size_t iterations, size_t size, LargeObjectSpace* los) :
119     id_(id), iterations_(iterations), size_(size), los_(los) {}
120 
Run(Thread * self)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 
Finalize()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 
RaceTest()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 
TEST_F(LargeObjectSpaceTest,LargeObjectTest)167 TEST_F(LargeObjectSpaceTest, LargeObjectTest) {
168   LargeObjectTest();
169 }
170 
TEST_F(LargeObjectSpaceTest,RaceTest)171 TEST_F(LargeObjectSpaceTest, RaceTest) {
172   RaceTest();
173 }
174 
175 }  // namespace space
176 }  // namespace gc
177 }  // namespace art
178