[vm, gc] Aggregate marker statistics and delete visitors on the main thread.
This makes parallel marking more like parallel scavenge and is preparation for allowing marking/scavenging to complete even if some workers haven't started.
Also improve work stealing of weak processing by processing the worker-local weak properties first.
TEST=ci
Change-Id: I73bfb930129e2d9848a3bbcf378303a51bd65a5d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/215681
Reviewed-by: Liam Appelbe <liama@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index 74ca4cc..a2f7477 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -39,7 +39,9 @@
marked_micros_(0) {
ASSERT(thread_->isolate_group() == isolate_group);
}
- ~MarkingVisitorBase() {}
+ ~MarkingVisitorBase() {
+ ASSERT(delayed_weak_properties_ == WeakProperty::null());
+ }
uintptr_t marked_bytes() const { return marked_bytes_; }
int64_t marked_micros() const { return marked_micros_; }
@@ -202,26 +204,22 @@
}
}
- void FinalizeDeferredMarking() {
- ProcessDeferredMarking();
+ // Called when all marking is complete. Any attempt to push to the mark stack
+ // after this will trigger an error.
+ void FinalizeMarking() {
+ work_list_.Finalize();
deferred_work_list_.Finalize();
}
- // Called when all marking is complete.
- void Finalize() {
- work_list_.Finalize();
- // Clear pending weak properties.
+ void MournWeakProperties() {
WeakPropertyPtr cur_weak = delayed_weak_properties_;
delayed_weak_properties_ = WeakProperty::null();
- intptr_t weak_properties_cleared = 0;
while (cur_weak != WeakProperty::null()) {
WeakPropertyPtr next_weak =
cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
cur_weak->untag()->next_ = WeakProperty::null();
RELEASE_ASSERT(!cur_weak->untag()->key()->untag()->IsMarked());
WeakProperty::Clear(cur_weak);
- weak_properties_cleared++;
- // Advance to next weak property in the queue.
cur_weak = next_weak;
}
}
@@ -233,6 +231,7 @@
void AbandonWork() {
work_list_.AbandonWork();
deferred_work_list_.AbandonWork();
+ delayed_weak_properties_ = WeakProperty::null();
}
private:
@@ -603,23 +602,20 @@
} while (more_to_mark);
// Phase 2: deferred marking.
- visitor_->FinalizeDeferredMarking();
+ visitor_->ProcessDeferredMarking();
+ visitor_->FinalizeMarking();
barrier_->Sync();
- // Phase 3: Weak processing.
+ // Phase 3: Weak processing and statistics.
+ visitor_->MournWeakProperties();
marker_->IterateWeakRoots(thread);
- barrier_->Sync();
-
- // Phase 4: Gather statistics from all markers.
int64_t stop = OS::GetCurrentMonotonicMicros();
visitor_->AddMicros(stop - start);
if (FLAG_log_marker_tasks) {
THR_Print("Task marked %" Pd " bytes in %" Pd64 " micros.\n",
visitor_->marked_bytes(), visitor_->marked_micros());
}
- marker_->FinalizeResultsFrom(visitor_);
-
- delete visitor_;
+ barrier_->Sync();
}
}
@@ -694,16 +690,6 @@
DISALLOW_COPY_AND_ASSIGN(ConcurrentMarkTask);
};
-template <class MarkingVisitorType>
-void GCMarker::FinalizeResultsFrom(MarkingVisitorType* visitor) {
- {
- MutexLocker ml(&stats_mutex_);
- marked_bytes_ += visitor->marked_bytes();
- marked_micros_ += visitor->marked_micros();
- }
- visitor->Finalize();
-}
-
intptr_t GCMarker::MarkedWordsPerMicro() const {
intptr_t marked_words_per_job_micro;
if (marked_micros_ == 0) {
@@ -799,18 +785,21 @@
TIMELINE_FUNCTION_GC_DURATION(thread, "Mark");
int64_t start = OS::GetCurrentMonotonicMicros();
// Mark everything on main thread.
- UnsyncMarkingVisitor mark(isolate_group_, page_space, &marking_stack_,
- &deferred_marking_stack_);
+ UnsyncMarkingVisitor visitor(isolate_group_, page_space, &marking_stack_,
+ &deferred_marking_stack_);
ResetSlices();
- IterateRoots(&mark);
- mark.ProcessDeferredMarking();
- mark.DrainMarkingStack();
- mark.FinalizeDeferredMarking();
+ IterateRoots(&visitor);
+ visitor.ProcessDeferredMarking();
+ visitor.DrainMarkingStack();
+ visitor.ProcessDeferredMarking();
+ visitor.FinalizeMarking();
+ visitor.MournWeakProperties();
IterateWeakRoots(thread);
// All marking done; detach code, etc.
int64_t stop = OS::GetCurrentMonotonicMicros();
- mark.AddMicros(stop - start);
- FinalizeResultsFrom(&mark);
+ visitor.AddMicros(stop - start);
+ marked_bytes_ += visitor.marked_bytes();
+ marked_micros_ += visitor.marked_micros();
} else {
ThreadBarrier barrier(num_tasks, heap_->barrier(), heap_->barrier_done());
ResetSlices();
@@ -818,14 +807,14 @@
RelaxedAtomic<uintptr_t> num_busy(num_tasks);
// Phase 1: Iterate over roots and drain marking stack in tasks.
for (intptr_t i = 0; i < num_tasks; ++i) {
- SyncMarkingVisitor* visitor;
- if (visitors_[i] != NULL) {
- visitor = visitors_[i];
- visitors_[i] = NULL;
- } else {
+ SyncMarkingVisitor* visitor = visitors_[i];
+ // Visitors may or may not have already been created depending on
+ // whether we did some concurrent marking.
+ if (visitor == nullptr) {
visitor =
new SyncMarkingVisitor(isolate_group_, page_space,
&marking_stack_, &deferred_marking_stack_);
+ visitors_[i] = visitor;
}
if (i < (num_tasks - 1)) {
// Begin marking on a helper thread.
@@ -841,6 +830,14 @@
barrier.Exit();
}
}
+
+ for (intptr_t i = 0; i < num_tasks; i++) {
+ SyncMarkingVisitor* visitor = visitors_[i];
+ marked_bytes_ += visitor->marked_bytes();
+ marked_micros_ += visitor->marked_micros();
+ delete visitor;
+ visitors_[i] = nullptr;
+ }
}
}
Epilogue();
diff --git a/runtime/vm/heap/marker.h b/runtime/vm/heap/marker.h
index 6f9e309..2fde0d8 100644
--- a/runtime/vm/heap/marker.h
+++ b/runtime/vm/heap/marker.h
@@ -73,7 +73,6 @@
intptr_t root_slices_count_;
RelaxedAtomic<intptr_t> weak_slices_started_;
- Mutex stats_mutex_;
uintptr_t marked_bytes_;
int64_t marked_micros_;
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index af64d84..b8e3e6c 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -121,6 +121,9 @@
visiting_old_object_(nullptr),
promoted_list_(promotion_stack),
delayed_weak_properties_(WeakProperty::null()) {}
+ ~ScavengerVisitorBase() {
+ ASSERT(delayed_weak_properties_ == WeakProperty::null());
+ }
virtual void VisitTypedDataViewPointers(TypedDataViewPtr view,
CompressedObjectPtr* first,
@@ -265,6 +268,7 @@
void Finalize() {
if (scavenger_->abort_) {
promoted_list_.AbandonWork();
+ delayed_weak_properties_ = WeakProperty::null();
} else {
ASSERT(!HasWork());