Commit 6a1b49d7 authored by ulan's avatar ulan Committed by Commit bot

[heap] Do more incremental marking work in tasks.

This patch changes incremental marking work scheduling from combination
of idle/delayed tasks to ordinary short-running tasks and moves
more marking work from V8.Execute to tasks by accounting how much
bytes were marked in tasks.

BUG=chromium:616434
LOG=NO

Review-Url: https://codereview.chromium.org/2321553002
Cr-Commit-Position: refs/heads/master@{#39348}
parent 8ffbd333
......@@ -937,7 +937,7 @@ void Heap::ReportExternalMemoryPressure() {
pressure * kMaxStepSizeOnExternalLimit;
incremental_marking()->AdvanceIncrementalMarking(
deadline, IncrementalMarking::GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8);
}
}
......@@ -1054,7 +1054,9 @@ bool Heap::CollectGarbage(GarbageCollector collector,
// Start incremental marking for the next cycle. The heap snapshot
// generator needs incremental marking to stay off after it aborted.
if (!ShouldAbortIncrementalMarking()) {
// We do this only for scavenger to avoid a loop where mark-compact
// causes another mark-compact.
if (collector == SCAVENGER && !ShouldAbortIncrementalMarking()) {
StartIncrementalMarkingIfAllocationLimitIsReached(kNoGCFlags,
kNoGCCallbackFlags);
}
......@@ -4294,15 +4296,16 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action,
result = true;
break;
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;
const double remaining_idle_time_in_ms =
incremental_marking()->AdvanceIncrementalMarking(
deadline_in_ms, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kTask);
if (remaining_idle_time_in_ms > 0.0) {
TryFinalizeIdleIncrementalMarking(
remaining_idle_time_in_ms,
GarbageCollectionReason::kFinalizeMarkingViaTask);
}
result = incremental_marking()->IsStopped();
break;
}
case DO_FULL_GC: {
......
......@@ -14,132 +14,41 @@
namespace v8 {
namespace internal {
const double IncrementalMarkingJob::kLongDelayInSeconds = 5;
const double IncrementalMarkingJob::kShortDelayInSeconds = 0.5;
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);
}
}
ScheduleTask(heap);
}
void IncrementalMarkingJob::NotifyTask() { task_pending_ = false; }
void IncrementalMarkingJob::ScheduleDelayedTask(Heap* heap) {
if (!delayed_task_pending_ && FLAG_memory_reducer) {
void IncrementalMarkingJob::ScheduleTask(Heap* heap) {
if (!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);
double delay =
heap->HighMemoryPressure() ? kShortDelayInSeconds : kLongDelayInSeconds;
V8::GetCurrentPlatform()->CallDelayedOnForegroundThread(isolate, task,
delay);
task_pending_ = true;
auto task = new Task(heap->isolate(), this);
V8::GetCurrentPlatform()->CallOnForegroundThread(isolate, task);
}
}
IncrementalMarkingJob::IdleTask::Progress IncrementalMarkingJob::IdleTask::Step(
Heap* heap, double deadline_in_ms) {
IncrementalMarking* incremental_marking = heap->incremental_marking();
if (incremental_marking->IsStopped()) {
return kDone;
}
if (incremental_marking->IsSweeping()) {
incremental_marking->FinalizeSweeping();
// TODO(hpayer): We can continue here if enough idle time is left.
return kMoreWork;
}
const double remaining_idle_time_in_ms =
incremental_marking->AdvanceIncrementalMarking(
deadline_in_ms, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::DO_NOT_FORCE_COMPLETION);
if (remaining_idle_time_in_ms > 0.0) {
heap->TryFinalizeIdleIncrementalMarking(
remaining_idle_time_in_ms,
GarbageCollectionReason::kFinalizeMarkingViaTask);
}
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;
void IncrementalMarkingJob::Task::Step(Heap* heap) {
const int kIncrementalMarkingDelayMs = 1;
double deadline =
heap->MonotonicallyIncreasingTimeInMs() + kIncrementalMarkingDelayMs;
heap->incremental_marking()->AdvanceIncrementalMarking(
deadline, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
deadline, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD,
i::IncrementalMarking::FORCE_COMPLETION, i::StepOrigin::kTask);
heap->FinalizeIncrementalMarkingIfComplete(
GarbageCollectionReason::kFinalizeMarkingViaTask);
}
void IncrementalMarkingJob::DelayedTask::RunInternal() {
void IncrementalMarkingJob::Task::RunInternal() {
Heap* heap = isolate()->heap();
job_->NotifyDelayedTask();
job_->NotifyTask();
IncrementalMarking* incremental_marking = heap->incremental_marking();
if (!incremental_marking->IsStopped()) {
if (job_->ShouldForceMarkingStep()) {
Step(heap);
}
// The Step() above could have finished incremental marking.
Step(heap);
if (!incremental_marking->IsStopped()) {
job_->ScheduleDelayedTask(heap);
job_->ScheduleTask(heap);
}
}
}
......
......@@ -14,31 +14,13 @@ 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.
// marking steps. The job posts a foreground task that makes a small (~1ms)
// step and posts another task until the marking is completed.
class IncrementalMarkingJob {
public:
class IdleTask : public CancelableIdleTask {
class Task : public CancelableTask {
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)
explicit Task(Isolate* isolate, IncrementalMarkingJob* job)
: CancelableTask(isolate), job_(job) {}
static void Step(Heap* heap);
// CancelableTask overrides.
......@@ -48,33 +30,18 @@ class IncrementalMarkingJob {
IncrementalMarkingJob* job_;
};
// Delay of the delayed task.
static const double kLongDelayInSeconds;
static const double kShortDelayInSeconds;
IncrementalMarkingJob()
: idle_task_pending_(false),
delayed_task_pending_(false),
made_progress_since_last_delayed_task_(false) {}
IncrementalMarkingJob() : task_pending_(false) {}
bool ShouldForceMarkingStep() {
return !made_progress_since_last_delayed_task_;
}
bool IdleTaskPending() { return idle_task_pending_; }
bool TaskPending() { return task_pending_; }
void Start(Heap* heap);
void NotifyIdleTask();
void NotifyDelayedTask();
void NotifyIdleTaskProgress();
void ScheduleIdleTask(Heap* heap);
void ScheduleDelayedTask(Heap* heap);
void NotifyTask();
void ScheduleTask(Heap* heap);
private:
bool idle_task_pending_;
bool delayed_task_pending_;
bool made_progress_since_last_delayed_task_;
bool task_pending_;
};
} // namespace internal
} // namespace v8
......
......@@ -33,6 +33,7 @@ IncrementalMarking::IncrementalMarking(Heap* heap)
bytes_scanned_(0),
allocated_(0),
write_barriers_invoked_since_last_step_(0),
bytes_marked_ahead_of_schedule_(0),
idle_marking_delay_counter_(0),
unscanned_bytes_of_large_object_(0),
was_activated_(false),
......@@ -1055,7 +1056,7 @@ void IncrementalMarking::Epilogue() {
double IncrementalMarking::AdvanceIncrementalMarking(
double deadline_in_ms, CompletionAction completion_action,
ForceCompletionAction force_completion) {
ForceCompletionAction force_completion, StepOrigin step_origin) {
DCHECK(!IsStopped());
double remaining_time_in_ms = 0.0;
......@@ -1064,7 +1065,7 @@ double IncrementalMarking::AdvanceIncrementalMarking(
heap()->tracer()->IncrementalMarkingSpeedInBytesPerMillisecond());
do {
Step(step_size_in_bytes, completion_action, force_completion);
Step(step_size_in_bytes, completion_action, force_completion, step_origin);
remaining_time_in_ms =
deadline_in_ms - heap()->MonotonicallyIncreasingTimeInMs();
} while (remaining_time_in_ms >= kStepSizeInMs && !IsComplete() &&
......@@ -1184,13 +1185,15 @@ void IncrementalMarking::NotifyAllocatedBytes(intptr_t allocated_bytes) {
intptr_t bytes_to_process =
marking_speed_ *
Max(allocated_, write_barriers_invoked_since_last_step_);
Step(bytes_to_process, GC_VIA_STACK_GUARD, FORCE_COMPLETION);
Step(bytes_to_process, GC_VIA_STACK_GUARD, FORCE_COMPLETION,
StepOrigin::kV8);
}
}
void IncrementalMarking::Step(intptr_t bytes_to_process,
CompletionAction action,
ForceCompletionAction completion) {
ForceCompletionAction completion,
StepOrigin step_origin) {
HistogramTimerScope incremental_marking_scope(
heap_->isolate()->counters()->gc_incremental_marking());
TRACE_EVENT0("v8", "V8.GCIncrementalMarking");
......@@ -1218,7 +1221,18 @@ void IncrementalMarking::Step(intptr_t bytes_to_process,
heap_->mark_compact_collector()->marking_deque()->IsEmpty());
bool wrapper_work_left = incremental_wrapper_tracing;
if (!process_wrappers) {
bytes_processed = ProcessMarkingDeque(bytes_to_process);
if (step_origin == StepOrigin::kV8 &&
bytes_marked_ahead_of_schedule_ >= bytes_to_process) {
// Steps performed in tasks have put us ahead of schedule.
// We skip processing of marking dequeue here and thus
// shift marking time from inside V8 to standalone tasks.
bytes_marked_ahead_of_schedule_ -= bytes_to_process;
} else {
bytes_processed = ProcessMarkingDeque(bytes_to_process);
if (step_origin == StepOrigin::kTask) {
bytes_marked_ahead_of_schedule_ += bytes_processed;
}
}
} else {
const double wrapper_deadline =
heap_->MonotonicallyIncreasingTimeInMs() + kStepSizeInMs;
......@@ -1261,6 +1275,13 @@ void IncrementalMarking::Step(intptr_t bytes_to_process,
// when we just started incremental marking. In these cases we did not
// process the marking deque.
heap_->tracer()->AddIncrementalMarkingStep(duration, bytes_processed);
if (FLAG_trace_incremental_marking) {
heap_->isolate()->PrintWithTimestamp(
"[IncrementalMarking] Step %s %d bytes (%d) in %.1f\n",
step_origin == StepOrigin::kV8 ? "in v8" : "in task",
static_cast<int>(bytes_processed), static_cast<int>(bytes_to_process),
duration);
}
}
......@@ -1274,6 +1295,7 @@ void IncrementalMarking::ResetStepCounters() {
marking_speed_ = kInitialMarkingSpeed;
bytes_scanned_ = 0;
write_barriers_invoked_since_last_step_ = 0;
bytes_marked_ahead_of_schedule_ = 0;
}
......
......@@ -20,6 +20,8 @@ namespace internal {
class MarkBit;
class PagedSpace;
enum class StepOrigin { kV8, kTask };
class IncrementalMarking {
public:
enum State { STOPPED, SWEEPING, MARKING, COMPLETE };
......@@ -97,7 +99,8 @@ class IncrementalMarking {
// anymore because a single step would exceed the deadline.
double AdvanceIncrementalMarking(double deadline_in_ms,
CompletionAction completion_action,
ForceCompletionAction force_completion);
ForceCompletionAction force_completion,
StepOrigin step_origin);
// It's hard to know how much work the incremental marker should do to make
// progress in the face of the mutator creating new work for it. We start
......@@ -129,7 +132,7 @@ class IncrementalMarking {
void NotifyAllocatedBytes(intptr_t allocated_bytes);
void Step(intptr_t bytes_to_process, CompletionAction action,
ForceCompletionAction completion);
ForceCompletionAction completion, StepOrigin origin);
inline void RestartIfNotMarking();
......@@ -294,6 +297,7 @@ class IncrementalMarking {
intptr_t bytes_scanned_;
intptr_t allocated_;
intptr_t write_barriers_invoked_since_last_step_;
intptr_t bytes_marked_ahead_of_schedule_;
size_t idle_marking_delay_counter_;
int unscanned_bytes_of_large_object_;
......
......@@ -86,7 +86,7 @@ void MemoryReducer::NotifyTimer(const Event& event) {
kIncrementalMarkingDelayMs;
heap()->incremental_marking()->AdvanceIncrementalMarking(
deadline, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kTask);
heap()->FinalizeIncrementalMarkingIfComplete(
GarbageCollectionReason::kFinalizeMarkingViaTask);
}
......
......@@ -161,7 +161,7 @@ void SimulateIncrementalMarking(i::Heap* heap, bool force_completion) {
while (!marking->IsComplete()) {
marking->Step(i::MB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD,
i::IncrementalMarking::FORCE_COMPLETION);
i::IncrementalMarking::FORCE_COMPLETION, i::StepOrigin::kV8);
if (marking->IsReadyToOverApproximateWeakClosure()) {
marking->FinalizeIncrementally();
}
......
......@@ -781,7 +781,7 @@ TEST(PromoteGreyOrBlackObjectsOnScavenge) {
while (
Marking::IsWhite(ObjectMarking::MarkBitFrom(HeapObject::cast(*marked)))) {
marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::DO_NOT_FORCE_COMPLETION);
IncrementalMarking::DO_NOT_FORCE_COMPLETION, StepOrigin::kV8);
}
CcTest::CollectGarbage(NEW_SPACE);
......@@ -2678,7 +2678,7 @@ TEST(InstanceOfStubWriteBarrier) {
// Discard any pending GC requests otherwise we will get GC when we enter
// code below.
marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8);
}
CHECK(marking->IsMarking());
......@@ -2846,7 +2846,7 @@ TEST(IdleNotificationFinishMarking) {
// Perform a huge incremental marking step but don't complete marking.
do {
marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::DO_NOT_FORCE_COMPLETION);
IncrementalMarking::DO_NOT_FORCE_COMPLETION, StepOrigin::kV8);
CHECK(!marking->IsIdleMarkingDelayCounterLimitReached());
} while (
!CcTest::heap()->mark_compact_collector()->marking_deque()->IsEmpty());
......@@ -2857,7 +2857,7 @@ TEST(IdleNotificationFinishMarking) {
for (size_t i = 0; i < IncrementalMarking::kMaxIdleMarkingDelayCounter - 2;
i++) {
marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::DO_NOT_FORCE_COMPLETION);
IncrementalMarking::DO_NOT_FORCE_COMPLETION, StepOrigin::kV8);
CHECK(!marking->IsIdleMarkingDelayCounterLimitReached());
}
......@@ -4611,7 +4611,7 @@ TEST(LargeObjectSlotRecording) {
heap::SimulateIncrementalMarking(heap, false);
heap->incremental_marking()->AdvanceIncrementalMarking(
10000000, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8);
// Create references from the large object to the object on the evacuation
// candidate.
......@@ -4674,7 +4674,7 @@ TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) {
}
// This big step should be sufficient to mark the whole array.
marking->Step(100 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8);
CHECK(marking->IsComplete() ||
marking->IsReadyToOverApproximateWeakClosure());
}
......@@ -5493,7 +5493,7 @@ TEST(WeakCellsWithIncrementalMarking) {
i::GarbageCollectionReason::kTesting);
}
marking->Step(128, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8);
CcTest::CollectGarbage(NEW_SPACE);
CHECK(weak_cell->value()->IsFixedArray());
weak_cells[i] = inner_scope.CloseAndEscape(weak_cell);
......@@ -5815,7 +5815,7 @@ TEST(Regress3631) {
ObjectMarking::MarkBitFrom(HeapObject::cast(weak_map->table()))) &&
!marking->IsStopped()) {
marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8);
}
// Stash the backing store in a handle.
Handle<Object> save(weak_map->table(), isolate);
......@@ -6656,7 +6656,7 @@ TEST(Regress598319) {
// only partially marked the large object.
while (!marking->IsComplete()) {
marking->Step(i::KB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8);
if (page->IsFlagSet(Page::HAS_PROGRESS_BAR) && page->progress_bar() > 0) {
CHECK_NE(page->progress_bar(), arr.get()->Size());
{
......@@ -6674,7 +6674,7 @@ TEST(Regress598319) {
// Finish marking with bigger steps to speed up test.
while (!marking->IsComplete()) {
marking->Step(10 * i::MB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8);
if (marking->IsReadyToOverApproximateWeakClosure()) {
marking->FinalizeIncrementally();
}
......@@ -6729,7 +6729,7 @@ TEST(Regress615489) {
}
while (!marking->IsComplete()) {
marking->Step(i::MB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8);
if (marking->IsReadyToOverApproximateWeakClosure()) {
marking->FinalizeIncrementally();
}
......@@ -6789,7 +6789,7 @@ TEST(Regress631969) {
IncrementalMarking* marking = heap->incremental_marking();
while (!marking->IsComplete()) {
marking->Step(MB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_COMPLETION);
IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8);
if (marking->IsReadyToOverApproximateWeakClosure()) {
marking->FinalizeIncrementally();
}
......
......@@ -31,11 +31,8 @@ namespace internal {
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_;
}
: platform_(platform), task_(nullptr) {}
virtual ~MockPlatform() { delete task_; }
void CallOnBackgroundThread(Task* task,
ExpectedRuntime expected_runtime) override {
......@@ -43,15 +40,12 @@ class MockPlatform : public v8::Platform {
}
void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
platform_->CallOnForegroundThread(isolate, task);
task_ = task;
}
void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
double delay_in_seconds) override {
if (delayed_task_ != nullptr) {
delete delayed_task_;
}
delayed_task_ = task;
platform_->CallDelayedOnForegroundThread(isolate, task, delay_in_seconds);
}
double MonotonicallyIncreasingTime() override {
......@@ -60,26 +54,16 @@ class MockPlatform : public v8::Platform {
void CallIdleOnForegroundThread(v8::Isolate* isolate,
IdleTask* task) override {
CHECK(nullptr == idle_task_);
idle_task_ = task;
platform_->CallIdleOnForegroundThread(isolate, task);
}
bool IdleTasksEnabled(v8::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 PendingTask() { return task_ != nullptr; }
bool PendingDelayedTask() { return delayed_task_ != nullptr; }
void PerformDelayedTask() {
Task* task = delayed_task_;
delayed_task_ = nullptr;
void PerformTask() {
Task* task = task_;
task_ = nullptr;
task->Run();
delete task;
}
......@@ -108,12 +92,10 @@ class MockPlatform : public v8::Platform {
private:
v8::Platform* platform_;
IdleTask* idle_task_;
Task* delayed_task_;
Task* task_;
};
TEST(IncrementalMarkingUsingIdleTasks) {
TEST(IncrementalMarkingUsingTasks) {
if (!i::FLAG_incremental_marking) return;
CcTest::InitializeVM();
v8::Platform* old_platform = i::V8::GetCurrentPlatform();
......@@ -123,15 +105,9 @@ TEST(IncrementalMarkingUsingIdleTasks) {
i::IncrementalMarking* marking = CcTest::heap()->incremental_marking();
marking->Stop();
marking->Start(i::GarbageCollectionReason::kTesting);
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(platform.PendingTask());
while (platform.PendingTask()) {
platform.PerformTask();
}
CHECK(marking->IsStopped());
i::V8::SetPlatformForTesting(old_platform);
......@@ -141,9 +117,6 @@ TEST(IncrementalMarkingUsingIdleTasks) {
TEST(IncrementalMarkingUsingIdleTasksAfterGC) {
if (!i::FLAG_incremental_marking) return;
const double kLongIdleTimeInSeconds = 1;
const double kShortIdleTimeInSeconds = 0.010;
CcTest::InitializeVM();
v8::Platform* old_platform = i::V8::GetCurrentPlatform();
MockPlatform platform(old_platform);
......@@ -151,51 +124,17 @@ TEST(IncrementalMarkingUsingIdleTasksAfterGC) {
i::heap::SimulateFullSpace(CcTest::heap()->old_space());
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
// Perform any pending idle tasks.
while (platform.PendingIdleTask()) {
platform.PerformIdleTask(kLongIdleTimeInSeconds);
while (platform.PendingTask()) {
platform.PerformTask();
}
CHECK(!platform.PendingIdleTask());
CHECK(!platform.PendingTask());
i::IncrementalMarking* marking = CcTest::heap()->incremental_marking();
marking->Stop();
marking->Start(i::GarbageCollectionReason::kTesting);
CHECK(platform.PendingIdleTask());
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);
i::heap::SimulateFullSpace(CcTest::heap()->old_space());
i::IncrementalMarking* marking = CcTest::heap()->incremental_marking();
marking->Stop();
marking->Start(i::GarbageCollectionReason::kTesting);
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();
CHECK(platform.PendingTask());
while (platform.PendingTask()) {
platform.PerformTask();
}
// There could be pending delayed task from memory reducer after GC finishes.
CHECK(marking->IsStopped());
i::V8::SetPlatformForTesting(old_platform);
}
......
......@@ -449,6 +449,9 @@ TEST(CompactionSpace) {
TEST(LargeObjectSpace) {
// This test does not initialize allocated objects, which confuses the
// incremental marker.
FLAG_incremental_marking = false;
v8::V8::Initialize();
LargeObjectSpace* lo = CcTest::heap()->lo_space();
......
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