• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/heap/incremental-marking-job.h"
6 
7 #include "src/base/platform/time.h"
8 #include "src/heap/heap-inl.h"
9 #include "src/heap/heap.h"
10 #include "src/heap/incremental-marking.h"
11 #include "src/isolate.h"
12 #include "src/v8.h"
13 
14 namespace v8 {
15 namespace internal {
16 
17 const double IncrementalMarkingJob::kLongDelayInSeconds = 5;
18 const double IncrementalMarkingJob::kShortDelayInSeconds = 0.5;
19 
Start(Heap * heap)20 void IncrementalMarkingJob::Start(Heap* heap) {
21   DCHECK(!heap->incremental_marking()->IsStopped());
22   // We don't need to reset the flags because tasks from the previous job
23   // can still be pending. We just want to ensure that tasks are posted
24   // if they are not pending.
25   // If delayed task is pending and made_progress_since_last_delayed_task_ is
26   // true, then the delayed task will clear that flag when it is rescheduled.
27   ScheduleIdleTask(heap);
28   ScheduleDelayedTask(heap);
29 }
30 
31 
NotifyIdleTask()32 void IncrementalMarkingJob::NotifyIdleTask() { idle_task_pending_ = false; }
33 
34 
NotifyDelayedTask()35 void IncrementalMarkingJob::NotifyDelayedTask() {
36   delayed_task_pending_ = false;
37 }
38 
39 
NotifyIdleTaskProgress()40 void IncrementalMarkingJob::NotifyIdleTaskProgress() {
41   made_progress_since_last_delayed_task_ = true;
42 }
43 
44 
ScheduleIdleTask(Heap * heap)45 void IncrementalMarkingJob::ScheduleIdleTask(Heap* heap) {
46   if (!idle_task_pending_) {
47     v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate());
48     if (V8::GetCurrentPlatform()->IdleTasksEnabled(isolate)) {
49       idle_task_pending_ = true;
50       auto task = new IdleTask(heap->isolate(), this);
51       V8::GetCurrentPlatform()->CallIdleOnForegroundThread(isolate, task);
52     }
53   }
54 }
55 
56 
ScheduleDelayedTask(Heap * heap)57 void IncrementalMarkingJob::ScheduleDelayedTask(Heap* heap) {
58   if (!delayed_task_pending_ && FLAG_memory_reducer) {
59     v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate());
60     delayed_task_pending_ = true;
61     made_progress_since_last_delayed_task_ = false;
62     auto task = new DelayedTask(heap->isolate(), this);
63     double delay =
64         heap->HighMemoryPressure() ? kShortDelayInSeconds : kLongDelayInSeconds;
65     V8::GetCurrentPlatform()->CallDelayedOnForegroundThread(isolate, task,
66                                                             delay);
67   }
68 }
69 
70 
Step(Heap * heap,double deadline_in_ms)71 IncrementalMarkingJob::IdleTask::Progress IncrementalMarkingJob::IdleTask::Step(
72     Heap* heap, double deadline_in_ms) {
73   IncrementalMarking* incremental_marking = heap->incremental_marking();
74   if (incremental_marking->IsStopped()) {
75     return kDone;
76   }
77   if (incremental_marking->IsSweeping()) {
78     incremental_marking->FinalizeSweeping();
79     // TODO(hpayer): We can continue here if enough idle time is left.
80     return kMoreWork;
81   }
82   const double remaining_idle_time_in_ms =
83       incremental_marking->AdvanceIncrementalMarking(
84           deadline_in_ms, IncrementalMarking::IdleStepActions());
85   if (remaining_idle_time_in_ms > 0.0) {
86     heap->TryFinalizeIdleIncrementalMarking(remaining_idle_time_in_ms);
87   }
88   return incremental_marking->IsStopped() ? kDone : kMoreWork;
89 }
90 
91 
RunInternal(double deadline_in_seconds)92 void IncrementalMarkingJob::IdleTask::RunInternal(double deadline_in_seconds) {
93   double deadline_in_ms =
94       deadline_in_seconds *
95       static_cast<double>(base::Time::kMillisecondsPerSecond);
96   Heap* heap = isolate()->heap();
97   double start_ms = heap->MonotonicallyIncreasingTimeInMs();
98   job_->NotifyIdleTask();
99   job_->NotifyIdleTaskProgress();
100   if (Step(heap, deadline_in_ms) == kMoreWork) {
101     job_->ScheduleIdleTask(heap);
102   }
103   if (FLAG_trace_idle_notification) {
104     double current_time_ms = heap->MonotonicallyIncreasingTimeInMs();
105     double idle_time_in_ms = deadline_in_ms - start_ms;
106     double deadline_difference = deadline_in_ms - current_time_ms;
107     PrintIsolate(isolate(), "%8.0f ms: ", isolate()->time_millis_since_init());
108     PrintF(
109         "Idle task: requested idle time %.2f ms, used idle time %.2f "
110         "ms, deadline usage %.2f ms\n",
111         idle_time_in_ms, idle_time_in_ms - deadline_difference,
112         deadline_difference);
113   }
114 }
115 
116 
Step(Heap * heap)117 void IncrementalMarkingJob::DelayedTask::Step(Heap* heap) {
118   const int kIncrementalMarkingDelayMs = 50;
119   double deadline =
120       heap->MonotonicallyIncreasingTimeInMs() + kIncrementalMarkingDelayMs;
121   heap->incremental_marking()->AdvanceIncrementalMarking(
122       deadline, i::IncrementalMarking::StepActions(
123                     i::IncrementalMarking::NO_GC_VIA_STACK_GUARD,
124                     i::IncrementalMarking::FORCE_MARKING,
125                     i::IncrementalMarking::FORCE_COMPLETION));
126   heap->FinalizeIncrementalMarkingIfComplete(
127       "Incremental marking task: finalize incremental marking");
128 }
129 
130 
RunInternal()131 void IncrementalMarkingJob::DelayedTask::RunInternal() {
132   Heap* heap = isolate()->heap();
133   job_->NotifyDelayedTask();
134   IncrementalMarking* incremental_marking = heap->incremental_marking();
135   if (!incremental_marking->IsStopped()) {
136     if (job_->ShouldForceMarkingStep()) {
137       Step(heap);
138     }
139     // The Step() above could have finished incremental marking.
140     if (!incremental_marking->IsStopped()) {
141       job_->ScheduleDelayedTask(heap);
142     }
143   }
144 }
145 
146 }  // namespace internal
147 }  // namespace v8
148