1 // Copyright 2015 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/scavenge-job.h" 6 7 #include "src/base/platform/time.h" 8 #include "src/heap/gc-tracer.h" 9 #include "src/heap/heap-inl.h" 10 #include "src/heap/heap.h" 11 #include "src/isolate.h" 12 #include "src/v8.h" 13 #include "src/vm-state-inl.h" 14 15 namespace v8 { 16 namespace internal { 17 18 19 const double ScavengeJob::kMaxAllocationLimitAsFractionOfNewSpace = 0.8; 20 21 void ScavengeJob::IdleTask::RunInternal(double deadline_in_seconds) { 22 VMState<GC> state(isolate()); 23 TRACE_EVENT_CALL_STATS_SCOPED(isolate(), "v8", "V8.Task"); 24 Heap* heap = isolate()->heap(); 25 double deadline_in_ms = 26 deadline_in_seconds * 27 static_cast<double>(base::Time::kMillisecondsPerSecond); 28 double start_ms = heap->MonotonicallyIncreasingTimeInMs(); 29 double idle_time_in_ms = deadline_in_ms - start_ms; 30 double scavenge_speed_in_bytes_per_ms = 31 heap->tracer()->ScavengeSpeedInBytesPerMillisecond(); 32 size_t new_space_size = heap->new_space()->Size(); 33 size_t new_space_capacity = heap->new_space()->Capacity(); 34 35 job_->NotifyIdleTask(); 36 37 if (ReachedIdleAllocationLimit(scavenge_speed_in_bytes_per_ms, new_space_size, 38 new_space_capacity)) { 39 if (EnoughIdleTimeForScavenge( 40 idle_time_in_ms, scavenge_speed_in_bytes_per_ms, new_space_size)) { 41 heap->CollectGarbage(NEW_SPACE, GarbageCollectionReason::kIdleTask); 42 } else { 43 // Immediately request another idle task that can get larger idle time. 44 job_->RescheduleIdleTask(heap); 45 } 46 } 47 } 48 49 bool ScavengeJob::ReachedIdleAllocationLimit( 50 double scavenge_speed_in_bytes_per_ms, size_t new_space_size, 51 size_t new_space_capacity) { 52 if (scavenge_speed_in_bytes_per_ms == 0) { 53 scavenge_speed_in_bytes_per_ms = kInitialScavengeSpeedInBytesPerMs; 54 } 55 56 // Set the allocation limit to the number of bytes we can scavenge in an 57 // average idle task. 58 double allocation_limit = kAverageIdleTimeMs * scavenge_speed_in_bytes_per_ms; 59 60 // Keep the limit smaller than the new space capacity. 61 allocation_limit = 62 Min<double>(allocation_limit, 63 new_space_capacity * kMaxAllocationLimitAsFractionOfNewSpace); 64 // Adjust the limit to take into account bytes that will be allocated until 65 // the next check and keep the limit large enough to avoid scavenges in tiny 66 // new space. 67 allocation_limit = 68 Max<double>(allocation_limit - kBytesAllocatedBeforeNextIdleTask, 69 kMinAllocationLimit); 70 71 return allocation_limit <= new_space_size; 72 } 73 74 bool ScavengeJob::EnoughIdleTimeForScavenge( 75 double idle_time_in_ms, double scavenge_speed_in_bytes_per_ms, 76 size_t new_space_size) { 77 if (scavenge_speed_in_bytes_per_ms == 0) { 78 scavenge_speed_in_bytes_per_ms = kInitialScavengeSpeedInBytesPerMs; 79 } 80 return new_space_size <= idle_time_in_ms * scavenge_speed_in_bytes_per_ms; 81 } 82 83 84 void ScavengeJob::RescheduleIdleTask(Heap* heap) { 85 // Make sure that we don't reschedule more than one time. 86 // Otherwise, we might spam the scheduler with idle tasks. 87 if (!idle_task_rescheduled_) { 88 ScheduleIdleTask(heap); 89 idle_task_rescheduled_ = true; 90 } 91 } 92 93 94 void ScavengeJob::ScheduleIdleTaskIfNeeded(Heap* heap, int bytes_allocated) { 95 bytes_allocated_since_the_last_task_ += bytes_allocated; 96 if (bytes_allocated_since_the_last_task_ >= 97 static_cast<int>(kBytesAllocatedBeforeNextIdleTask)) { 98 ScheduleIdleTask(heap); 99 bytes_allocated_since_the_last_task_ = 0; 100 idle_task_rescheduled_ = false; 101 } 102 } 103 104 105 void ScavengeJob::ScheduleIdleTask(Heap* heap) { 106 if (!idle_task_pending_ && !heap->IsTearingDown()) { 107 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate()); 108 if (V8::GetCurrentPlatform()->IdleTasksEnabled(isolate)) { 109 idle_task_pending_ = true; 110 auto task = new IdleTask(heap->isolate(), this); 111 V8::GetCurrentPlatform()->CallIdleOnForegroundThread(isolate, task); 112 } 113 } 114 } 115 } // namespace internal 116 } // namespace v8 117