1 // Copyright 2014 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/gc-idle-time-handler.h" 6 7 #include "src/flags.h" 8 #include "src/heap/gc-tracer.h" 9 #include "src/utils.h" 10 11 namespace v8 { 12 namespace internal { 13 14 const double GCIdleTimeHandler::kConservativeTimeRatio = 0.9; 15 const size_t GCIdleTimeHandler::kMaxFinalIncrementalMarkCompactTimeInMs = 1000; 16 const double GCIdleTimeHandler::kHighContextDisposalRate = 100; 17 const size_t GCIdleTimeHandler::kMinTimeForOverApproximatingWeakClosureInMs = 1; 18 19 20 void GCIdleTimeAction::Print() { 21 switch (type) { 22 case DONE: 23 PrintF("done"); 24 break; 25 case DO_NOTHING: 26 PrintF("no action"); 27 break; 28 case DO_INCREMENTAL_STEP: 29 PrintF("incremental step"); 30 if (additional_work) { 31 PrintF("; finalized marking"); 32 } 33 break; 34 case DO_FULL_GC: 35 PrintF("full GC"); 36 break; 37 } 38 } 39 40 41 void GCIdleTimeHeapState::Print() { 42 PrintF("contexts_disposed=%d ", contexts_disposed); 43 PrintF("contexts_disposal_rate=%f ", contexts_disposal_rate); 44 PrintF("size_of_objects=%" PRIuS " ", size_of_objects); 45 PrintF("incremental_marking_stopped=%d ", incremental_marking_stopped); 46 } 47 48 size_t GCIdleTimeHandler::EstimateMarkingStepSize( 49 double idle_time_in_ms, double marking_speed_in_bytes_per_ms) { 50 DCHECK(idle_time_in_ms > 0); 51 52 if (marking_speed_in_bytes_per_ms == 0) { 53 marking_speed_in_bytes_per_ms = kInitialConservativeMarkingSpeed; 54 } 55 56 double marking_step_size = marking_speed_in_bytes_per_ms * idle_time_in_ms; 57 if (marking_step_size >= kMaximumMarkingStepSize) { 58 return kMaximumMarkingStepSize; 59 } 60 return static_cast<size_t>(marking_step_size * kConservativeTimeRatio); 61 } 62 63 double GCIdleTimeHandler::EstimateFinalIncrementalMarkCompactTime( 64 size_t size_of_objects, 65 double final_incremental_mark_compact_speed_in_bytes_per_ms) { 66 if (final_incremental_mark_compact_speed_in_bytes_per_ms == 0) { 67 final_incremental_mark_compact_speed_in_bytes_per_ms = 68 kInitialConservativeFinalIncrementalMarkCompactSpeed; 69 } 70 double result = 71 size_of_objects / final_incremental_mark_compact_speed_in_bytes_per_ms; 72 return Min<double>(result, kMaxFinalIncrementalMarkCompactTimeInMs); 73 } 74 75 bool GCIdleTimeHandler::ShouldDoContextDisposalMarkCompact( 76 int contexts_disposed, double contexts_disposal_rate) { 77 return contexts_disposed > 0 && contexts_disposal_rate > 0 && 78 contexts_disposal_rate < kHighContextDisposalRate; 79 } 80 81 bool GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact( 82 double idle_time_in_ms, size_t size_of_objects, 83 double final_incremental_mark_compact_speed_in_bytes_per_ms) { 84 return idle_time_in_ms >= 85 EstimateFinalIncrementalMarkCompactTime( 86 size_of_objects, 87 final_incremental_mark_compact_speed_in_bytes_per_ms); 88 } 89 90 bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure( 91 double idle_time_in_ms) { 92 // TODO(jochen): Estimate the time it will take to build the object groups. 93 return idle_time_in_ms >= kMinTimeForOverApproximatingWeakClosureInMs; 94 } 95 96 97 GCIdleTimeAction GCIdleTimeHandler::NothingOrDone(double idle_time_in_ms) { 98 if (idle_time_in_ms >= kMinBackgroundIdleTime) { 99 return GCIdleTimeAction::Nothing(); 100 } 101 if (idle_times_which_made_no_progress_ >= kMaxNoProgressIdleTimes) { 102 return GCIdleTimeAction::Done(); 103 } else { 104 idle_times_which_made_no_progress_++; 105 return GCIdleTimeAction::Nothing(); 106 } 107 } 108 109 110 // The following logic is implemented by the controller: 111 // (1) If we don't have any idle time, do nothing, unless a context was 112 // disposed, incremental marking is stopped, and the heap is small. Then do 113 // a full GC. 114 // (2) If the context disposal rate is high and we cannot perform a full GC, 115 // we do nothing until the context disposal rate becomes lower. 116 // (3) If the new space is almost full and we can affort a scavenge or if the 117 // next scavenge will very likely take long, then a scavenge is performed. 118 // (4) If sweeping is in progress and we received a large enough idle time 119 // request, we finalize sweeping here. 120 // (5) If incremental marking is in progress, we perform a marking step. Note, 121 // that this currently may trigger a full garbage collection. 122 GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms, 123 GCIdleTimeHeapState heap_state) { 124 if (static_cast<int>(idle_time_in_ms) <= 0) { 125 if (heap_state.incremental_marking_stopped) { 126 if (ShouldDoContextDisposalMarkCompact( 127 heap_state.contexts_disposed, 128 heap_state.contexts_disposal_rate)) { 129 return GCIdleTimeAction::FullGC(); 130 } 131 } 132 return GCIdleTimeAction::Nothing(); 133 } 134 135 // We are in a context disposal GC scenario. Don't do anything if we do not 136 // get the right idle signal. 137 if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed, 138 heap_state.contexts_disposal_rate)) { 139 return NothingOrDone(idle_time_in_ms); 140 } 141 142 if (!FLAG_incremental_marking || heap_state.incremental_marking_stopped) { 143 return GCIdleTimeAction::Done(); 144 } 145 146 return GCIdleTimeAction::IncrementalStep(); 147 } 148 149 150 } // namespace internal 151 } // namespace v8 152