| 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));
|
|
|