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