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