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}
This commit is contained in:
ulan 2015-09-08 08:54:24 -07:00 committed by Commit bot
parent 244cc0a6a9
commit 057514d3fa
15 changed files with 444 additions and 133 deletions

View File

@ -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",

View File

@ -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<size_t>(kIncrementalMarkingStepTimeInMs),
heap_state.incremental_marking_speed_in_bytes_per_ms);
return GCIdleTimeAction::IncrementalMarking(step_size);
return GCIdleTimeAction::IncrementalStep();
}

View File

@ -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;
};

View File

@ -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<size_t>(SizeOfObjects());
size_t final_incremental_mark_compact_speed_in_bytes_per_ms =
static_cast<size_t>(
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<size_t>(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<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 =
static_cast<size_t>(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;
}

View File

@ -1278,6 +1278,8 @@ class Heap {
void FinalizeIncrementalMarkingIfComplete(const char* comment);
bool TryFinalizeIdleIncrementalMarking(double idle_time_in_ms);
IncrementalMarking* incremental_marking() { return &incremental_marking_; }
// ===========================================================================

View File

@ -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<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

View File

@ -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_

View File

@ -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_);
}

View File

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

View File

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

View File

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

View File

@ -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',

View File

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

View File

@ -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<double>(heap_state.size_of_objects / speed - 1);
double idle_time_ms = static_cast<double>(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<double>(heap_state.size_of_objects / speed - 1);
double idle_time_ms = static_cast<double>(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<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);
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<double>(heap_state.size_of_objects / speed - 1);
double idle_time_ms = static_cast<double>(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();

View File

@ -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',