diff options
| -rw-r--r-- | runtime/gc/accounting/card_table-inl.h | 29 | ||||
| -rw-r--r-- | runtime/gc/accounting/card_table.cc | 20 | ||||
| -rw-r--r-- | runtime/gc/accounting/card_table.h | 13 | ||||
| -rw-r--r-- | runtime/gc/accounting/mod_union_table.cc | 4 | ||||
| -rw-r--r-- | runtime/gc/accounting/mod_union_table.h | 18 | ||||
| -rw-r--r-- | runtime/gc/accounting/mod_union_table_test.cc | 2 | ||||
| -rw-r--r-- | runtime/gc/accounting/space_bitmap.cc | 27 | ||||
| -rw-r--r-- | runtime/gc/collector/concurrent_copying.cc | 23 | ||||
| -rw-r--r-- | runtime/gc/heap.cc | 2 | ||||
| -rw-r--r-- | runtime/mem_map.cc | 19 | ||||
| -rw-r--r-- | runtime/mem_map.h | 4 |
11 files changed, 77 insertions, 84 deletions
diff --git a/runtime/gc/accounting/card_table-inl.h b/runtime/gc/accounting/card_table-inl.h index f72f219a0d..6ff53597e4 100644 --- a/runtime/gc/accounting/card_table-inl.h +++ b/runtime/gc/accounting/card_table-inl.h @@ -50,13 +50,17 @@ static inline bool byte_cas(uint8_t old_value, uint8_t new_value, uint8_t* addre } template <bool kClearCard, typename Visitor> -inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin, uint8_t* scan_end, - const Visitor& visitor, const uint8_t minimum_age) const { +inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, + uint8_t* const scan_begin, + uint8_t* const scan_end, + const Visitor& visitor, + const uint8_t minimum_age) { DCHECK_GE(scan_begin, reinterpret_cast<uint8_t*>(bitmap->HeapBegin())); // scan_end is the byte after the last byte we scan. DCHECK_LE(scan_end, reinterpret_cast<uint8_t*>(bitmap->HeapLimit())); - uint8_t* card_cur = CardFromAddr(scan_begin); - uint8_t* card_end = CardFromAddr(AlignUp(scan_end, kCardSize)); + uint8_t* const card_begin = CardFromAddr(scan_begin); + uint8_t* const card_end = CardFromAddr(AlignUp(scan_end, kCardSize)); + uint8_t* card_cur = card_begin; CheckCardValid(card_cur); CheckCardValid(card_end); size_t cards_scanned = 0; @@ -67,9 +71,6 @@ inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur)); bitmap->VisitMarkedRange(start, start + kCardSize, visitor); ++cards_scanned; - if (kClearCard) { - *card_cur = 0; - } } ++card_cur; } @@ -99,9 +100,6 @@ inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin << "card " << static_cast<size_t>(*card) << " intptr_t " << (start_word & 0xFF); bitmap->VisitMarkedRange(start, start + kCardSize, visitor); ++cards_scanned; - if (kClearCard) { - *card = 0; - } } start_word >>= 8; start += kCardSize; @@ -116,13 +114,14 @@ inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur)); bitmap->VisitMarkedRange(start, start + kCardSize, visitor); ++cards_scanned; - if (kClearCard) { - *card_cur = 0; - } } ++card_cur; } + if (kClearCard) { + ClearCardRange(scan_begin, scan_end); + } + return cards_scanned; } @@ -135,7 +134,9 @@ inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin * us to know which cards got cleared. */ template <typename Visitor, typename ModifiedVisitor> -inline void CardTable::ModifyCardsAtomic(uint8_t* scan_begin, uint8_t* scan_end, const Visitor& visitor, +inline void CardTable::ModifyCardsAtomic(uint8_t* scan_begin, + uint8_t* scan_end, + const Visitor& visitor, const ModifiedVisitor& modified) { uint8_t* card_cur = CardFromAddr(scan_begin); uint8_t* card_end = CardFromAddr(AlignUp(scan_end, kCardSize)); diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc index 121da37389..450659791d 100644 --- a/runtime/gc/accounting/card_table.cc +++ b/runtime/gc/accounting/card_table.cc @@ -97,36 +97,18 @@ CardTable::~CardTable() { // Destroys MemMap via std::unique_ptr<>. } -void CardTable::ClearSpaceCards(space::ContinuousSpace* space) { - // TODO: clear just the range of the table that has been modified - uint8_t* card_start = CardFromAddr(space->Begin()); - uint8_t* card_end = CardFromAddr(space->End()); // Make sure to round up. - memset(reinterpret_cast<void*>(card_start), kCardClean, card_end - card_start); -} - void CardTable::ClearCardTable() { static_assert(kCardClean == 0, "kCardClean must be 0"); mem_map_->MadviseDontNeedAndZero(); } void CardTable::ClearCardRange(uint8_t* start, uint8_t* end) { - if (!kMadviseZeroes) { - memset(start, 0, end - start); - return; - } CHECK_ALIGNED(reinterpret_cast<uintptr_t>(start), kCardSize); CHECK_ALIGNED(reinterpret_cast<uintptr_t>(end), kCardSize); static_assert(kCardClean == 0, "kCardClean must be 0"); uint8_t* start_card = CardFromAddr(start); uint8_t* end_card = CardFromAddr(end); - uint8_t* round_start = AlignUp(start_card, kPageSize); - uint8_t* round_end = AlignDown(end_card, kPageSize); - if (round_start < round_end) { - madvise(round_start, round_end - round_start, MADV_DONTNEED); - } - // Handle unaligned regions at start / end. - memset(start_card, 0, std::min(round_start, end_card) - start_card); - memset(std::max(round_end, start_card), 0, end_card - std::max(round_end, start_card)); + ZeroAndReleasePages(start_card, end_card - start_card); } bool CardTable::AddrIsInCardTable(const void* addr) const { diff --git a/runtime/gc/accounting/card_table.h b/runtime/gc/accounting/card_table.h index 969bfb7182..68ef15d0cf 100644 --- a/runtime/gc/accounting/card_table.h +++ b/runtime/gc/accounting/card_table.h @@ -98,15 +98,19 @@ class CardTable { * us to know which cards got cleared. */ template <typename Visitor, typename ModifiedVisitor> - void ModifyCardsAtomic(uint8_t* scan_begin, uint8_t* scan_end, const Visitor& visitor, + void ModifyCardsAtomic(uint8_t* scan_begin, + uint8_t* scan_end, + const Visitor& visitor, const ModifiedVisitor& modified); // For every dirty at least minumum age between begin and end invoke the visitor with the // specified argument. Returns how many cards the visitor was run on. template <bool kClearCard, typename Visitor> - size_t Scan(SpaceBitmap<kObjectAlignment>* bitmap, uint8_t* scan_begin, uint8_t* scan_end, + size_t Scan(SpaceBitmap<kObjectAlignment>* bitmap, + uint8_t* scan_begin, + uint8_t* scan_end, const Visitor& visitor, - const uint8_t minimum_age = kCardDirty) const + const uint8_t minimum_age = kCardDirty) REQUIRES(Locks::heap_bitmap_lock_) REQUIRES_SHARED(Locks::mutator_lock_); @@ -119,9 +123,6 @@ class CardTable { // Clear a range of cards that covers start to end, start and end must be aligned to kCardSize. void ClearCardRange(uint8_t* start, uint8_t* end); - // Resets all of the bytes in the card table which do not map to the image space. - void ClearSpaceCards(space::ContinuousSpace* space); - // Returns the first address in the heap which maps to this card. void* AddrFromCard(const uint8_t *card_addr) const ALWAYS_INLINE; diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc index 14f59977d6..0325535a1b 100644 --- a/runtime/gc/accounting/mod_union_table.cc +++ b/runtime/gc/accounting/mod_union_table.cc @@ -168,7 +168,7 @@ class ModUnionScanImageRootVisitor { bool* const contains_reference_to_other_space_; }; -void ModUnionTableReferenceCache::ClearCards() { +void ModUnionTableReferenceCache::ProcessCards() { CardTable* card_table = GetHeap()->GetCardTable(); ModUnionAddToCardSetVisitor visitor(&cleared_cards_); // Clear dirty cards in the this space and update the corresponding mod-union bits. @@ -525,7 +525,7 @@ class CardBitVisitor { ModUnionTable::CardBitmap* const card_bitmap_; }; -void ModUnionTableCardCache::ClearCards() { +void ModUnionTableCardCache::ProcessCards() { CardTable* const card_table = GetHeap()->GetCardTable(); ModUnionAddToCardBitmapVisitor visitor(card_bitmap_.get(), card_table); // Clear dirty cards in the this space and update the corresponding mod-union bits. diff --git a/runtime/gc/accounting/mod_union_table.h b/runtime/gc/accounting/mod_union_table.h index b6792c4f1f..591365f33a 100644 --- a/runtime/gc/accounting/mod_union_table.h +++ b/runtime/gc/accounting/mod_union_table.h @@ -55,10 +55,10 @@ class ModUnionTable { virtual ~ModUnionTable() {} - // Clear cards which map to a memory range of a space. This doesn't immediately update the - // mod-union table, as updating the mod-union table may have an associated cost, such as - // determining references to track. - virtual void ClearCards() = 0; + // Process cards for a memory range of a space. This doesn't immediately update the mod-union + // table, as updating the mod-union table may have an associated cost, such as determining + // references to track. + virtual void ProcessCards() = 0; // Set all the cards. virtual void SetCards() = 0; @@ -66,9 +66,9 @@ class ModUnionTable { // Clear all of the table. virtual void ClearTable() = 0; - // Update the mod-union table using data stored by ClearCards. There may be multiple ClearCards - // before a call to update, for example, back-to-back sticky GCs. Also mark references to other - // spaces which are stored in the mod-union table. + // Update the mod-union table using data stored by ProcessCards. There may be multiple + // ProcessCards before a call to update, for example, back-to-back sticky GCs. Also mark + // references to other spaces which are stored in the mod-union table. virtual void UpdateAndMarkReferences(MarkObjectVisitor* visitor) = 0; // Visit all of the objects that may contain references to other spaces. @@ -117,7 +117,7 @@ class ModUnionTableReferenceCache : public ModUnionTable { virtual ~ModUnionTableReferenceCache() {} // Clear and store cards for a space. - void ClearCards() OVERRIDE; + void ProcessCards() OVERRIDE; // Update table based on cleared cards and mark all references to the other spaces. void UpdateAndMarkReferences(MarkObjectVisitor* visitor) OVERRIDE @@ -164,7 +164,7 @@ class ModUnionTableCardCache : public ModUnionTable { virtual ~ModUnionTableCardCache() {} // Clear and store cards for a space. - virtual void ClearCards() OVERRIDE; + virtual void ProcessCards() OVERRIDE; // Mark all references to the alloc space(s). virtual void UpdateAndMarkReferences(MarkObjectVisitor* visitor) OVERRIDE diff --git a/runtime/gc/accounting/mod_union_table_test.cc b/runtime/gc/accounting/mod_union_table_test.cc index 2810f58584..cf63b30d43 100644 --- a/runtime/gc/accounting/mod_union_table_test.cc +++ b/runtime/gc/accounting/mod_union_table_test.cc @@ -214,7 +214,7 @@ void ModUnionTableTest::RunTest(ModUnionTableFactory::TableType type) { ASSERT_TRUE(other_space_ref2 != nullptr); obj1->Set(1, other_space_ref1); obj2->Set(3, other_space_ref2); - table->ClearCards(); + table->ProcessCards(); std::set<mirror::Object*> visited_before; CollectVisitedVisitor collector_before(&visited_before); table->UpdateAndMarkReferences(&collector_before); diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc index e2f5a1d7fc..f4d0bc7dbf 100644 --- a/runtime/gc/accounting/space_bitmap.cc +++ b/runtime/gc/accounting/space_bitmap.cc @@ -118,31 +118,8 @@ void SpaceBitmap<kAlignment>::ClearRange(const mirror::Object* begin, const mirr } const uintptr_t start_index = OffsetToIndex(begin_offset); const uintptr_t end_index = OffsetToIndex(end_offset); - Atomic<uintptr_t>* const mem_begin = &bitmap_begin_[start_index]; - Atomic<uintptr_t>* const mem_end = &bitmap_begin_[end_index]; - Atomic<uintptr_t>* const page_begin = AlignUp(mem_begin, kPageSize); - Atomic<uintptr_t>* const page_end = AlignDown(mem_end, kPageSize); - if (!kMadviseZeroes || page_begin >= page_end) { - // No possible area to madvise. - std::fill(reinterpret_cast<uint8_t*>(mem_begin), - reinterpret_cast<uint8_t*>(mem_end), - 0); - } else { - // Spans one or more pages. - DCHECK_LE(mem_begin, page_begin); - DCHECK_LE(page_begin, page_end); - DCHECK_LE(page_end, mem_end); - std::fill(reinterpret_cast<uint8_t*>(mem_begin), - reinterpret_cast<uint8_t*>(page_begin), - 0); - CHECK_NE(madvise(page_begin, - reinterpret_cast<uint8_t*>(page_end) - reinterpret_cast<uint8_t*>(page_begin), - MADV_DONTNEED), - -1) << "madvise failed"; - std::fill(reinterpret_cast<uint8_t*>(page_end), - reinterpret_cast<uint8_t*>(mem_end), - 0); - } + ZeroAndReleasePages(reinterpret_cast<uint8_t*>(&bitmap_begin_[start_index]), + (end_index - start_index) * sizeof(*bitmap_begin_)); } template<size_t kAlignment> diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index 13af67eb3e..c43b048893 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -486,9 +486,14 @@ void ConcurrentCopying::GrayAllDirtyImmuneObjects() { // Table is non null for boot image and zygote spaces. It is only null for application image // spaces. if (table != nullptr) { - // TODO: Add preclean outside the pause. - table->ClearCards(); + // TODO: Consider adding precleaning outside the pause. + table->ProcessCards(); table->VisitObjects(GrayImmuneObjectVisitor::Callback, &visitor); + // Since the cards are recorded in the mod-union table and this is paused, we can clear + // the cards for the space (to madvise). + TimingLogger::ScopedTiming split2("(Paused)ClearCards", GetTimings()); + card_table->ClearCardRange(space->Begin(), + AlignDown(space->End(), accounting::CardTable::kCardSize)); } else { // TODO: Consider having a mark bitmap for app image spaces and avoid scanning during the // pause because app image spaces are all dirty pages anyways. @@ -2325,9 +2330,14 @@ void ConcurrentCopying::FinishPhase() { MutexLock mu(self, mark_stack_lock_); CHECK_EQ(pooled_mark_stacks_.size(), kMarkStackPoolSize); } - region_space_ = nullptr; { - MutexLock mu(Thread::Current(), skipped_blocks_lock_); + TimingLogger::ScopedTiming split("ClearRegionSpaceCards", GetTimings()); + // We do not currently use the region space cards at all, madvise them away to save ram. + heap_->GetCardTable()->ClearCardRange(region_space_->Begin(), region_space_->Limit()); + region_space_ = nullptr; + } + { + MutexLock mu(self, skipped_blocks_lock_); skipped_blocks_map_.clear(); } { @@ -2339,10 +2349,9 @@ void ConcurrentCopying::FinishPhase() { if (kUseBakerReadBarrier && kFilterModUnionCards) { TimingLogger::ScopedTiming split("FilterModUnionCards", GetTimings()); ReaderMutexLock mu2(self, *Locks::heap_bitmap_lock_); - gc::Heap* const heap = Runtime::Current()->GetHeap(); for (space::ContinuousSpace* space : immune_spaces_.GetSpaces()) { DCHECK(space->IsImageSpace() || space->IsZygoteSpace()); - accounting::ModUnionTable* table = heap->FindModUnionTableFromSpace(space); + accounting::ModUnionTable* table = heap_->FindModUnionTableFromSpace(space); // Filter out cards that don't need to be set. if (table != nullptr) { table->FilterCards(); @@ -2351,7 +2360,7 @@ void ConcurrentCopying::FinishPhase() { } if (kUseBakerReadBarrier) { TimingLogger::ScopedTiming split("EmptyRBMarkBitStack", GetTimings()); - DCHECK(rb_mark_bit_stack_.get() != nullptr); + DCHECK(rb_mark_bit_stack_ != nullptr); const auto* limit = rb_mark_bit_stack_->End(); for (StackReference<mirror::Object>* it = rb_mark_bit_stack_->Begin(); it != limit; ++it) { CHECK(it->AsMirrorPtr()->AtomicSetMarkBit(1, 0)); diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 3b9abd228d..ffad80d946 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -3327,7 +3327,7 @@ void Heap::ProcessCards(TimingLogger* timings, const char* name = space->IsZygoteSpace() ? "ZygoteModUnionClearCards" : "ImageModUnionClearCards"; TimingLogger::ScopedTiming t2(name, timings); - table->ClearCards(); + table->ProcessCards(); } else if (use_rem_sets && rem_set != nullptr) { DCHECK(collector::SemiSpace::kUseRememberedSet && collector_type_ == kCollectorTypeGSS) << static_cast<int>(collector_type_); diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc index bb07fcbf37..e4c67e0664 100644 --- a/runtime/mem_map.cc +++ b/runtime/mem_map.cc @@ -918,4 +918,23 @@ void MemMap::TryReadable() { } } +void ZeroAndReleasePages(void* address, size_t length) { + uint8_t* const mem_begin = reinterpret_cast<uint8_t*>(address); + uint8_t* const mem_end = mem_begin + length; + uint8_t* const page_begin = AlignUp(mem_begin, kPageSize); + uint8_t* const page_end = AlignDown(mem_end, kPageSize); + if (!kMadviseZeroes || page_begin >= page_end) { + // No possible area to madvise. + std::fill(mem_begin, mem_end, 0); + } else { + // Spans one or more pages. + DCHECK_LE(mem_begin, page_begin); + DCHECK_LE(page_begin, page_end); + DCHECK_LE(page_end, mem_end); + std::fill(mem_begin, page_begin, 0); + CHECK_NE(madvise(page_begin, page_end - page_begin, MADV_DONTNEED), -1) << "madvise failed"; + std::fill(page_end, mem_end, 0); + } +} + } // namespace art diff --git a/runtime/mem_map.h b/runtime/mem_map.h index 597f0d46e1..049ae12acf 100644 --- a/runtime/mem_map.h +++ b/runtime/mem_map.h @@ -241,9 +241,13 @@ class MemMap { friend class MemMapTest; // To allow access to base_begin_ and base_size_. }; + std::ostream& operator<<(std::ostream& os, const MemMap& mem_map); std::ostream& operator<<(std::ostream& os, const MemMap::Maps& mem_maps); +// Zero and release pages if possible, no requirements on alignments. +void ZeroAndReleasePages(void* address, size_t length); + } // namespace art #endif // ART_RUNTIME_MEM_MAP_H_ |