blob: fe14dd04c68bb09bb31e3e1d80741e180829ff38 [file] [log] [blame]
// 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 {
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);
}
}
}
void IncrementalMarkingJob::ScheduleDelayedTask(Heap* heap) {
if (!delayed_task_pending_ && FLAG_memory_reducer) {
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);
}
}
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::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->incremental_marking()->AdvanceIncrementalMarking(
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