Home | History | Annotate | Download | only in accounting
      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 "base/atomic.h"
     22 #include "base/utils.h"
     23 #include "common_runtime_test.h"
     24 #include "handle_scope-inl.h"
     25 #include "mirror/class-inl.h"
     26 #include "mirror/string-inl.h"  // Strings are easiest to allocate
     27 #include "scoped_thread_state_change-inl.h"
     28 #include "thread_pool.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