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 #ifndef PANDA_RUNTIME_TESTS_BITMAP_TEST_BASE_H
16 #define PANDA_RUNTIME_TESTS_BITMAP_TEST_BASE_H
17
18 #include <cstdlib>
19 #include <memory>
20 #include <vector>
21
22 #include "runtime/mem/gc/bitmap.h"
23
24 namespace panda::mem {
25
26 class BitmapTest : public testing::Test {
27 public:
28 static constexpr ObjectPointerType HEAP_STARTING_ADDRESS = static_cast<ObjectPointerType>(0x10000000);
29 };
30
31 using BitmapWordType = panda::mem::Bitmap::BitmapWordType;
32
33 class BitmapVerify {
34 public:
35 using BitmapType = MemBitmap<DEFAULT_ALIGNMENT_IN_BYTES>;
BitmapVerify(BitmapType * bitmapArg,void * beginArg,void * endArg)36 BitmapVerify(BitmapType *bitmapArg, void *beginArg, void *endArg)
37 : bitmap_(bitmapArg), begin_(beginArg), end_(endArg)
38 {
39 }
40
operator()41 void operator()(void *obj)
42 {
43 EXPECT_TRUE(obj >= begin_);
44 EXPECT_TRUE(obj <= end_);
45 EXPECT_EQ(bitmap_->Test(obj), ((BitmapType::ToPointerType(obj) & ADDRESS_MASK_TO_SET) != 0));
46 }
47
48 static constexpr BitmapWordType ADDRESS_MASK_TO_SET = 0xF;
49
50 private:
51 BitmapType *const bitmap_;
52 void *begin_;
53 void *end_;
54 };
55
FnRounddown(size_t val,size_t alignment)56 inline size_t FnRounddown(size_t val, size_t alignment)
57 {
58 size_t mask = ~((static_cast<size_t>(1) * alignment) - 1);
59 return val & mask;
60 }
61
62 template <size_t K_ALIGNMENT, typename TestFn>
RunTest(TestFn && fn)63 void RunTest(TestFn &&fn)
64 {
65 auto heapBegin = BitmapTest::HEAP_STARTING_ADDRESS;
66 const size_t heapCapacity = 16_MB;
67
68 #ifdef PANDA_NIGHTLY_TEST_ON
69 // NOLINTNEXTLINE(cert-msc51-cpp)
70 std::srand(time(nullptr));
71 #else
72 // NOLINTNEXTLINE(cert-msc51-cpp,readability-magic-numbers)
73 std::srand(0x1234);
74 #endif
75
76 constexpr int TEST_REPEAT = 1;
77 for (int i = 0; i < TEST_REPEAT; ++i) {
78 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
79 auto bmPtr = std::make_unique<BitmapWordType[]>((heapCapacity >> Bitmap::LOG_BITSPERWORD) / K_ALIGNMENT);
80 MemBitmap<K_ALIGNMENT> bm(ToVoidPtr(heapBegin), heapCapacity, bmPtr.get());
81
82 constexpr int NUM_BITS_TO_MODIFY = 1000;
83 for (int j = 0; j < NUM_BITS_TO_MODIFY; ++j) {
84 // NOLINTNEXTLINE(cert-msc50-cpp)
85 size_t offset = FnRounddown(std::rand() % heapCapacity, K_ALIGNMENT);
86 // NOLINTNEXTLINE(cert-msc50-cpp)
87 bool set = std::rand() % 2 == 1;
88 if (set) {
89 bm.Set(ToVoidPtr(heapBegin + offset));
90 } else {
91 bm.Clear(ToVoidPtr(heapBegin + offset));
92 }
93 }
94
95 constexpr int NUM_TEST_RANGES = 50;
96 for (int j = 0; j < NUM_TEST_RANGES; ++j) {
97 // NOLINTNEXTLINE(cert-msc50-cpp)
98 const size_t offset = FnRounddown(std::rand() % heapCapacity, K_ALIGNMENT);
99 const size_t remain = heapCapacity - offset;
100 // NOLINTNEXTLINE(cert-msc50-cpp)
101 const size_t end = offset + FnRounddown(std::rand() % (remain + 1), K_ALIGNMENT);
102
103 size_t manual = 0;
104 for (ObjectPointerType k = offset; k < end; k += K_ALIGNMENT) {
105 if (bm.Test(ToVoidPtr(heapBegin + k))) {
106 manual++;
107 }
108 }
109
110 fn(&bm, heapBegin + offset, heapBegin + end, manual);
111 }
112 }
113 }
114
115 template <size_t K_ALIGNMENT>
RunTestCount()116 void RunTestCount()
117 {
118 auto countTestFn = [](MemBitmap<K_ALIGNMENT> *bitmap, ObjectPointerType begin, ObjectPointerType end,
119 size_t manualCount) {
120 size_t count = 0;
121 auto countFn = [&count, begin, end]([[maybe_unused]] void *obj) {
122 auto p = ToObjPtr(obj);
123 if (p >= begin && p < end) {
124 count++;
125 }
126 };
127 bitmap->IterateOverMarkedChunkInRange(ToVoidPtr(begin), ToVoidPtr(end), countFn);
128 EXPECT_EQ(count, manualCount);
129 };
130 RunTest<K_ALIGNMENT>(countTestFn);
131 }
132
133 template <size_t K_ALIGNMENT>
RunTestOrder()134 void RunTestOrder()
135 {
136 auto orderTestFn = [](MemBitmap<K_ALIGNMENT> *bitmap, ObjectPointerType begin, ObjectPointerType end,
137 size_t manualCount) {
138 void *lastPtr = nullptr;
139 auto orderCheck = [&lastPtr](void *obj) {
140 EXPECT_LT(lastPtr, obj);
141 lastPtr = obj;
142 };
143
144 // Test complete walk.
145 bitmap->IterateOverChunks(orderCheck);
146 if (manualCount > 0) {
147 EXPECT_NE(nullptr, lastPtr);
148 }
149
150 // Test range.
151 lastPtr = nullptr;
152 bitmap->IterateOverMarkedChunkInRange(ToVoidPtr(begin), ToVoidPtr(end), orderCheck);
153 if (manualCount > 0) {
154 EXPECT_NE(nullptr, lastPtr);
155 }
156 };
157 RunTest<K_ALIGNMENT>(orderTestFn);
158 }
159
TEST_F(BitmapTest,AtomicClearSetTest)160 TEST_F(BitmapTest, AtomicClearSetTest)
161 {
162 void *object = ToVoidPtr(HEAP_STARTING_ADDRESS);
163 const size_t sz = 1_MB;
164 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
165 auto bmPtr = std::make_unique<BitmapWordType[]>(sz >> MemBitmap<>::LOG_BITSPERWORD);
166 MemBitmap<> bm(ToVoidPtr(HEAP_STARTING_ADDRESS), sz, bmPtr.get());
167
168 // Set bit
169 ASSERT_TRUE(bm.Test(object) == bm.AtomicTestAndSet(object));
170 ASSERT_TRUE(bm.Test(object));
171 ASSERT_TRUE(bm.AtomicTest(object));
172
173 // Clear bit
174 ASSERT_TRUE(bm.Test(object) == bm.AtomicTestAndClear(object));
175 ASSERT_TRUE(!bm.Test(object));
176 ASSERT_TRUE(!bm.AtomicTest(object));
177 }
178
179 } // namespace panda::mem
180
181 #endif // PANDA_RUNTIME_TESTS_BITMAP_TEST_BASE_H
182