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