Compute "scanned bytes" GC metrics in ART's CMC collector.
Test: ART_USE_READ_BARRIER=false \
m test-art-host-gtest-art_runtime_tests
Bug: 270957146
Bug: 270391874
Change-Id: Ie64ed1c89774676af58a47caa7e697474bbeaaf4
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index 03e8bdd..3c2606a 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -587,6 +587,7 @@
moving_first_objs_count_ = 0;
non_moving_first_objs_count_ = 0;
black_page_count_ = 0;
+ bytes_scanned_ = 0;
freed_objects_ = 0;
// The first buffer is used by gc-thread.
compaction_buffer_counter_ = 1;
@@ -2266,7 +2267,9 @@
&& obj->GetClass<kDefaultVerifyFlags, kWithoutReadBarrier>() != nullptr) {
// Try to keep instructions which access class instance together to
// avoid reloading the pointer from object.
- size_t obj_size = RoundUp(obj->SizeOf(), kAlignment);
+ size_t obj_size = obj->SizeOf();
+ bytes_scanned_ += obj_size;
+ obj_size = RoundUp(obj_size, kAlignment);
UpdateClassAfterObjectMap(obj);
if (first_obj == nullptr) {
first_obj = obj;
@@ -3921,11 +3924,12 @@
return words * kAlignment;
}
-void MarkCompact::UpdateLivenessInfo(mirror::Object* obj) {
+void MarkCompact::UpdateLivenessInfo(mirror::Object* obj, size_t obj_size) {
DCHECK(obj != nullptr);
+ DCHECK_EQ(obj_size, obj->SizeOf<kDefaultVerifyFlags>());
uintptr_t obj_begin = reinterpret_cast<uintptr_t>(obj);
UpdateClassAfterObjectMap(obj);
- size_t size = RoundUp(obj->SizeOf<kDefaultVerifyFlags>(), kAlignment);
+ size_t size = RoundUp(obj_size, kAlignment);
uintptr_t bit_index = live_words_bitmap_->SetLiveWords(obj_begin, size);
size_t chunk_idx = (obj_begin - live_words_bitmap_->Begin()) / kOffsetChunkSize;
// Compute the bit-index within the chunk-info vector word.
@@ -3944,10 +3948,16 @@
template <bool kUpdateLiveWords>
void MarkCompact::ScanObject(mirror::Object* obj) {
+ // The size of `obj` is used both here (to update `bytes_scanned_`) and in
+ // `UpdateLivenessInfo`. As fetching this value can be expensive, do it once
+ // here and pass that information to `UpdateLivenessInfo`.
+ size_t obj_size = obj->SizeOf<kDefaultVerifyFlags>();
+ bytes_scanned_ += obj_size;
+
RefFieldsVisitor visitor(this);
DCHECK(IsMarked(obj)) << "Scanning marked object " << obj << "\n" << heap_->DumpSpaces();
if (kUpdateLiveWords && moving_space_bitmap_->HasAddress(obj)) {
- UpdateLivenessInfo(obj);
+ UpdateLivenessInfo(obj, obj_size);
}
obj->VisitReferences(visitor, visitor);
}
@@ -4132,6 +4142,7 @@
}
void MarkCompact::FinishPhase() {
+ GetCurrentIteration()->SetScannedBytes(bytes_scanned_);
bool is_zygote = Runtime::Current()->IsZygote();
compacting_ = false;
minor_fault_initialized_ = !is_zygote && uffd_minor_fault_supported_;
diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h
index 3504ad3..d73f40d 100644
--- a/runtime/gc/collector/mark_compact.h
+++ b/runtime/gc/collector/mark_compact.h
@@ -422,7 +422,8 @@
// Update the live-words bitmap as well as add the object size to the
// chunk-info vector. Both are required for computation of post-compact addresses.
// Also updates freed_objects_ counter.
- void UpdateLivenessInfo(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_);
+ void UpdateLivenessInfo(mirror::Object* obj, size_t obj_size)
+ REQUIRES_SHARED(Locks::mutator_lock_);
void ProcessReferences(Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_)
@@ -655,6 +656,8 @@
size_t vector_length_;
size_t live_stack_freeze_size_;
+ uint64_t bytes_scanned_;
+
// For every page in the to-space (post-compact heap) we need to know the
// first object from which we must compact and/or update references. This is
// for both non-moving and moving space. Additionally, for the moving-space,
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index 5e64ae2..b569241 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -201,12 +201,8 @@
EXPECT_FALSE(full_gc_tracing_throughput->IsNull());
EXPECT_FALSE(full_gc_throughput_avg->IsNull());
EXPECT_FALSE(full_gc_tracing_throughput_avg->IsNull());
- if (fg_collector_type != kCollectorTypeCMC) {
- // TODO(b/270957146): For some reason, these metrics are still null
- // after running the Concurrent Mark-Compact collector; investigate why.
- EXPECT_FALSE(full_gc_scanned_bytes->IsNull());
- EXPECT_FALSE(full_gc_scanned_bytes_delta->IsNull());
- }
+ EXPECT_FALSE(full_gc_scanned_bytes->IsNull());
+ EXPECT_FALSE(full_gc_scanned_bytes_delta->IsNull());
EXPECT_FALSE(full_gc_freed_bytes->IsNull());
EXPECT_FALSE(full_gc_freed_bytes_delta->IsNull());
EXPECT_FALSE(full_gc_duration->IsNull());