• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <chrono>
17 #include <cstdlib>
18 #include <ctime>
19 #include <random>
20 
21 #include "gtest/gtest.h"
22 #include "runtime/mem/gc/card_table-inl.h"
23 #include "runtime/mem/mem_stats_additional_info.h"
24 #include "runtime/mem/mem_stats_default.h"
25 #include "runtime/mem/internal_allocator-inl.h"
26 #include "runtime/include/runtime_options.h"
27 #include "runtime/include/runtime.h"
28 #include "runtime/include/panda_vm.h"
29 
30 namespace panda::mem::test {
31 
32 class CardTableTest : public testing::Test {
33 protected:
34     // static constexpr size_t kHeapSize = 0xffffffff;
35     static constexpr size_t kAllocCount = 1000;
36     // static constexpr size_t maxCardIndex = kHeapSize / ::panda::mem::CardTable::GetCardSize();
37     std::mt19937 gen;
38     std::uniform_int_distribution<uintptr_t> addrDis;
39     std::uniform_int_distribution<size_t> cardIndexDis;
40 
CardTableTest()41     CardTableTest()
42     {
43 #ifdef PANDA_NIGHTLY_TEST_ON
44         seed_ = std::time(NULL);
45 #else
46         seed_ = 123456U;
47 #endif
48         RuntimeOptions options;
49         options.SetHeapSizeLimit(64_MB);
50         options.SetShouldLoadBootPandaFiles(false);
51         options.SetShouldInitializeIntrinsics(false);
52         options.SetGcType("epsilon");
53         Runtime::Create(options);
54         thread_ = panda::MTManagedThread::GetCurrent();
55         thread_->ManagedCodeBegin();
56 
57         internal_allocator_ = thread_->GetVM()->GetHeapManager()->GetInternalAllocator();
58         addrDis = std::uniform_int_distribution<uintptr_t>(0, GetPoolSize() - 1);
59         ASSERT(GetPoolSize() % CardTable::GetCardSize() == 0);
60         cardIndexDis = std::uniform_int_distribution<size_t>(0, GetPoolSize() / CardTable::GetCardSize() - 1);
61         card_table_ = std::make_unique<CardTable>(internal_allocator_, GetMinAddress(), GetPoolSize());
62         card_table_->Initialize();
63     }
64 
~CardTableTest()65     ~CardTableTest()
66     {
67         card_table_.reset(nullptr);
68         thread_->ManagedCodeEnd();
69         Runtime::Destroy();
70     }
71 
SetUp()72     void SetUp() override
73     {
74         gen.seed(seed_);
75     }
76 
TearDown()77     void TearDown() override
78     {
79         const ::testing::TestInfo *const test_info = ::testing::UnitTest::GetInstance()->current_test_info();
80         if (test_info->result()->Failed()) {
81             std::cout << "CartTableTest seed = " << seed_ << std::endl;
82         }
83     }
84 
GetMinAddress()85     uintptr_t GetMinAddress()
86     {
87         return PoolManager::GetMmapMemPool()->GetMinObjectAddress();
88     }
89 
GetPoolSize()90     size_t GetPoolSize()
91     {
92         return (PoolManager::GetMmapMemPool()->GetMaxObjectAddress() -
93                 PoolManager::GetMmapMemPool()->GetMinObjectAddress());
94     }
95 
GetRandomAddress()96     uintptr_t GetRandomAddress()
97     {
98         return PoolManager::GetMmapMemPool()->GetMinObjectAddress() + addrDis(gen) % GetPoolSize();
99     }
100 
GetRandomCardIndex()101     size_t GetRandomCardIndex()
102     {
103         return cardIndexDis(gen) % GetPoolSize();
104     }
105 
106     // Generate address at the beginning of the card
GetRandomCardAddress()107     uintptr_t GetRandomCardAddress()
108     {
109         return PoolManager::GetMmapMemPool()->GetMinObjectAddress() + GetRandomCardIndex() * CardTable::GetCardSize();
110     }
111 
112     InternalAllocatorPtr internal_allocator_ {nullptr};
113     std::unique_ptr<CardTable> card_table_ {nullptr};
114     unsigned int seed_ {0};
115     panda::MTManagedThread *thread_ {nullptr};
116 };
117 
TEST_F(CardTableTest,MarkTest)118 TEST_F(CardTableTest, MarkTest)
119 {
120     size_t markedCnt = 0;
121     for (size_t i = 0; i < kAllocCount; i++) {
122         uintptr_t addr;
123         addr = GetRandomAddress();
124         if (!card_table_->IsMarked(addr)) {
125             ++markedCnt;
126             card_table_->MarkCard(addr);
127         }
128     }
129 
130     for (auto card : *card_table_) {
131         if (card->IsMarked()) {
132             markedCnt--;
133         }
134     }
135     ASSERT_EQ(markedCnt, 0);
136 }
137 
TEST_F(CardTableTest,MarkAndClearAllTest)138 TEST_F(CardTableTest, MarkAndClearAllTest)
139 {
140     size_t cnt = 0;
141     for (auto card : *card_table_) {
142         card->Mark();
143         cnt++;
144     }
145     ASSERT_EQ(cnt, card_table_->GetCardsCount());
146 
147     size_t cnt_cleared = 0;
148     for (auto card : *card_table_) {
149         card->Clear();
150         cnt_cleared++;
151     }
152     ASSERT_EQ(cnt_cleared, card_table_->GetCardsCount());
153 }
154 
TEST_F(CardTableTest,ClearTest)155 TEST_F(CardTableTest, ClearTest)
156 {
157     std::set<uintptr_t> addrSet;
158 
159     // Mark some cards not more than once
160     while (addrSet.size() <= kAllocCount) {
161         uintptr_t addr;
162         addr = GetRandomCardAddress();
163         if (addrSet.insert(addr).second == false) {
164             continue;
165         }
166         card_table_->MarkCard(addr);
167     }
168 
169     size_t cleared_cnt = 0;
170     // Clear all marked and count them
171     for (auto card : *card_table_) {
172         if (card->IsMarked()) {
173             card->Clear();
174             cleared_cnt++;
175         }
176     }
177 
178     ASSERT_EQ(addrSet.size(), cleared_cnt);
179     // Check that there are no marked
180     for (auto card : *card_table_) {
181         ASSERT_EQ(card->IsMarked(), false);
182     }
183 }
184 
TEST_F(CardTableTest,ClearAllTest)185 TEST_F(CardTableTest, ClearAllTest)
186 {
187     std::set<uintptr_t> addrSet;
188 
189     // Mark some cards not more than once
190     while (addrSet.size() < kAllocCount) {
191         uintptr_t addr;
192         addr = GetRandomCardAddress();
193         if (addrSet.insert(addr).second == false) {
194             continue;
195         }
196         card_table_->MarkCard(addr);
197     }
198 
199     card_table_->ClearAll();
200     for (auto card : *card_table_) {
201         ASSERT_EQ(card->IsMarked(), false);
202     }
203 }
204 
TEST_F(CardTableTest,double_initialization)205 TEST_F(CardTableTest, double_initialization)
206 {
207     EXPECT_DEATH(card_table_->Initialize(), ".*");
208 }
209 
TEST_F(CardTableTest,corner_cases)210 TEST_F(CardTableTest, corner_cases)
211 {
212     // Mark 1st byte in the heap
213     ASSERT_EQ((*card_table_->begin())->IsMarked(), false);
214     card_table_->MarkCard(GetMinAddress());
215     ASSERT_EQ((*card_table_->begin())->IsMarked(), true);
216     // Mark last byte in the heap
217     uintptr_t last = GetMinAddress() + GetPoolSize() - 1;
218     ASSERT_EQ(card_table_->IsMarked(last), false);
219     card_table_->MarkCard(last);
220     ASSERT_EQ(card_table_->IsMarked(last), true);
221     // Mark last byte of second card
222     uintptr_t secondLast = GetMinAddress() + 2 * card_table_->GetCardSize() - 1;
223     ASSERT_EQ(card_table_->IsMarked(secondLast), false);
224     card_table_->MarkCard(secondLast);
225     ASSERT_EQ(((*card_table_->begin()) + 1)->IsMarked(), true);
226 }
227 
TEST_F(CardTableTest,VisitMarked)228 TEST_F(CardTableTest, VisitMarked)
229 {
230     size_t markedCnt = 0;
231     while (markedCnt < kAllocCount) {
232         uintptr_t addr;
233         addr = GetRandomAddress();
234         if (!card_table_->IsMarked(addr)) {
235             ++markedCnt;
236             card_table_->MarkCard(addr);
237         }
238     }
239 
240     PandaVector<MemRange> mem_ranges;
241     card_table_->VisitMarked([&mem_ranges](MemRange mem_range) { mem_ranges.emplace_back(mem_range); },
242                              CardTableProcessedFlag::VISIT_MARKED);
243 
244     // Got ranges one by one
245     PandaVector<MemRange> expected_ranges;
246     for (auto card : *card_table_) {
247         if (card->IsMarked()) {
248             expected_ranges.emplace_back(card_table_->GetMemoryRange(card));
249         }
250     }
251 
252     ASSERT_EQ(expected_ranges.size(), mem_ranges.size());
253     for (size_t i = 0; i < expected_ranges.size(); i++) {
254         ASSERT(mem_ranges[i].GetStartAddress() == expected_ranges[i].GetStartAddress());
255         ASSERT(mem_ranges[i].GetEndAddress() == expected_ranges[i].GetEndAddress());
256     }
257 }
258 
259 }  // namespace panda::mem::test
260