Commit 057514d3 authored by ulan's avatar ulan Committed by Commit bot

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}
parent 244cc0a6
...@@ -968,6 +968,8 @@ source_set("v8_base") { ...@@ -968,6 +968,8 @@ source_set("v8_base") {
"src/heap/heap-inl.h", "src/heap/heap-inl.h",
"src/heap/heap.cc", "src/heap/heap.cc",
"src/heap/heap.h", "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.cc",
"src/heap/incremental-marking.h", "src/heap/incremental-marking.h",
"src/heap/mark-compact-inl.h", "src/heap/mark-compact-inl.h",
......
...@@ -26,9 +26,8 @@ void GCIdleTimeAction::Print() { ...@@ -26,9 +26,8 @@ void GCIdleTimeAction::Print() {
case DO_NOTHING: case DO_NOTHING:
PrintF("no action"); PrintF("no action");
break; break;
case DO_INCREMENTAL_MARKING: case DO_INCREMENTAL_STEP:
PrintF("incremental marking with step %" V8_PTR_PREFIX "d / ms", PrintF("incremental step");
parameter);
if (additional_work) { if (additional_work) {
PrintF("; finalized marking"); PrintF("; finalized marking");
} }
...@@ -39,9 +38,6 @@ void GCIdleTimeAction::Print() { ...@@ -39,9 +38,6 @@ void GCIdleTimeAction::Print() {
case DO_FULL_GC: case DO_FULL_GC:
PrintF("full GC"); PrintF("full GC");
break; break;
case DO_FINALIZE_SWEEPING:
PrintF("finalize sweeping");
break;
} }
} }
...@@ -271,22 +267,11 @@ GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms, ...@@ -271,22 +267,11 @@ GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms,
return GCIdleTimeAction::Scavenge(); 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) { if (!FLAG_incremental_marking || heap_state.incremental_marking_stopped) {
return GCIdleTimeAction::Done(); return GCIdleTimeAction::Done();
} }
size_t step_size = EstimateMarkingStepSize( return GCIdleTimeAction::IncrementalStep();
static_cast<size_t>(kIncrementalMarkingStepTimeInMs),
heap_state.incremental_marking_speed_in_bytes_per_ms);
return GCIdleTimeAction::IncrementalMarking(step_size);
} }
......
...@@ -13,10 +13,9 @@ namespace internal { ...@@ -13,10 +13,9 @@ namespace internal {
enum GCIdleTimeActionType { enum GCIdleTimeActionType {
DONE, DONE,
DO_NOTHING, DO_NOTHING,
DO_INCREMENTAL_MARKING, DO_INCREMENTAL_STEP,
DO_SCAVENGE, DO_SCAVENGE,
DO_FULL_GC, DO_FULL_GC,
DO_FINALIZE_SWEEPING
}; };
...@@ -25,7 +24,6 @@ class GCIdleTimeAction { ...@@ -25,7 +24,6 @@ class GCIdleTimeAction {
static GCIdleTimeAction Done() { static GCIdleTimeAction Done() {
GCIdleTimeAction result; GCIdleTimeAction result;
result.type = DONE; result.type = DONE;
result.parameter = 0;
result.additional_work = false; result.additional_work = false;
return result; return result;
} }
...@@ -33,15 +31,13 @@ class GCIdleTimeAction { ...@@ -33,15 +31,13 @@ class GCIdleTimeAction {
static GCIdleTimeAction Nothing() { static GCIdleTimeAction Nothing() {
GCIdleTimeAction result; GCIdleTimeAction result;
result.type = DO_NOTHING; result.type = DO_NOTHING;
result.parameter = 0;
result.additional_work = false; result.additional_work = false;
return result; return result;
} }
static GCIdleTimeAction IncrementalMarking(intptr_t step_size) { static GCIdleTimeAction IncrementalStep() {
GCIdleTimeAction result; GCIdleTimeAction result;
result.type = DO_INCREMENTAL_MARKING; result.type = DO_INCREMENTAL_STEP;
result.parameter = step_size;
result.additional_work = false; result.additional_work = false;
return result; return result;
} }
...@@ -49,7 +45,6 @@ class GCIdleTimeAction { ...@@ -49,7 +45,6 @@ class GCIdleTimeAction {
static GCIdleTimeAction Scavenge() { static GCIdleTimeAction Scavenge() {
GCIdleTimeAction result; GCIdleTimeAction result;
result.type = DO_SCAVENGE; result.type = DO_SCAVENGE;
result.parameter = 0;
result.additional_work = false; result.additional_work = false;
return result; return result;
} }
...@@ -57,15 +52,6 @@ class GCIdleTimeAction { ...@@ -57,15 +52,6 @@ class GCIdleTimeAction {
static GCIdleTimeAction FullGC() { static GCIdleTimeAction FullGC() {
GCIdleTimeAction result; GCIdleTimeAction result;
result.type = DO_FULL_GC; 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; result.additional_work = false;
return result; return result;
} }
...@@ -73,7 +59,6 @@ class GCIdleTimeAction { ...@@ -73,7 +59,6 @@ class GCIdleTimeAction {
void Print(); void Print();
GCIdleTimeActionType type; GCIdleTimeActionType type;
intptr_t parameter;
bool additional_work; bool additional_work;
}; };
......
...@@ -4535,10 +4535,12 @@ void Heap::FinalizeIncrementalMarkingIfComplete(const char* comment) { ...@@ -4535,10 +4535,12 @@ void Heap::FinalizeIncrementalMarkingIfComplete(const char* comment) {
} }
bool Heap::TryFinalizeIdleIncrementalMarking( bool Heap::TryFinalizeIdleIncrementalMarking(double idle_time_in_ms) {
double idle_time_in_ms, size_t size_of_objects, size_t size_of_objects = static_cast<size_t>(SizeOfObjects());
size_t final_incremental_mark_compact_speed_in_bytes_per_ms) { size_t final_incremental_mark_compact_speed_in_bytes_per_ms =
if (FLAG_overapproximate_weak_closure && incremental_marking()->IsMarking() && static_cast<size_t>(
tracer()->FinalIncrementalMarkCompactSpeedInBytesPerMillisecond());
if (FLAG_overapproximate_weak_closure &&
(incremental_marking()->IsReadyToOverApproximateWeakClosure() || (incremental_marking()->IsReadyToOverApproximateWeakClosure() ||
(!incremental_marking()->weak_closure_was_overapproximated() && (!incremental_marking()->weak_closure_was_overapproximated() &&
mark_compact_collector_.marking_deque()->IsEmpty() && mark_compact_collector_.marking_deque()->IsEmpty() &&
...@@ -4565,19 +4567,9 @@ GCIdleTimeHandler::HeapState Heap::ComputeHeapState() { ...@@ -4565,19 +4567,9 @@ GCIdleTimeHandler::HeapState Heap::ComputeHeapState() {
heap_state.contexts_disposed = contexts_disposed_; heap_state.contexts_disposed = contexts_disposed_;
heap_state.contexts_disposal_rate = heap_state.contexts_disposal_rate =
tracer()->ContextDisposalRateInMilliseconds(); tracer()->ContextDisposalRateInMilliseconds();
heap_state.size_of_objects = static_cast<size_t>(SizeOfObjects());
heap_state.incremental_marking_stopped = incremental_marking()->IsStopped(); 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 = heap_state.mark_compact_speed_in_bytes_per_ms =
static_cast<size_t>(tracer()->MarkCompactSpeedInBytesPerMillisecond()); static_cast<size_t>(tracer()->MarkCompactSpeedInBytesPerMillisecond());
heap_state.incremental_marking_speed_in_bytes_per_ms = static_cast<size_t>(
tracer()->IncrementalMarkingSpeedInBytesPerMillisecond());
heap_state.final_incremental_mark_compact_speed_in_bytes_per_ms =
static_cast<size_t>(
tracer()->FinalIncrementalMarkCompactSpeedInBytesPerMillisecond());
heap_state.scavenge_speed_in_bytes_per_ms = heap_state.scavenge_speed_in_bytes_per_ms =
static_cast<size_t>(tracer()->ScavengeSpeedInBytesPerMillisecond()); static_cast<size_t>(tracer()->ScavengeSpeedInBytesPerMillisecond());
heap_state.used_new_space_size = new_space_.Size(); heap_state.used_new_space_size = new_space_.Size();
...@@ -4622,14 +4614,15 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action, ...@@ -4622,14 +4614,15 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action,
case DONE: case DONE:
result = true; result = true;
break; break;
case DO_INCREMENTAL_MARKING: { case DO_INCREMENTAL_STEP: {
const double remaining_idle_time_in_ms = if (incremental_marking()->incremental_marking_job()->IdleTaskPending()) {
AdvanceIncrementalMarking(action.parameter, deadline_in_ms, result = true;
IncrementalMarking::IdleStepActions()); } else {
if (remaining_idle_time_in_ms > 0.0) { incremental_marking()
action.additional_work = TryFinalizeIdleIncrementalMarking( ->incremental_marking_job()
remaining_idle_time_in_ms, heap_state.size_of_objects, ->NotifyIdleTaskProgress();
heap_state.final_incremental_mark_compact_speed_in_bytes_per_ms); result = IncrementalMarkingJob::IdleTask::Step(this, deadline_in_ms) ==
IncrementalMarkingJob::IdleTask::kDone;
} }
break; break;
} }
...@@ -4642,9 +4635,6 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action, ...@@ -4642,9 +4635,6 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action,
case DO_SCAVENGE: case DO_SCAVENGE:
CollectGarbage(NEW_SPACE, "idle notification: scavenge"); CollectGarbage(NEW_SPACE, "idle notification: scavenge");
break; break;
case DO_FINALIZE_SWEEPING:
mark_compact_collector()->EnsureSweepingCompleted();
break;
case DO_NOTHING: case DO_NOTHING:
break; break;
} }
......
...@@ -1278,6 +1278,8 @@ class Heap { ...@@ -1278,6 +1278,8 @@ class Heap {
void FinalizeIncrementalMarkingIfComplete(const char* comment); void FinalizeIncrementalMarkingIfComplete(const char* comment);
bool TryFinalizeIdleIncrementalMarking(double idle_time_in_ms);
IncrementalMarking* incremental_marking() { return &incremental_marking_; } IncrementalMarking* incremental_marking() { return &incremental_marking_; }
// =========================================================================== // ===========================================================================
......
// 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<v8::Isolate*>(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<v8::Isolate*>(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<double>(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
// 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_
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "src/heap/mark-compact-inl.h" #include "src/heap/mark-compact-inl.h"
#include "src/heap/objects-visiting.h" #include "src/heap/objects-visiting.h"
#include "src/heap/objects-visiting-inl.h" #include "src/heap/objects-visiting-inl.h"
#include "src/v8.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -486,6 +487,7 @@ void IncrementalMarking::Start(const char* reason) { ...@@ -486,6 +487,7 @@ void IncrementalMarking::Start(const char* reason) {
} }
heap_->new_space()->LowerInlineAllocationLimit(kAllocatedThreshold); heap_->new_space()->LowerInlineAllocationLimit(kAllocatedThreshold);
incremental_marking_job()->Start(heap_);
} }
......
...@@ -5,14 +5,15 @@ ...@@ -5,14 +5,15 @@
#ifndef V8_HEAP_INCREMENTAL_MARKING_H_ #ifndef V8_HEAP_INCREMENTAL_MARKING_H_
#define V8_HEAP_INCREMENTAL_MARKING_H_ #define V8_HEAP_INCREMENTAL_MARKING_H_
#include "src/cancelable-task.h"
#include "src/execution.h" #include "src/execution.h"
#include "src/heap/incremental-marking-job.h"
#include "src/heap/mark-compact.h" #include "src/heap/mark-compact.h"
#include "src/objects.h" #include "src/objects.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class IncrementalMarking { class IncrementalMarking {
public: public:
enum State { STOPPED, SWEEPING, MARKING, COMPLETE }; enum State { STOPPED, SWEEPING, MARKING, COMPLETE };
...@@ -197,6 +198,10 @@ class IncrementalMarking { ...@@ -197,6 +198,10 @@ class IncrementalMarking {
Heap* heap() const { return heap_; } Heap* heap() const { return heap_; }
IncrementalMarkingJob* incremental_marking_job() {
return &incremental_marking_job_;
}
private: private:
int64_t SpaceLeftInOldSpace(); int64_t SpaceLeftInOldSpace();
...@@ -255,6 +260,8 @@ class IncrementalMarking { ...@@ -255,6 +260,8 @@ class IncrementalMarking {
GCRequestType request_type_; GCRequestType request_type_;
IncrementalMarkingJob incremental_marking_job_;
DISALLOW_IMPLICIT_CONSTRUCTORS(IncrementalMarking); DISALLOW_IMPLICIT_CONSTRUCTORS(IncrementalMarking);
}; };
} }
......
...@@ -119,6 +119,9 @@ v8::Platform* V8::GetCurrentPlatform() { ...@@ -119,6 +119,9 @@ v8::Platform* V8::GetCurrentPlatform() {
} }
void V8::SetPlatformForTesting(v8::Platform* platform) { platform_ = platform; }
void V8::SetNativesBlob(StartupData* natives_blob) { void V8::SetNativesBlob(StartupData* natives_blob) {
#ifdef V8_USE_EXTERNAL_STARTUP_DATA #ifdef V8_USE_EXTERNAL_STARTUP_DATA
base::CallOnce(&init_natives_once, &SetNativesFromFile, natives_blob); base::CallOnce(&init_natives_once, &SetNativesFromFile, natives_blob);
......
...@@ -26,6 +26,9 @@ class V8 : public AllStatic { ...@@ -26,6 +26,9 @@ class V8 : public AllStatic {
static void InitializePlatform(v8::Platform* platform); static void InitializePlatform(v8::Platform* platform);
static void ShutdownPlatform(); static void ShutdownPlatform();
static v8::Platform* GetCurrentPlatform(); 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 SetNativesBlob(StartupData* natives_blob);
static void SetSnapshotBlob(StartupData* snapshot_blob); static void SetSnapshotBlob(StartupData* snapshot_blob);
......
...@@ -133,6 +133,7 @@ ...@@ -133,6 +133,7 @@
'test-heap-profiler.cc', 'test-heap-profiler.cc',
'test-hydrogen-types.cc', 'test-hydrogen-types.cc',
'test-identity-map.cc', 'test-identity-map.cc',
'test-incremental-marking.cc',
'test-list.cc', 'test-list.cc',
'test-liveedit.cc', 'test-liveedit.cc',
'test-lockers.cc', 'test-lockers.cc',
......
// 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 <stdlib.h>
#ifdef __linux__
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#include <utility>
#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);
}
...@@ -23,12 +23,8 @@ class GCIdleTimeHandlerTest : public ::testing::Test { ...@@ -23,12 +23,8 @@ class GCIdleTimeHandlerTest : public ::testing::Test {
GCIdleTimeHandler::HeapState result; GCIdleTimeHandler::HeapState result;
result.contexts_disposed = 0; result.contexts_disposed = 0;
result.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate; result.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate;
result.size_of_objects = kSizeOfObjects;
result.incremental_marking_stopped = false; result.incremental_marking_stopped = false;
result.sweeping_in_progress = false;
result.sweeping_completed = false;
result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed; 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.scavenge_speed_in_bytes_per_ms = kScavengeSpeed;
result.used_new_space_size = 0; result.used_new_space_size = 0;
result.new_space_capacity = kNewSpaceCapacity; result.new_space_capacity = kNewSpaceCapacity;
...@@ -259,10 +255,9 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) { ...@@ -259,10 +255,9 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) {
heap_state.contexts_disposal_rate = heap_state.contexts_disposal_rate =
GCIdleTimeHandler::kHighContextDisposalRate; GCIdleTimeHandler::kHighContextDisposalRate;
size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
double idle_time_ms = double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1);
static_cast<double>(heap_state.size_of_objects / speed - 1);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 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) { ...@@ -272,34 +267,17 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) {
heap_state.contexts_disposal_rate = heap_state.contexts_disposal_rate =
GCIdleTimeHandler::kHighContextDisposalRate; GCIdleTimeHandler::kHighContextDisposalRate;
size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
double idle_time_ms = double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1);
static_cast<double>(heap_state.size_of_objects / speed - 1);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 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) { TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
double idle_time_ms = 10; double idle_time_ms = 10;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); EXPECT_EQ(DO_INCREMENTAL_STEP, action.type);
EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
static_cast<size_t>(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<size_t>(idle_time_ms),
static_cast<size_t>(action.parameter));
EXPECT_LT(0, action.parameter);
} }
...@@ -307,35 +285,12 @@ TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) { ...@@ -307,35 +285,12 @@ TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
heap_state.incremental_marking_stopped = true; heap_state.incremental_marking_stopped = true;
size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
double idle_time_ms = double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1);
static_cast<double>(heap_state.size_of_objects / speed - 1);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DONE, action.type); 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) { TEST_F(GCIdleTimeHandlerTest, Scavenge) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
int idle_time_ms = 10; int idle_time_ms = 10;
...@@ -382,7 +337,7 @@ TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop) { ...@@ -382,7 +337,7 @@ TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop) {
EXPECT_EQ(DONE, action.type); EXPECT_EQ(DONE, action.type);
heap_state.incremental_marking_stopped = false; heap_state.incremental_marking_stopped = false;
action = handler()->Compute(idle_time_ms, heap_state); 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) { ...@@ -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) { TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnIncrementalMarking) {
// Regression test for crbug.com/489323. // Regression test for crbug.com/489323.
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
......
...@@ -713,6 +713,8 @@ ...@@ -713,6 +713,8 @@
'../../src/heap/heap.cc', '../../src/heap/heap.cc',
'../../src/heap/heap.h', '../../src/heap/heap.h',
'../../src/heap/incremental-marking-inl.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.cc',
'../../src/heap/incremental-marking.h', '../../src/heap/incremental-marking.h',
'../../src/heap/mark-compact-inl.h', '../../src/heap/mark-compact-inl.h',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment