Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(695)

Unified Diff: runtime/vm/scavenger.cc

Issue 3001423002: Initial idle GC logic. (Closed)
Patch Set: divide-by-zero Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/scavenger.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/scavenger.cc
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index c3bbc268bd07e9937cb171c57c59eb5f5f10e853..d35d8c8fa231b8f98627161b33ad475de91c81d3 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -323,6 +323,8 @@ Scavenger::Scavenger(Heap* heap,
delayed_weak_properties_(NULL),
gc_time_micros_(0),
collections_(0),
+ scavenge_words_per_micro_(400),
+ idle_scavenge_threshold_in_words_(0),
external_size_(0),
failed_to_promote_(false) {
// Verify assumptions about the first word in objects which the scavenger is
@@ -347,6 +349,7 @@ Scavenger::Scavenger(Heap* heap,
end_ = to_->end();
survivor_end_ = FirstObjectStart();
+ idle_scavenge_threshold_in_words_ = initial_semi_capacity_in_words;
UpdateMaxHeapCapacity();
UpdateMaxHeapUsage();
@@ -427,6 +430,45 @@ void Scavenger::Epilogue(Isolate* isolate, SemiSpace* from) {
// objects candidates for promotion next time.
survivor_end_ = end_;
}
+
+ // Update estimate of scavenger speed. This statistic assumes survivorship
+ // rates don't change much.
+ intptr_t history_used = 0;
+ intptr_t history_micros = 0;
+ ASSERT(stats_history_.Size() > 0);
+ for (intptr_t i = 0; i < stats_history_.Size(); i++) {
+ history_used += stats_history_.Get(i).UsedBeforeInWords();
+ history_micros += stats_history_.Get(i).DurationMicros();
+ }
+ if (history_micros == 0) {
+ history_micros = 1;
+ }
+ scavenge_words_per_micro_ = history_used / history_micros;
+ if (scavenge_words_per_micro_ == 0) {
+ scavenge_words_per_micro_ = 1;
+ }
+
+ // Update amount of new-space we must allocate before performing an idle
+ // scavenge. This is based on the amount of work we expect to be able to
+ // complete in a typical idle period.
+ intptr_t average_idle_task_micros = 4000;
+ idle_scavenge_threshold_in_words_ =
+ scavenge_words_per_micro_ * average_idle_task_micros;
+ // Even if the scavenge speed is slow, make sure we don't scavenge too
+ // frequently, which just wastes power and falsely increases the promotion
+ // rate.
+ intptr_t lower_bound = 512 * KBInWords;
+ if (idle_scavenge_threshold_in_words_ < lower_bound) {
+ idle_scavenge_threshold_in_words_ = lower_bound;
+ }
+ // Even if the scavenge speed is very high, make sure we start considering
+ // idle scavenges before new space is full to avoid requiring a scavenge in
+ // the middle of a frame.
+ intptr_t upper_bound = 8 * CapacityInWords() / 10;
+ if (idle_scavenge_threshold_in_words_ > upper_bound) {
+ idle_scavenge_threshold_in_words_ = upper_bound;
+ }
+
#if defined(DEBUG)
// We can only safely verify the store buffers from old space if there is no
// concurrent old space task. At the same time we prevent new tasks from
@@ -447,6 +489,18 @@ void Scavenger::Epilogue(Isolate* isolate, SemiSpace* from) {
}
}
+bool Scavenger::ShouldPerformIdleScavenge(int64_t deadline) {
+ // TODO(rmacnak): Investigate collecting a history of idle period durations.
+ intptr_t used_in_words = UsedInWords();
+ if (used_in_words < idle_scavenge_threshold_in_words_) {
+ return false;
+ }
+ int64_t estimated_scavenge_completion =
+ OS::GetCurrentMonotonicMicros() +
+ used_in_words / scavenge_words_per_micro_;
+ return estimated_scavenge_completion <= deadline;
+}
+
void Scavenger::IterateStoreBuffers(Isolate* isolate,
ScavengerVisitor* visitor) {
// Iterating through the store buffers.
@@ -775,7 +829,7 @@ void Scavenger::Scavenge() {
// TODO(koda): Consider moving SafepointThreads into allocation failure/retry
// logic to avoid needless collections.
- int64_t pre_safe_point = OS::GetCurrentMonotonicMicros();
+ int64_t start = OS::GetCurrentMonotonicMicros();
Thread* thread = Thread::Current();
SafepointOperationScope safepoint_scope(thread);
@@ -789,8 +843,8 @@ void Scavenger::Scavenge() {
PageSpace* page_space = heap_->old_space();
NoSafepointScope no_safepoints;
- int64_t post_safe_point = OS::GetCurrentMonotonicMicros();
- heap_->RecordTime(kSafePoint, post_safe_point - pre_safe_point);
+ int64_t safe_point = OS::GetCurrentMonotonicMicros();
+ heap_->RecordTime(kSafePoint, safe_point - start);
// TODO(koda): Make verification more compatible with concurrent sweep.
if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) {
@@ -812,9 +866,9 @@ void Scavenger::Scavenge() {
ScavengerVisitor visitor(isolate, this, from);
page_space->AcquireDataLock();
IterateRoots(isolate, &visitor);
- int64_t start = OS::GetCurrentMonotonicMicros();
+ int64_t iterate_roots = OS::GetCurrentMonotonicMicros();
ProcessToSpace(&visitor);
- int64_t middle = OS::GetCurrentMonotonicMicros();
+ int64_t process_to_space = OS::GetCurrentMonotonicMicros();
{
TIMELINE_FUNCTION_GC_DURATION(thread, "WeakHandleProcessing");
ScavengerWeakVisitor weak_visitor(thread, this);
@@ -825,8 +879,8 @@ void Scavenger::Scavenge() {
// Scavenge finished. Run accounting.
int64_t end = OS::GetCurrentMonotonicMicros();
- heap_->RecordTime(kProcessToSpace, middle - start);
- heap_->RecordTime(kIterateWeaks, end - middle);
+ heap_->RecordTime(kProcessToSpace, process_to_space - iterate_roots);
+ heap_->RecordTime(kIterateWeaks, end - process_to_space);
stats_history_.Add(ScavengeStats(
start, end, usage_before, GetCurrentUsage(), promo_candidate_words,
visitor.bytes_promoted() >> kWordSizeLog2));
« no previous file with comments | « runtime/vm/scavenger.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698