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