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
Start(Heap * heap)18 void IncrementalMarkingJob::Start(Heap* heap) {
19 DCHECK(!heap->incremental_marking()->IsStopped());
20 // We don't need to reset the flags because tasks from the previous job
21 // can still be pending. We just want to ensure that tasks are posted
22 // if they are not pending.
23 // If delayed task is pending and made_progress_since_last_delayed_task_ is
24 // true, then the delayed task will clear that flag when it is rescheduled.
25 ScheduleIdleTask(heap);
26 ScheduleDelayedTask(heap);
27 }
28
29
NotifyIdleTask()30 void IncrementalMarkingJob::NotifyIdleTask() { idle_task_pending_ = false; }
31
32
NotifyDelayedTask()33 void IncrementalMarkingJob::NotifyDelayedTask() {
34 delayed_task_pending_ = false;
35 }
36
37
NotifyIdleTaskProgress()38 void IncrementalMarkingJob::NotifyIdleTaskProgress() {
39 made_progress_since_last_delayed_task_ = true;
40 }
41
42
ScheduleIdleTask(Heap * heap)43 void IncrementalMarkingJob::ScheduleIdleTask(Heap* heap) {
44 if (!idle_task_pending_) {
45 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate());
46 if (V8::GetCurrentPlatform()->IdleTasksEnabled(isolate)) {
47 idle_task_pending_ = true;
48 auto task = new IdleTask(heap->isolate(), this);
49 V8::GetCurrentPlatform()->CallIdleOnForegroundThread(isolate, task);
50 }
51 }
52 }
53
54
ScheduleDelayedTask(Heap * heap)55 void IncrementalMarkingJob::ScheduleDelayedTask(Heap* heap) {
56 if (!delayed_task_pending_ && FLAG_memory_reducer) {
57 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate());
58 delayed_task_pending_ = true;
59 made_progress_since_last_delayed_task_ = false;
60 auto task = new DelayedTask(heap->isolate(), this);
61 V8::GetCurrentPlatform()->CallDelayedOnForegroundThread(isolate, task,
62 kDelayInSeconds);
63 }
64 }
65
66
Step(Heap * heap,double deadline_in_ms)67 IncrementalMarkingJob::IdleTask::Progress IncrementalMarkingJob::IdleTask::Step(
68 Heap* heap, double deadline_in_ms) {
69 IncrementalMarking* incremental_marking = heap->incremental_marking();
70 MarkCompactCollector* mark_compact_collector = heap->mark_compact_collector();
71 if (incremental_marking->IsStopped()) {
72 return kDone;
73 }
74 if (mark_compact_collector->sweeping_in_progress()) {
75 if (mark_compact_collector->IsSweepingCompleted()) {
76 mark_compact_collector->EnsureSweepingCompleted();
77 }
78 return kMoreWork;
79 }
80 const double remaining_idle_time_in_ms =
81 incremental_marking->AdvanceIncrementalMarking(
82 0, deadline_in_ms, IncrementalMarking::IdleStepActions());
83 if (remaining_idle_time_in_ms > 0.0) {
84 heap->TryFinalizeIdleIncrementalMarking(remaining_idle_time_in_ms);
85 }
86 return incremental_marking->IsStopped() ? kDone : kMoreWork;
87 }
88
89
RunInternal(double deadline_in_seconds)90 void IncrementalMarkingJob::IdleTask::RunInternal(double deadline_in_seconds) {
91 double deadline_in_ms =
92 deadline_in_seconds *
93 static_cast<double>(base::Time::kMillisecondsPerSecond);
94 Heap* heap = isolate()->heap();
95 double start_ms = heap->MonotonicallyIncreasingTimeInMs();
96 job_->NotifyIdleTask();
97 job_->NotifyIdleTaskProgress();
98 if (Step(heap, deadline_in_ms) == kMoreWork) {
99 job_->ScheduleIdleTask(heap);
100 }
101 if (FLAG_trace_idle_notification) {
102 double current_time_ms = heap->MonotonicallyIncreasingTimeInMs();
103 double idle_time_in_ms = deadline_in_ms - start_ms;
104 double deadline_difference = deadline_in_ms - current_time_ms;
105 PrintIsolate(isolate(), "%8.0f ms: ", isolate()->time_millis_since_init());
106 PrintF(
107 "Idle task: requested idle time %.2f ms, used idle time %.2f "
108 "ms, deadline usage %.2f ms\n",
109 idle_time_in_ms, idle_time_in_ms - deadline_difference,
110 deadline_difference);
111 }
112 }
113
114
Step(Heap * heap)115 void IncrementalMarkingJob::DelayedTask::Step(Heap* heap) {
116 const int kIncrementalMarkingDelayMs = 50;
117 double deadline =
118 heap->MonotonicallyIncreasingTimeInMs() + kIncrementalMarkingDelayMs;
119 heap->incremental_marking()->AdvanceIncrementalMarking(
120 0, deadline, i::IncrementalMarking::StepActions(
121 i::IncrementalMarking::NO_GC_VIA_STACK_GUARD,
122 i::IncrementalMarking::FORCE_MARKING,
123 i::IncrementalMarking::FORCE_COMPLETION));
124 heap->FinalizeIncrementalMarkingIfComplete(
125 "Incremental marking task: finalize incremental marking");
126 }
127
128
RunInternal()129 void IncrementalMarkingJob::DelayedTask::RunInternal() {
130 Heap* heap = isolate()->heap();
131 job_->NotifyDelayedTask();
132 IncrementalMarking* incremental_marking = heap->incremental_marking();
133 if (!incremental_marking->IsStopped()) {
134 if (job_->ShouldForceMarkingStep()) {
135 Step(heap);
136 }
137 // The Step() above could have finished incremental marking.
138 if (!incremental_marking->IsStopped()) {
139 job_->ScheduleDelayedTask(heap);
140 }
141 }
142 }
143
144 } // namespace internal
145 } // namespace v8
146