Use the card table to speed up the GSS collector.
Scan only dirty cards, as opposed to the whole space, to find
references from the non-moving spaces to the bump pointer spaces at
bump pointer space only collections.
With this change, the Ritz MemAllocTest speeds up by 8-10% on host and
2-3% on N4. The Ritz EvaluateFibonacci speeds up by 8% and its average
pause time is reduced by 43% on N4.
Bug: 11650816
Change-Id: I1eefe75776bc37e24673b301ffa65a25f9bd4cde
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 45904ff..e8ee62f 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -33,6 +33,7 @@
#include "gc/accounting/heap_bitmap-inl.h"
#include "gc/accounting/mod_union_table.h"
#include "gc/accounting/mod_union_table-inl.h"
+#include "gc/accounting/remembered_set.h"
#include "gc/accounting/space_bitmap-inl.h"
#include "gc/collector/mark_sweep-inl.h"
#include "gc/collector/partial_mark_sweep.h"
@@ -161,7 +162,8 @@
} else {
if (kMovingCollector) {
// We are the zygote, use bump pointer allocation + semi space collector.
- desired_collector_type_ = kCollectorTypeSS;
+ bool generational = post_zygote_collector_type_ == kCollectorTypeGSS;
+ desired_collector_type_ = generational ? kCollectorTypeGSS : kCollectorTypeSS;
} else {
desired_collector_type_ = post_zygote_collector_type_;
}
@@ -279,6 +281,13 @@
CHECK(mod_union_table != nullptr) << "Failed to create image mod-union table";
AddModUnionTable(mod_union_table);
+ if (collector::SemiSpace::kUseRememberedSet) {
+ accounting::RememberedSet* non_moving_space_rem_set =
+ new accounting::RememberedSet("Non-moving space remembered set", this, non_moving_space_);
+ CHECK(non_moving_space_rem_set != nullptr) << "Failed to create non-moving space remembered set";
+ AddRememberedSet(non_moving_space_rem_set);
+ }
+
// TODO: Count objects in the image space here.
num_bytes_allocated_ = 0;
@@ -1469,7 +1478,7 @@
// Special compacting collector which uses sub-optimal bin packing to reduce zygote space size.
class ZygoteCompactingCollector FINAL : public collector::SemiSpace {
public:
- explicit ZygoteCompactingCollector(gc::Heap* heap) : SemiSpace(heap, "zygote collector"),
+ explicit ZygoteCompactingCollector(gc::Heap* heap) : SemiSpace(heap, false, "zygote collector"),
bin_live_bitmap_(nullptr), bin_mark_bitmap_(nullptr) {
}
@@ -1618,6 +1627,16 @@
// Remove the old space before creating the zygote space since creating the zygote space sets
// the old alloc space's bitmaps to nullptr.
RemoveSpace(old_alloc_space);
+ if (collector::SemiSpace::kUseRememberedSet) {
+ // Sanity bound check.
+ FindRememberedSetFromSpace(old_alloc_space)->AssertAllDirtyCardsAreWithinSpace();
+ // Remove the remembered set for the now zygote space (the old
+ // non-moving space). Note now that we have compacted objects into
+ // the zygote space, the data in the remembered set is no longer
+ // needed. The zygote space will instead have a mod-union table
+ // from this point on.
+ RemoveRememberedSet(old_alloc_space);
+ }
space::ZygoteSpace* zygote_space = old_alloc_space->CreateZygoteSpace("alloc space",
low_memory_mode_,
&main_space_);
@@ -1640,6 +1659,13 @@
new accounting::ModUnionTableCardCache("zygote space mod-union table", this, zygote_space);
CHECK(mod_union_table != nullptr) << "Failed to create zygote space mod-union table";
AddModUnionTable(mod_union_table);
+ if (collector::SemiSpace::kUseRememberedSet) {
+ // Add a new remembered set for the new main space.
+ accounting::RememberedSet* main_space_rem_set =
+ new accounting::RememberedSet("Main space remembered set", this, main_space_);
+ CHECK(main_space_rem_set != nullptr) << "Failed to create main space remembered set";
+ AddRememberedSet(main_space_rem_set);
+ }
// Can't use RosAlloc for non moving space due to thread local buffers.
// TODO: Non limited space for non-movable objects?
MemMap* mem_map = post_zygote_non_moving_space_mem_map_.release();
@@ -1650,6 +1676,15 @@
CHECK(new_non_moving_space != nullptr) << "Failed to create new non-moving space";
new_non_moving_space->SetFootprintLimit(new_non_moving_space->Capacity());
non_moving_space_ = new_non_moving_space;
+ if (collector::SemiSpace::kUseRememberedSet) {
+ // Add a new remembered set for the post-zygote non-moving space.
+ accounting::RememberedSet* post_zygote_non_moving_space_rem_set =
+ new accounting::RememberedSet("Post-zygote non-moving space remembered set", this,
+ non_moving_space_);
+ CHECK(post_zygote_non_moving_space_rem_set != nullptr)
+ << "Failed to create post-zygote non-moving space remembered set";
+ AddRememberedSet(post_zygote_non_moving_space_rem_set);
+ }
}
void Heap::FlushAllocStack() {
@@ -2034,6 +2069,11 @@
accounting::ModUnionTable* mod_union_table = table_pair.second;
mod_union_table->Dump(LOG(ERROR) << mod_union_table->GetName() << ": ");
}
+ // Dump remembered sets.
+ for (const auto& table_pair : remembered_sets_) {
+ accounting::RememberedSet* remembered_set = table_pair.second;
+ remembered_set->Dump(LOG(ERROR) << remembered_set->GetName() << ": ");
+ }
DumpSpaces();
return false;
}
@@ -2185,15 +2225,29 @@
return it->second;
}
-void Heap::ProcessCards(TimingLogger& timings) {
+accounting::RememberedSet* Heap::FindRememberedSetFromSpace(space::Space* space) {
+ auto it = remembered_sets_.find(space);
+ if (it == remembered_sets_.end()) {
+ return nullptr;
+ }
+ return it->second;
+}
+
+void Heap::ProcessCards(TimingLogger& timings, bool use_rem_sets) {
// Clear cards and keep track of cards cleared in the mod-union table.
for (const auto& space : continuous_spaces_) {
accounting::ModUnionTable* table = FindModUnionTableFromSpace(space);
+ accounting::RememberedSet* rem_set = FindRememberedSetFromSpace(space);
if (table != nullptr) {
const char* name = space->IsZygoteSpace() ? "ZygoteModUnionClearCards" :
"ImageModUnionClearCards";
TimingLogger::ScopedSplit split(name, &timings);
table->ClearCards();
+ } else if (use_rem_sets && rem_set != nullptr) {
+ DCHECK(collector::SemiSpace::kUseRememberedSet && collector_type_ == kCollectorTypeGSS)
+ << static_cast<int>(collector_type_);
+ TimingLogger::ScopedSplit split("AllocSpaceRemSetClearCards", &timings);
+ rem_set->ClearCards();
} else if (space->GetType() != space::kSpaceTypeBumpPointerSpace) {
TimingLogger::ScopedSplit split("AllocSpaceClearCards", &timings);
// No mod union table for the AllocSpace. Age the cards so that the GC knows that these cards
@@ -2694,5 +2748,22 @@
CHECK_GE(byte_count, sizeof(mirror::Object));
}
+void Heap::AddRememberedSet(accounting::RememberedSet* remembered_set) {
+ CHECK(remembered_set != nullptr);
+ space::Space* space = remembered_set->GetSpace();
+ CHECK(space != nullptr);
+ CHECK(remembered_sets_.find(space) == remembered_sets_.end());
+ remembered_sets_.Put(space, remembered_set);
+ CHECK(remembered_sets_.find(space) != remembered_sets_.end());
+}
+
+void Heap::RemoveRememberedSet(space::Space* space) {
+ CHECK(space != nullptr);
+ auto it = remembered_sets_.find(space);
+ CHECK(it != remembered_sets_.end());
+ remembered_sets_.erase(it);
+ CHECK(remembered_sets_.find(space) == remembered_sets_.end());
+}
+
} // namespace gc
} // namespace art