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 #include <memory>
17 #include <vector>
18 #include <thread>
19
20 #include "libpandabase/utils/tsan_interface.h"
21 #include "gtest/gtest.h"
22 #include "bitmap_test_base.h"
23 #include "runtime/mem/gc/bitmap.h"
24
25 namespace ark::mem {
26
TEST_F(BitmapTest,Init)27 TEST_F(BitmapTest, Init)
28 {
29 const size_t sz = 1_MB;
30 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
31 auto bmPtr = std::make_unique<BitmapWordType[]>(sz >> MemBitmap<>::LOG_BITSPERWORD);
32 MemBitmap<> bm(ToVoidPtr(HEAP_STARTING_ADDRESS), sz, bmPtr.get());
33 EXPECT_EQ(bm.Size(), sz);
34 }
35
TEST_F(BitmapTest,ScanRange)36 TEST_F(BitmapTest, ScanRange)
37 {
38 auto heapBegin = HEAP_STARTING_ADDRESS;
39 constexpr size_t HEAP_CAPACITY = 16_MB;
40 // NOLINTBEGIN(modernize-avoid-c-arrays)
41 auto bmPtr =
42 std::make_unique<BitmapWordType[]>((HEAP_CAPACITY >> Bitmap::LOG_BITSPERWORD) / DEFAULT_ALIGNMENT_IN_BYTES);
43 // NOLINTEND(modernize-avoid-c-arrays)
44
45 MemBitmap<DEFAULT_ALIGNMENT_IN_BYTES> bm(ToVoidPtr(heapBegin), HEAP_CAPACITY, bmPtr.get());
46
47 constexpr size_t BIT_SET_RANGE_END = Bitmap::BITSPERWORD * 3U;
48
49 for (size_t j = 0; j < BIT_SET_RANGE_END; ++j) {
50 auto *obj = ToVoidPtr(heapBegin + j * DEFAULT_ALIGNMENT_IN_BYTES);
51 if ((ToUintPtr(obj) & BitmapVerify::ADDRESS_MASK_TO_SET) != 0U) {
52 bm.Set(obj);
53 }
54 }
55
56 constexpr size_t BIT_VERIFY_RANGE_END = Bitmap::BITSPERWORD * 2;
57
58 for (size_t i = 0; i < Bitmap::BITSPERWORD; ++i) {
59 auto *start = ToVoidPtr(heapBegin + i * DEFAULT_ALIGNMENT_IN_BYTES);
60 for (size_t j = 0; j < BIT_VERIFY_RANGE_END; ++j) {
61 auto *end = ToVoidPtr(heapBegin + (i + j) * DEFAULT_ALIGNMENT_IN_BYTES);
62 BitmapVerify(&bm, start, end);
63 }
64 }
65 }
66
TEST_F(BitmapTest,VisitorPageAlignment)67 TEST_F(BitmapTest, VisitorPageAlignment)
68 {
69 RunTestCount<4_KB>();
70 }
71
TEST_F(BitmapTest,OrderPageAlignment)72 TEST_F(BitmapTest, OrderPageAlignment)
73 {
74 RunTestOrder<4_KB>();
75 }
76
77 // test check that IterateOverMarkedChunkInRange & AtomicTestAndSetBit works fine with TSAN from two threads
78 // concurrently
TEST_F(BitmapTest,TSANMultithreadingTest)79 TEST_F(BitmapTest, TSANMultithreadingTest)
80 {
81 #ifdef PANDA_TSAN_ON
82 const size_t heapCapacity = 1_MB;
83 auto bmPtr = std::make_unique<BitmapWordType[]>(heapCapacity >> MemBitmap<>::LOG_BITSPERWORD);
84 auto heapBegin = BitmapTest::HEAP_STARTING_ADDRESS;
85 MemBitmap<> bm(ToVoidPtr(heapBegin), heapCapacity, bmPtr.get());
86
87 std::srand(0xBADDEAD);
88 size_t iterations;
89 #ifdef PANDA_NIGHTLY_TEST_ON
90 iterations = 3000U;
91 #else
92 iterations = 1000U;
93 #endif
94
95 auto iterateThread = std::thread([&bm, &iterations] {
96 // we do less iterations for IterateOverMarkedChunks
97 for (size_t i = 0; i < iterations; i++) {
98 bm.IterateOverMarkedChunks<true>([](const void *object) { ASSERT_NE(object, nullptr); });
99 }
100 });
101
102 auto setThread = std::thread([&bm, &heapBegin, &iterations] {
103 for (size_t i = 0; i < iterations * iterations; i++) {
104 bool value = std::rand() % 2 == 1;
105 size_t offset = FnRounddown(std::rand() % heapCapacity, 4_KB);
106
107 if (value) {
108 bm.AtomicTestAndSet(ToVoidPtr(heapBegin + offset));
109 } else {
110 bm.AtomicTestAndClear(ToVoidPtr(heapBegin + offset));
111 }
112 }
113 });
114 iterateThread.join();
115 setThread.join();
116 #endif
117 }
118
119 } // namespace ark::mem
120