summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Roland Levillain <rpl@google.com> 2023-03-17 17:59:05 +0000
committer Roland Levillain <rpl@google.com> 2023-03-27 10:18:58 +0000
commit6dc2655b1474d137f59dc92c00458f6440a59e03 (patch)
treedc8d09e72d962b6b2d8bf1174b15d82e26158804
parent4efc53d64dd5a04fcb9203bee756ae462c6da9f9 (diff)
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
-rw-r--r--runtime/gc/collector/mark_compact.cc19
-rw-r--r--runtime/gc/collector/mark_compact.h5
-rw-r--r--runtime/gc/heap_test.cc8
3 files changed, 21 insertions, 11 deletions
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index 03e8bdd17b..3c2606a6d7 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -587,6 +587,7 @@ void MarkCompact::InitializePhase() {
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 @@ void MarkCompact::UpdateMovingSpaceBlackAllocations() {
&& 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 @@ size_t MarkCompact::LiveWordsBitmap<kAlignment>::LiveBytesInBitmapWord(size_t ch
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 @@ void MarkCompact::UpdateLivenessInfo(mirror::Object* obj) {
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::DelayReferenceReferent(ObjPtr<mirror::Class> klass,
}
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 3504ad3c0d..d73f40d436 100644
--- a/runtime/gc/collector/mark_compact.h
+++ b/runtime/gc/collector/mark_compact.h
@@ -422,7 +422,8 @@ class MarkCompact final : public GarbageCollector {
// 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 @@ class MarkCompact final : public GarbageCollector {
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 5e64ae2192..b569241bdc 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -201,12 +201,8 @@ TEST_F(HeapTest, GCMetrics) {
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());