• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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     mem::MemStatsType *mem_stats;
41 
CardTableTest()42     CardTableTest()
43     {
44 #ifdef PANDA_NIGHTLY_TEST_ON
45         seed_ = std::time(NULL);
46 #else
47         seed_ = 123456;
48 #endif
49         RuntimeOptions options;
50         options.SetHeapSizeLimit(64_MB);
51         options.SetShouldLoadBootPandaFiles(false);
52         options.SetShouldInitializeIntrinsics(false);
53         options.SetGcType("epsilon");
54         Runtime::Create(options);
55         thread_ = panda::MTManagedThread::GetCurrent();
56         thread_->ManagedCodeBegin();
57 
58         internal_allocator_ = thread_->GetVM()->GetHeapManager()->GetInternalAllocator();
59         addrDis = std::uniform_int_distribution<uintptr_t>(0, GetPoolSize() - 1);
60         ASSERT(GetPoolSize() % CardTable::GetCardSize() == 0);
61         cardIndexDis = std::uniform_int_distribution<size_t>(0, GetPoolSize() / CardTable::GetCardSize() - 1);
62         card_table_ = std::make_unique<CardTable>(internal_allocator_, GetMinAddress(), GetPoolSize());
63         card_table_->Initialize();
64     }
65 
~CardTableTest()66     ~CardTableTest()
67     {
68         card_table_.reset(nullptr);
69         thread_->ManagedCodeEnd();
70         Runtime::Destroy();
71     }
72 
SetUp()73     void SetUp() override
74     {
75         gen.seed(seed_);
76     }
77 
TearDown()78     void TearDown() override
79     {
80         const ::testing::TestInfo *const test_info = ::testing::UnitTest::GetInstance()->current_test_info();
81         if (test_info->result()->Failed()) {
82             std::cout << "CartTableTest seed = " << seed_ << std::endl;
83         }
84     }
85 
GetMinAddress()86     uintptr_t GetMinAddress()
87     {
88         return PoolManager::GetMmapMemPool()->GetMinObjectAddress();
89     }
90 
GetPoolSize()91     size_t GetPoolSize()
92     {
93         return (PoolManager::GetMmapMemPool()->GetMaxObjectAddress() -
94                 PoolManager::GetMmapMemPool()->GetMinObjectAddress());
95     }
96 
GetRandomAddress()97     uintptr_t GetRandomAddress()
98     {
99         return PoolManager::GetMmapMemPool()->GetMinObjectAddress() + addrDis(gen) % GetPoolSize();
100     }
101 
GetRandomCardIndex()102     size_t GetRandomCardIndex()
103     {
104         return cardIndexDis(gen) % GetPoolSize();
105     }
106 
107     // generate address at the begining of the card
GetRandomCardAddress()108     uintptr_t GetRandomCardAddress()
109     {
110         return PoolManager::GetMmapMemPool()->GetMinObjectAddress() + GetRandomCardIndex() * CardTable::GetCardSize();
111     }
112 
113     InternalAllocatorPtr internal_allocator_;
114     std::unique_ptr<CardTable> card_table_;
115     unsigned int seed_;
116     panda::MTManagedThread *thread_;
117 };
118 
TEST_F(CardTableTest,MarkTest)119 TEST_F(CardTableTest, MarkTest)
120 {
121     size_t markedCnt = 0;
122 
123     for (size_t i = 0; i < kAllocCount; i++) {
124         uintptr_t addr = GetRandomAddress();
125         if (!card_table_->IsMarked(addr)) {
126             ++markedCnt;
127             card_table_->MarkCard(addr);
128         }
129     }
130 
131     for (auto card : *card_table_) {
132         if (card->IsMarked()) {
133             markedCnt--;
134         }
135     }
136     ASSERT_EQ(markedCnt, 0);
137 }
138 
TEST_F(CardTableTest,MarkAndClearAllTest)139 TEST_F(CardTableTest, MarkAndClearAllTest)
140 {
141     // std::set<uintptr_t> addrSet;
142 
143     size_t cnt = 0;
144     for (auto card : *card_table_) {
145         card->Mark();
146         cnt++;
147     }
148     ASSERT_EQ(cnt, card_table_->GetCardsCount());
149 
150     size_t cnt_cleared = 0;
151     for (auto card : *card_table_) {
152         card->Clear();
153         cnt_cleared++;
154     }
155     ASSERT_EQ(cnt_cleared, card_table_->GetCardsCount());
156 }
157 
TEST_F(CardTableTest,ClearTest)158 TEST_F(CardTableTest, ClearTest)
159 {
160     std::set<uintptr_t> addrSet;
161 
162     // Mark some cards not more than once
163     while (addrSet.size() <= kAllocCount) {
164         uintptr_t addr = GetRandomCardAddress();
165         if (!addrSet.insert(addr).second) {
166             continue;
167         }
168         card_table_->MarkCard(addr);
169     }
170 
171     size_t cleared_cnt = 0;
172     // clear all marked and count them
173     for (auto card : *card_table_) {
174         if (card->IsMarked()) {
175             card->Clear();
176             cleared_cnt++;
177         }
178     }
179 
180     ASSERT_EQ(addrSet.size(), cleared_cnt);
181     // check that there are no marked
182     for (auto card : *card_table_) {
183         ASSERT_EQ(card->IsMarked(), false);
184     }
185 }
186 
TEST_F(CardTableTest,ClearAllTest)187 TEST_F(CardTableTest, ClearAllTest)
188 {
189     std::set<uintptr_t> addrSet;
190 
191     // Mark some cards not more than once
192     while (addrSet.size() < kAllocCount) {
193         uintptr_t addr = GetRandomCardAddress();
194         if (!addrSet.insert(addr).second) {
195             continue;
196         }
197         card_table_->MarkCard(addr);
198     }
199 
200     card_table_->ClearAll();
201     for (auto card : *card_table_) {
202         ASSERT_EQ(card->IsMarked(), false);
203     }
204 }
205 
TEST_F(CardTableTest,double_initialization)206 TEST_F(CardTableTest, double_initialization)
207 {
208     EXPECT_DEATH(card_table_->Initialize(), ".*");
209 }
210 
TEST_F(CardTableTest,corner_cases)211 TEST_F(CardTableTest, corner_cases)
212 {
213     // Mark 1st byte in the heap
214     ASSERT_EQ((*card_table_->begin())->IsMarked(), false);
215     card_table_->MarkCard(GetMinAddress());
216     ASSERT_EQ((*card_table_->begin())->IsMarked(), true);
217     // Mark last byte in the heap
218     uintptr_t last = GetMinAddress() + GetPoolSize() - 1;
219     ASSERT_EQ(card_table_->IsMarked(last), false);
220     card_table_->MarkCard(last);
221     ASSERT_EQ(card_table_->IsMarked(last), true);
222     // Mark last byte of second card
223     uintptr_t secondLast = GetMinAddress() + 2 * card_table_->GetCardSize() - 1;
224     ASSERT_EQ(card_table_->IsMarked(secondLast), false);
225     card_table_->MarkCard(secondLast);
226     ASSERT_EQ(((*card_table_->begin()) + 1)->IsMarked(), true);
227 }
228 
TEST_F(CardTableTest,VisitMarked)229 TEST_F(CardTableTest, VisitMarked)
230 {
231     size_t markedCnt = 0;
232 
233     while (markedCnt < kAllocCount) {
234         uintptr_t addr = GetRandomAddress();
235         if (!card_table_->IsMarked(addr)) {
236             ++markedCnt;
237             card_table_->MarkCard(addr);
238         }
239     }
240 
241     PandaVector<MemRange> mem_ranges;
242     card_table_->VisitMarked([&mem_ranges](MemRange mem_range) { mem_ranges.emplace_back(mem_range); },
243                              CardTableProcessedFlag::VISIT_MARKED);
244 
245     // Got ranges one by one
246     PandaVector<MemRange> expected_ranges;
247     for (auto card : *card_table_) {
248         if (card->IsMarked()) {
249             expected_ranges.emplace_back(card_table_->GetMemoryRange(card));
250         }
251     }
252 
253     ASSERT_EQ(expected_ranges.size(), mem_ranges.size());
254     for (size_t i = 0; i < expected_ranges.size(); i++) {
255         ASSERT(mem_ranges[i].GetStartAddress() == expected_ranges[i].GetStartAddress());
256         ASSERT(mem_ranges[i].GetEndAddress() == expected_ranges[i].GetEndAddress());
257     }
258 }
259 
260 }  // namespace panda::mem::test
261