1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "card_table-inl.h" 18 19 #include <string> 20 21 #include "atomic.h" 22 #include "common_runtime_test.h" 23 #include "handle_scope-inl.h" 24 #include "mirror/class-inl.h" 25 #include "mirror/string-inl.h" // Strings are easiest to allocate 26 #include "scoped_thread_state_change.h" 27 #include "thread_pool.h" 28 #include "utils.h" 29 30 namespace art { 31 32 namespace mirror { 33 class Object; 34 } // namespace mirror 35 36 namespace gc { 37 namespace accounting { 38 39 class CardTableTest : public CommonRuntimeTest { 40 public: 41 std::unique_ptr<CardTable> card_table_; 42 43 void CommonSetup() { 44 if (card_table_.get() == nullptr) { 45 card_table_.reset(CardTable::Create(heap_begin_, heap_size_)); 46 EXPECT_TRUE(card_table_.get() != nullptr); 47 } else { 48 ClearCardTable(); 49 } 50 } 51 // Default values for the test, not random to avoid undeterministic behaviour. 52 CardTableTest() : heap_begin_(reinterpret_cast<uint8_t*>(0x2000000)), heap_size_(2 * MB) { 53 } 54 void ClearCardTable() { 55 card_table_->ClearCardTable(); 56 } 57 uint8_t* HeapBegin() const { 58 return heap_begin_; 59 } 60 uint8_t* HeapLimit() const { 61 return HeapBegin() + heap_size_; 62 } 63 // Return a pseudo random card for an address. 64 uint8_t PseudoRandomCard(const uint8_t* addr) const { 65 size_t offset = RoundDown(addr - heap_begin_, CardTable::kCardSize); 66 return 1 + offset % 254; 67 } 68 void FillRandom() { 69 for (const uint8_t* addr = HeapBegin(); addr != HeapLimit(); addr += CardTable::kCardSize) { 70 EXPECT_TRUE(card_table_->AddrIsInCardTable(addr)); 71 uint8_t* card = card_table_->CardFromAddr(addr); 72 *card = PseudoRandomCard(addr); 73 } 74 } 75 76 private: 77 uint8_t* const heap_begin_; 78 const size_t heap_size_; 79 }; 80 81 TEST_F(CardTableTest, TestMarkCard) { 82 CommonSetup(); 83 for (const uint8_t* addr = HeapBegin(); addr < HeapLimit(); addr += kObjectAlignment) { 84 auto obj = reinterpret_cast<const mirror::Object*>(addr); 85 EXPECT_EQ(card_table_->GetCard(obj), CardTable::kCardClean); 86 EXPECT_TRUE(!card_table_->IsDirty(obj)); 87 card_table_->MarkCard(addr); 88 EXPECT_TRUE(card_table_->IsDirty(obj)); 89 EXPECT_EQ(card_table_->GetCard(obj), CardTable::kCardDirty); 90 uint8_t* card_addr = card_table_->CardFromAddr(addr); 91 EXPECT_EQ(*card_addr, CardTable::kCardDirty); 92 *card_addr = CardTable::kCardClean; 93 EXPECT_EQ(*card_addr, CardTable::kCardClean); 94 } 95 } 96 97 class UpdateVisitor { 98 public: 99 uint8_t operator()(uint8_t c) const { 100 return c * 93 + 123; 101 } 102 void operator()(uint8_t* /*card*/, uint8_t /*expected_value*/, uint8_t /*new_value*/) const { 103 } 104 }; 105 106 TEST_F(CardTableTest, TestModifyCardsAtomic) { 107 CommonSetup(); 108 FillRandom(); 109 const size_t delta = std::min(static_cast<size_t>(HeapLimit() - HeapBegin()), 110 8U * CardTable::kCardSize); 111 UpdateVisitor visitor; 112 size_t start_offset = 0; 113 for (uint8_t* cstart = HeapBegin(); cstart < HeapBegin() + delta; cstart += CardTable::kCardSize) { 114 start_offset = (start_offset + kObjectAlignment) % CardTable::kCardSize; 115 size_t end_offset = 0; 116 for (uint8_t* cend = HeapLimit() - delta; cend < HeapLimit(); cend += CardTable::kCardSize) { 117 // Don't always start at a card boundary. 118 uint8_t* start = cstart + start_offset; 119 uint8_t* end = cend - end_offset; 120 end_offset = (end_offset + kObjectAlignment) % CardTable::kCardSize; 121 // Modify cards. 122 card_table_->ModifyCardsAtomic(start, end, visitor, visitor); 123 // Check adjacent cards not modified. 124 for (uint8_t* cur = start - CardTable::kCardSize; cur >= HeapBegin(); 125 cur -= CardTable::kCardSize) { 126 EXPECT_EQ(card_table_->GetCard(reinterpret_cast<mirror::Object*>(cur)), 127 PseudoRandomCard(cur)); 128 } 129 for (uint8_t* cur = end + CardTable::kCardSize; cur < HeapLimit(); 130 cur += CardTable::kCardSize) { 131 EXPECT_EQ(card_table_->GetCard(reinterpret_cast<mirror::Object*>(cur)), 132 PseudoRandomCard(cur)); 133 } 134 // Verify Range. 135 for (uint8_t* cur = start; cur < AlignUp(end, CardTable::kCardSize); 136 cur += CardTable::kCardSize) { 137 uint8_t* card = card_table_->CardFromAddr(cur); 138 uint8_t value = PseudoRandomCard(cur); 139 EXPECT_EQ(visitor(value), *card); 140 // Restore for next iteration. 141 *card = value; 142 } 143 } 144 } 145 } 146 147 // TODO: Add test for CardTable::Scan. 148 } // namespace accounting 149 } // namespace gc 150 } // namespace art 151