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 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 32 void IncrementalMarkingJob::NotifyIdleTask() { idle_task_pending_ = false; } 33 34 35 void IncrementalMarkingJob::NotifyDelayedTask() { 36 delayed_task_pending_ = false; 37 } 38 39 40 void IncrementalMarkingJob::NotifyIdleTaskProgress() { 41 made_progress_since_last_delayed_task_ = true; 42 } 43 44 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 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 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 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 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 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