普通文本  |  148行  |  5.08 KB

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