From 057514d3fa79af4732e136f5daad4b805a65e569 Mon Sep 17 00:00:00 2001 From: ulan Date: Tue, 8 Sep 2015 08:54:24 -0700 Subject: [PATCH] Use idle task to perform incremental marking steps. This moves incremental marking steps from gc-idle-time-handler and heap to the new incremental marking task. BUG=chromium:490559 LOG=NO Review URL: https://codereview.chromium.org/1265423002 Cr-Commit-Position: refs/heads/master@{#30641} --- BUILD.gn | 2 + src/heap/gc-idle-time-handler.cc | 21 +-- src/heap/gc-idle-time-handler.h | 21 +-- src/heap/heap.cc | 40 ++--- src/heap/heap.h | 2 + src/heap/incremental-marking-job.cc | 144 ++++++++++++++++++ src/heap/incremental-marking-job.h | 81 ++++++++++ src/heap/incremental-marking.cc | 2 + src/heap/incremental-marking.h | 9 +- src/v8.cc | 3 + src/v8.h | 3 + test/cctest/cctest.gyp | 1 + test/cctest/test-incremental-marking.cc | 168 +++++++++++++++++++++ .../heap/gc-idle-time-handler-unittest.cc | 78 +--------- tools/gyp/v8.gyp | 2 + 15 files changed, 444 insertions(+), 133 deletions(-) create mode 100644 src/heap/incremental-marking-job.cc create mode 100644 src/heap/incremental-marking-job.h create mode 100644 test/cctest/test-incremental-marking.cc diff --git a/BUILD.gn b/BUILD.gn index ea8b558..0191508 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -968,6 +968,8 @@ source_set("v8_base") { "src/heap/heap-inl.h", "src/heap/heap.cc", "src/heap/heap.h", + "src/heap/incremental-marking-job.cc", + "src/heap/incremental-marking-job.h", "src/heap/incremental-marking.cc", "src/heap/incremental-marking.h", "src/heap/mark-compact-inl.h", diff --git a/src/heap/gc-idle-time-handler.cc b/src/heap/gc-idle-time-handler.cc index b51b53b..f9783b3 100644 --- a/src/heap/gc-idle-time-handler.cc +++ b/src/heap/gc-idle-time-handler.cc @@ -26,9 +26,8 @@ void GCIdleTimeAction::Print() { case DO_NOTHING: PrintF("no action"); break; - case DO_INCREMENTAL_MARKING: - PrintF("incremental marking with step %" V8_PTR_PREFIX "d / ms", - parameter); + case DO_INCREMENTAL_STEP: + PrintF("incremental step"); if (additional_work) { PrintF("; finalized marking"); } @@ -39,9 +38,6 @@ void GCIdleTimeAction::Print() { case DO_FULL_GC: PrintF("full GC"); break; - case DO_FINALIZE_SWEEPING: - PrintF("finalize sweeping"); - break; } } @@ -271,22 +267,11 @@ GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms, return GCIdleTimeAction::Scavenge(); } - if (heap_state.sweeping_in_progress) { - if (heap_state.sweeping_completed) { - return GCIdleTimeAction::FinalizeSweeping(); - } else { - return NothingOrDone(idle_time_in_ms); - } - } - if (!FLAG_incremental_marking || heap_state.incremental_marking_stopped) { return GCIdleTimeAction::Done(); } - size_t step_size = EstimateMarkingStepSize( - static_cast(kIncrementalMarkingStepTimeInMs), - heap_state.incremental_marking_speed_in_bytes_per_ms); - return GCIdleTimeAction::IncrementalMarking(step_size); + return GCIdleTimeAction::IncrementalStep(); } diff --git a/src/heap/gc-idle-time-handler.h b/src/heap/gc-idle-time-handler.h index ebd132e..3f7f02d 100644 --- a/src/heap/gc-idle-time-handler.h +++ b/src/heap/gc-idle-time-handler.h @@ -13,10 +13,9 @@ namespace internal { enum GCIdleTimeActionType { DONE, DO_NOTHING, - DO_INCREMENTAL_MARKING, + DO_INCREMENTAL_STEP, DO_SCAVENGE, DO_FULL_GC, - DO_FINALIZE_SWEEPING }; @@ -25,7 +24,6 @@ class GCIdleTimeAction { static GCIdleTimeAction Done() { GCIdleTimeAction result; result.type = DONE; - result.parameter = 0; result.additional_work = false; return result; } @@ -33,15 +31,13 @@ class GCIdleTimeAction { static GCIdleTimeAction Nothing() { GCIdleTimeAction result; result.type = DO_NOTHING; - result.parameter = 0; result.additional_work = false; return result; } - static GCIdleTimeAction IncrementalMarking(intptr_t step_size) { + static GCIdleTimeAction IncrementalStep() { GCIdleTimeAction result; - result.type = DO_INCREMENTAL_MARKING; - result.parameter = step_size; + result.type = DO_INCREMENTAL_STEP; result.additional_work = false; return result; } @@ -49,7 +45,6 @@ class GCIdleTimeAction { static GCIdleTimeAction Scavenge() { GCIdleTimeAction result; result.type = DO_SCAVENGE; - result.parameter = 0; result.additional_work = false; return result; } @@ -57,15 +52,6 @@ class GCIdleTimeAction { static GCIdleTimeAction FullGC() { GCIdleTimeAction result; result.type = DO_FULL_GC; - result.parameter = 0; - result.additional_work = false; - return result; - } - - static GCIdleTimeAction FinalizeSweeping() { - GCIdleTimeAction result; - result.type = DO_FINALIZE_SWEEPING; - result.parameter = 0; result.additional_work = false; return result; } @@ -73,7 +59,6 @@ class GCIdleTimeAction { void Print(); GCIdleTimeActionType type; - intptr_t parameter; bool additional_work; }; diff --git a/src/heap/heap.cc b/src/heap/heap.cc index a0858ee..cfe4630 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -4535,10 +4535,12 @@ void Heap::FinalizeIncrementalMarkingIfComplete(const char* comment) { } -bool Heap::TryFinalizeIdleIncrementalMarking( - double idle_time_in_ms, size_t size_of_objects, - size_t final_incremental_mark_compact_speed_in_bytes_per_ms) { - if (FLAG_overapproximate_weak_closure && incremental_marking()->IsMarking() && +bool Heap::TryFinalizeIdleIncrementalMarking(double idle_time_in_ms) { + size_t size_of_objects = static_cast(SizeOfObjects()); + size_t final_incremental_mark_compact_speed_in_bytes_per_ms = + static_cast( + tracer()->FinalIncrementalMarkCompactSpeedInBytesPerMillisecond()); + if (FLAG_overapproximate_weak_closure && (incremental_marking()->IsReadyToOverApproximateWeakClosure() || (!incremental_marking()->weak_closure_was_overapproximated() && mark_compact_collector_.marking_deque()->IsEmpty() && @@ -4565,19 +4567,9 @@ GCIdleTimeHandler::HeapState Heap::ComputeHeapState() { heap_state.contexts_disposed = contexts_disposed_; heap_state.contexts_disposal_rate = tracer()->ContextDisposalRateInMilliseconds(); - heap_state.size_of_objects = static_cast(SizeOfObjects()); heap_state.incremental_marking_stopped = incremental_marking()->IsStopped(); - heap_state.sweeping_in_progress = - mark_compact_collector()->sweeping_in_progress(); - heap_state.sweeping_completed = - mark_compact_collector()->IsSweepingCompleted(); heap_state.mark_compact_speed_in_bytes_per_ms = static_cast(tracer()->MarkCompactSpeedInBytesPerMillisecond()); - heap_state.incremental_marking_speed_in_bytes_per_ms = static_cast( - tracer()->IncrementalMarkingSpeedInBytesPerMillisecond()); - heap_state.final_incremental_mark_compact_speed_in_bytes_per_ms = - static_cast( - tracer()->FinalIncrementalMarkCompactSpeedInBytesPerMillisecond()); heap_state.scavenge_speed_in_bytes_per_ms = static_cast(tracer()->ScavengeSpeedInBytesPerMillisecond()); heap_state.used_new_space_size = new_space_.Size(); @@ -4622,14 +4614,15 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action, case DONE: result = true; break; - case DO_INCREMENTAL_MARKING: { - const double remaining_idle_time_in_ms = - AdvanceIncrementalMarking(action.parameter, deadline_in_ms, - IncrementalMarking::IdleStepActions()); - if (remaining_idle_time_in_ms > 0.0) { - action.additional_work = TryFinalizeIdleIncrementalMarking( - remaining_idle_time_in_ms, heap_state.size_of_objects, - heap_state.final_incremental_mark_compact_speed_in_bytes_per_ms); + case DO_INCREMENTAL_STEP: { + if (incremental_marking()->incremental_marking_job()->IdleTaskPending()) { + result = true; + } else { + incremental_marking() + ->incremental_marking_job() + ->NotifyIdleTaskProgress(); + result = IncrementalMarkingJob::IdleTask::Step(this, deadline_in_ms) == + IncrementalMarkingJob::IdleTask::kDone; } break; } @@ -4642,9 +4635,6 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action, case DO_SCAVENGE: CollectGarbage(NEW_SPACE, "idle notification: scavenge"); break; - case DO_FINALIZE_SWEEPING: - mark_compact_collector()->EnsureSweepingCompleted(); - break; case DO_NOTHING: break; } diff --git a/src/heap/heap.h b/src/heap/heap.h index bb54a1d..9ae12f7 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -1278,6 +1278,8 @@ class Heap { void FinalizeIncrementalMarkingIfComplete(const char* comment); + bool TryFinalizeIdleIncrementalMarking(double idle_time_in_ms); + IncrementalMarking* incremental_marking() { return &incremental_marking_; } // =========================================================================== diff --git a/src/heap/incremental-marking-job.cc b/src/heap/incremental-marking-job.cc new file mode 100644 index 0000000..308d1b9 --- /dev/null +++ b/src/heap/incremental-marking-job.cc @@ -0,0 +1,144 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/heap/incremental-marking-job.h" + +#include "src/base/platform/time.h" +#include "src/heap/heap-inl.h" +#include "src/heap/heap.h" +#include "src/heap/incremental-marking.h" +#include "src/isolate.h" +#include "src/v8.h" + +namespace v8 { +namespace internal { + + +void IncrementalMarkingJob::Start(Heap* heap) { + DCHECK(!heap->incremental_marking()->IsStopped()); + // We don't need to reset the flags because tasks from the previous job + // can still be pending. We just want to ensure that tasks are posted + // if they are not pending. + // If delayed task is pending and made_progress_since_last_delayed_task_ is + // true, then the delayed task will clear that flag when it is rescheduled. + ScheduleIdleTask(heap); + ScheduleDelayedTask(heap); +} + + +void IncrementalMarkingJob::NotifyIdleTask() { idle_task_pending_ = false; } + + +void IncrementalMarkingJob::NotifyDelayedTask() { + delayed_task_pending_ = false; +} + + +void IncrementalMarkingJob::NotifyIdleTaskProgress() { + made_progress_since_last_delayed_task_ = true; +} + + +void IncrementalMarkingJob::ScheduleIdleTask(Heap* heap) { + if (!idle_task_pending_) { + v8::Isolate* isolate = reinterpret_cast(heap->isolate()); + if (V8::GetCurrentPlatform()->IdleTasksEnabled(isolate)) { + idle_task_pending_ = true; + auto task = new IdleTask(heap->isolate(), this); + V8::GetCurrentPlatform()->CallIdleOnForegroundThread(isolate, task); + } + } +} + + +void IncrementalMarkingJob::ScheduleDelayedTask(Heap* heap) { + if (!delayed_task_pending_) { + v8::Isolate* isolate = reinterpret_cast(heap->isolate()); + delayed_task_pending_ = true; + made_progress_since_last_delayed_task_ = false; + auto task = new DelayedTask(heap->isolate(), this); + V8::GetCurrentPlatform()->CallDelayedOnForegroundThread(isolate, task, + kDelayInSeconds); + } +} + + +IncrementalMarkingJob::IdleTask::Progress IncrementalMarkingJob::IdleTask::Step( + Heap* heap, double deadline_in_ms) { + IncrementalMarking* incremental_marking = heap->incremental_marking(); + MarkCompactCollector* mark_compact_collector = heap->mark_compact_collector(); + if (incremental_marking->IsStopped()) { + return kDone; + } + if (mark_compact_collector->sweeping_in_progress()) { + if (mark_compact_collector->IsSweepingCompleted()) { + mark_compact_collector->EnsureSweepingCompleted(); + } + return kMoreWork; + } + const double remaining_idle_time_in_ms = heap->AdvanceIncrementalMarking( + 0, deadline_in_ms, IncrementalMarking::IdleStepActions()); + if (remaining_idle_time_in_ms > 0.0) { + heap->TryFinalizeIdleIncrementalMarking(remaining_idle_time_in_ms); + } + return incremental_marking->IsStopped() ? kDone : kMoreWork; +} + + +void IncrementalMarkingJob::IdleTask::RunInternal(double deadline_in_seconds) { + double deadline_in_ms = + deadline_in_seconds * + static_cast(base::Time::kMillisecondsPerSecond); + Heap* heap = isolate_->heap(); + double start_ms = heap->MonotonicallyIncreasingTimeInMs(); + job_->NotifyIdleTask(); + job_->NotifyIdleTaskProgress(); + if (Step(heap, deadline_in_ms) == kMoreWork) { + job_->ScheduleIdleTask(heap); + } + if (FLAG_trace_idle_notification) { + double current_time_ms = heap->MonotonicallyIncreasingTimeInMs(); + double idle_time_in_ms = deadline_in_ms - start_ms; + double deadline_difference = deadline_in_ms - current_time_ms; + PrintIsolate(isolate_, "%8.0f ms: ", isolate_->time_millis_since_init()); + PrintF( + "Idle task: requested idle time %.2f ms, used idle time %.2f " + "ms, deadline usage %.2f ms\n", + idle_time_in_ms, idle_time_in_ms - deadline_difference, + deadline_difference); + } +} + + +void IncrementalMarkingJob::DelayedTask::Step(Heap* heap) { + const int kIncrementalMarkingDelayMs = 50; + double deadline = + heap->MonotonicallyIncreasingTimeInMs() + kIncrementalMarkingDelayMs; + heap->AdvanceIncrementalMarking( + 0, deadline, i::IncrementalMarking::StepActions( + i::IncrementalMarking::NO_GC_VIA_STACK_GUARD, + i::IncrementalMarking::FORCE_MARKING, + i::IncrementalMarking::FORCE_COMPLETION)); + heap->FinalizeIncrementalMarkingIfComplete( + "Incremental marking task: finalize incremental marking"); +} + + +void IncrementalMarkingJob::DelayedTask::RunInternal() { + Heap* heap = isolate_->heap(); + job_->NotifyDelayedTask(); + IncrementalMarking* incremental_marking = heap->incremental_marking(); + if (!incremental_marking->IsStopped()) { + if (job_->ShouldForceMarkingStep()) { + Step(heap); + } + // The Step() above could have finished incremental marking. + if (!incremental_marking->IsStopped()) { + job_->ScheduleDelayedTask(heap); + } + } +} + +} // namespace internal +} // namespace v8 diff --git a/src/heap/incremental-marking-job.h b/src/heap/incremental-marking-job.h new file mode 100644 index 0000000..fad46c1 --- /dev/null +++ b/src/heap/incremental-marking-job.h @@ -0,0 +1,81 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_HEAP_INCREMENTAL_MARKING_JOB_H_ +#define V8_HEAP_INCREMENTAL_MARKING_JOB_H_ + +#include "src/cancelable-task.h" + +namespace v8 { +namespace internal { + +class Heap; +class Isolate; + +// The incremental marking job uses platform tasks to perform incremental +// marking steps. The job posts an idle and a delayed task with a large delay. +// The delayed task performs steps only if the idle task is not making progress. +// We expect this to be a rare event since incremental marking should finish +// quickly with the help of the mutator and the idle task. +// The delayed task guarantees that we eventually finish incremental marking +// even if the mutator becomes idle and the platform stops running idle tasks, +// which can happen for background tabs in Chrome. +class IncrementalMarkingJob { + public: + class IdleTask : public CancelableIdleTask { + public: + explicit IdleTask(Isolate* isolate, IncrementalMarkingJob* job) + : CancelableIdleTask(isolate), job_(job) {} + enum Progress { kDone, kMoreWork }; + static Progress Step(Heap* heap, double deadline_in_ms); + // CancelableIdleTask overrides. + void RunInternal(double deadline_in_seconds) override; + + private: + IncrementalMarkingJob* job_; + }; + + class DelayedTask : public CancelableTask { + public: + explicit DelayedTask(Isolate* isolate, IncrementalMarkingJob* job) + : CancelableTask(isolate), job_(job) {} + static void Step(Heap* heap); + // CancelableTask overrides. + void RunInternal() override; + + private: + IncrementalMarkingJob* job_; + }; + + // Delay of the delayed task. + static const int kDelayInSeconds = 5; + + IncrementalMarkingJob() + : idle_task_pending_(false), + delayed_task_pending_(false), + made_progress_since_last_delayed_task_(false) {} + + bool ShouldForceMarkingStep() { + return !made_progress_since_last_delayed_task_; + } + + bool IdleTaskPending() { return idle_task_pending_; } + + void Start(Heap* heap); + + void NotifyIdleTask(); + void NotifyDelayedTask(); + void NotifyIdleTaskProgress(); + void ScheduleIdleTask(Heap* heap); + void ScheduleDelayedTask(Heap* heap); + + private: + bool idle_task_pending_; + bool delayed_task_pending_; + bool made_progress_since_last_delayed_task_; +}; +} +} // namespace v8::internal + +#endif // V8_HEAP_INCREMENTAL_MARKING_JOB_H_ diff --git a/src/heap/incremental-marking.cc b/src/heap/incremental-marking.cc index b420cb7..4fe9eef 100644 --- a/src/heap/incremental-marking.cc +++ b/src/heap/incremental-marking.cc @@ -11,6 +11,7 @@ #include "src/heap/mark-compact-inl.h" #include "src/heap/objects-visiting.h" #include "src/heap/objects-visiting-inl.h" +#include "src/v8.h" namespace v8 { namespace internal { @@ -486,6 +487,7 @@ void IncrementalMarking::Start(const char* reason) { } heap_->new_space()->LowerInlineAllocationLimit(kAllocatedThreshold); + incremental_marking_job()->Start(heap_); } diff --git a/src/heap/incremental-marking.h b/src/heap/incremental-marking.h index 18c8c0d..e0b449a 100644 --- a/src/heap/incremental-marking.h +++ b/src/heap/incremental-marking.h @@ -5,14 +5,15 @@ #ifndef V8_HEAP_INCREMENTAL_MARKING_H_ #define V8_HEAP_INCREMENTAL_MARKING_H_ +#include "src/cancelable-task.h" #include "src/execution.h" +#include "src/heap/incremental-marking-job.h" #include "src/heap/mark-compact.h" #include "src/objects.h" namespace v8 { namespace internal { - class IncrementalMarking { public: enum State { STOPPED, SWEEPING, MARKING, COMPLETE }; @@ -197,6 +198,10 @@ class IncrementalMarking { Heap* heap() const { return heap_; } + IncrementalMarkingJob* incremental_marking_job() { + return &incremental_marking_job_; + } + private: int64_t SpaceLeftInOldSpace(); @@ -255,6 +260,8 @@ class IncrementalMarking { GCRequestType request_type_; + IncrementalMarkingJob incremental_marking_job_; + DISALLOW_IMPLICIT_CONSTRUCTORS(IncrementalMarking); }; } diff --git a/src/v8.cc b/src/v8.cc index c7effb6..d7cc797 100644 --- a/src/v8.cc +++ b/src/v8.cc @@ -119,6 +119,9 @@ v8::Platform* V8::GetCurrentPlatform() { } +void V8::SetPlatformForTesting(v8::Platform* platform) { platform_ = platform; } + + void V8::SetNativesBlob(StartupData* natives_blob) { #ifdef V8_USE_EXTERNAL_STARTUP_DATA base::CallOnce(&init_natives_once, &SetNativesFromFile, natives_blob); diff --git a/src/v8.h b/src/v8.h index 3035b9a..f5b3b84 100644 --- a/src/v8.h +++ b/src/v8.h @@ -26,6 +26,9 @@ class V8 : public AllStatic { static void InitializePlatform(v8::Platform* platform); static void ShutdownPlatform(); static v8::Platform* GetCurrentPlatform(); + // Replaces the current platform with the given platform. + // Should be used only for testing. + static void SetPlatformForTesting(v8::Platform* platform); static void SetNativesBlob(StartupData* natives_blob); static void SetSnapshotBlob(StartupData* snapshot_blob); diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index f9ffade..d15820a 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -133,6 +133,7 @@ 'test-heap-profiler.cc', 'test-hydrogen-types.cc', 'test-identity-map.cc', + 'test-incremental-marking.cc', 'test-list.cc', 'test-liveedit.cc', 'test-lockers.cc', diff --git a/test/cctest/test-incremental-marking.cc b/test/cctest/test-incremental-marking.cc new file mode 100644 index 0000000..d8bdeee --- /dev/null +++ b/test/cctest/test-incremental-marking.cc @@ -0,0 +1,168 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#ifdef __linux__ +#include +#include +#include +#include +#include +#endif + +#include + +#include "src/v8.h" + +#include "src/full-codegen/full-codegen.h" +#include "src/global-handles.h" +#include "test/cctest/cctest.h" + +using v8::IdleTask; +using v8::Task; +using v8::Isolate; + + +class MockPlatform : public v8::Platform { + public: + explicit MockPlatform(v8::Platform* platform) + : platform_(platform), idle_task_(nullptr), delayed_task_(nullptr) {} + virtual ~MockPlatform() { + delete idle_task_; + delete delayed_task_; + } + + void CallOnBackgroundThread(Task* task, + ExpectedRuntime expected_runtime) override { + platform_->CallOnBackgroundThread(task, expected_runtime); + } + + void CallOnForegroundThread(Isolate* isolate, Task* task) override { + platform_->CallOnForegroundThread(isolate, task); + } + + void CallDelayedOnForegroundThread(Isolate* isolate, Task* task, + double delay_in_seconds) override { + if (delayed_task_ != nullptr) { + delete delayed_task_; + } + delayed_task_ = task; + } + + double MonotonicallyIncreasingTime() override { + return platform_->MonotonicallyIncreasingTime(); + } + + void CallIdleOnForegroundThread(Isolate* isolate, IdleTask* task) override { + CHECK(nullptr == idle_task_); + idle_task_ = task; + } + + bool IdleTasksEnabled(Isolate* isolate) override { return true; } + + bool PendingIdleTask() { return idle_task_ != nullptr; } + + void PerformIdleTask(double idle_time_in_seconds) { + IdleTask* task = idle_task_; + idle_task_ = nullptr; + task->Run(MonotonicallyIncreasingTime() + idle_time_in_seconds); + delete task; + } + + bool PendingDelayedTask() { return delayed_task_ != nullptr; } + + void PerformDelayedTask() { + Task* task = delayed_task_; + delayed_task_ = nullptr; + task->Run(); + delete task; + } + + private: + v8::Platform* platform_; + IdleTask* idle_task_; + Task* delayed_task_; +}; + + +TEST(IncrementalMarkingUsingIdleTasks) { + if (!i::FLAG_incremental_marking) return; + CcTest::InitializeVM(); + v8::Platform* old_platform = i::V8::GetCurrentPlatform(); + MockPlatform platform(old_platform); + i::V8::SetPlatformForTesting(&platform); + SimulateFullSpace(CcTest::heap()->old_space()); + i::IncrementalMarking* marking = CcTest::heap()->incremental_marking(); + marking->Stop(); + marking->Start(); + CHECK(platform.PendingIdleTask()); + const double kLongIdleTimeInSeconds = 1; + const double kShortIdleTimeInSeconds = 0.010; + const int kShortStepCount = 10; + for (int i = 0; i < kShortStepCount && platform.PendingIdleTask(); i++) { + platform.PerformIdleTask(kShortIdleTimeInSeconds); + } + while (platform.PendingIdleTask()) { + platform.PerformIdleTask(kLongIdleTimeInSeconds); + } + CHECK(marking->IsStopped()); + i::V8::SetPlatformForTesting(old_platform); +} + + +TEST(IncrementalMarkingUsingIdleTasksAfterGC) { + if (!i::FLAG_incremental_marking) return; + CcTest::InitializeVM(); + v8::Platform* old_platform = i::V8::GetCurrentPlatform(); + MockPlatform platform(old_platform); + i::V8::SetPlatformForTesting(&platform); + SimulateFullSpace(CcTest::heap()->old_space()); + CcTest::heap()->CollectAllGarbage(); + i::IncrementalMarking* marking = CcTest::heap()->incremental_marking(); + marking->Stop(); + marking->Start(); + CHECK(platform.PendingIdleTask()); + const double kLongIdleTimeInSeconds = 1; + const double kShortIdleTimeInSeconds = 0.010; + const int kShortStepCount = 10; + for (int i = 0; i < kShortStepCount && platform.PendingIdleTask(); i++) { + platform.PerformIdleTask(kShortIdleTimeInSeconds); + } + while (platform.PendingIdleTask()) { + platform.PerformIdleTask(kLongIdleTimeInSeconds); + } + CHECK(marking->IsStopped()); + i::V8::SetPlatformForTesting(old_platform); +} + + +TEST(IncrementalMarkingUsingDelayedTasks) { + if (!i::FLAG_incremental_marking) return; + CcTest::InitializeVM(); + v8::Platform* old_platform = i::V8::GetCurrentPlatform(); + MockPlatform platform(old_platform); + i::V8::SetPlatformForTesting(&platform); + SimulateFullSpace(CcTest::heap()->old_space()); + i::IncrementalMarking* marking = CcTest::heap()->incremental_marking(); + marking->Stop(); + marking->Start(); + CHECK(platform.PendingIdleTask()); + // The delayed task should be a no-op if the idle task makes progress. + const int kIgnoredDelayedTaskStepCount = 1000; + for (int i = 0; i < kIgnoredDelayedTaskStepCount; i++) { + // Dummy idle task progress. + marking->incremental_marking_job()->NotifyIdleTaskProgress(); + CHECK(platform.PendingDelayedTask()); + platform.PerformDelayedTask(); + } + // Once we stop notifying idle task progress, the delayed tasks + // should finish marking. + while (!marking->IsStopped() && platform.PendingDelayedTask()) { + platform.PerformDelayedTask(); + } + // There could be pending delayed task from memory reducer after GC finishes. + CHECK(marking->IsStopped()); + i::V8::SetPlatformForTesting(old_platform); +} diff --git a/test/unittests/heap/gc-idle-time-handler-unittest.cc b/test/unittests/heap/gc-idle-time-handler-unittest.cc index e74152a..d87a921 100644 --- a/test/unittests/heap/gc-idle-time-handler-unittest.cc +++ b/test/unittests/heap/gc-idle-time-handler-unittest.cc @@ -23,12 +23,8 @@ class GCIdleTimeHandlerTest : public ::testing::Test { GCIdleTimeHandler::HeapState result; result.contexts_disposed = 0; result.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate; - result.size_of_objects = kSizeOfObjects; result.incremental_marking_stopped = false; - result.sweeping_in_progress = false; - result.sweeping_completed = false; result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed; - result.incremental_marking_speed_in_bytes_per_ms = kMarkingSpeed; result.scavenge_speed_in_bytes_per_ms = kScavengeSpeed; result.used_new_space_size = 0; result.new_space_capacity = kNewSpaceCapacity; @@ -259,10 +255,9 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) { heap_state.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate; size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; - double idle_time_ms = - static_cast(heap_state.size_of_objects / speed - 1); + double idle_time_ms = static_cast(kSizeOfObjects / speed - 1); GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); + EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); } @@ -272,34 +267,17 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) { heap_state.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate; size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; - double idle_time_ms = - static_cast(heap_state.size_of_objects / speed - 1); + double idle_time_ms = static_cast(kSizeOfObjects / speed - 1); GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); + EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); } TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms; double idle_time_ms = 10; GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - EXPECT_GT(speed * static_cast(idle_time_ms), - static_cast(action.parameter)); - EXPECT_LT(0, action.parameter); -} - - -TEST_F(GCIdleTimeHandlerTest, IncrementalMarking2) { - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms; - double idle_time_ms = 10; - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); - EXPECT_GT(speed * static_cast(idle_time_ms), - static_cast(action.parameter)); - EXPECT_LT(0, action.parameter); + EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); } @@ -307,35 +285,12 @@ TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); heap_state.incremental_marking_stopped = true; size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; - double idle_time_ms = - static_cast(heap_state.size_of_objects / speed - 1); + double idle_time_ms = static_cast(kSizeOfObjects / speed - 1); GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(DONE, action.type); } -TEST_F(GCIdleTimeHandlerTest, FinalizeSweeping) { - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - heap_state.incremental_marking_stopped = true; - heap_state.sweeping_in_progress = true; - heap_state.sweeping_completed = true; - double idle_time_ms = 10.0; - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_FINALIZE_SWEEPING, action.type); -} - - -TEST_F(GCIdleTimeHandlerTest, CannotFinalizeSweeping) { - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - heap_state.incremental_marking_stopped = true; - heap_state.sweeping_in_progress = true; - heap_state.sweeping_completed = false; - double idle_time_ms = 10.0; - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_NOTHING, action.type); -} - - TEST_F(GCIdleTimeHandlerTest, Scavenge) { GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); int idle_time_ms = 10; @@ -382,7 +337,7 @@ TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop) { EXPECT_EQ(DONE, action.type); heap_state.incremental_marking_stopped = false; action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); + EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); } @@ -405,25 +360,6 @@ TEST_F(GCIdleTimeHandlerTest, SmallIdleTimeNothingToDo) { } -TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnSweeping) { - // Regression test for crbug.com/489323. - GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); - - // Simulate sweeping being in-progress but not complete. - heap_state.incremental_marking_stopped = true; - heap_state.sweeping_in_progress = true; - heap_state.sweeping_completed = false; - double idle_time_ms = 10.0; - for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimes; i++) { - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DO_NOTHING, action.type); - } - // We should return DONE after not making progress for some time. - GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); - EXPECT_EQ(DONE, action.type); -} - - TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnIncrementalMarking) { // Regression test for crbug.com/489323. GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index f336e04..808098e 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -713,6 +713,8 @@ '../../src/heap/heap.cc', '../../src/heap/heap.h', '../../src/heap/incremental-marking-inl.h', + '../../src/heap/incremental-marking-job.cc', + '../../src/heap/incremental-marking-job.h', '../../src/heap/incremental-marking.cc', '../../src/heap/incremental-marking.h', '../../src/heap/mark-compact-inl.h', -- 2.7.4