| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/heap/memory-reducer.h" | 5 #include "src/heap/memory-reducer.h" |
| 6 | 6 |
| 7 #include "src/flags.h" | 7 #include "src/flags.h" |
| 8 #include "src/heap/heap.h" | 8 #include "src/heap/heap.h" |
| 9 #include "src/utils.h" | 9 #include "src/utils.h" |
| 10 #include "src/v8.h" | 10 #include "src/v8.h" |
| 11 | 11 |
| 12 namespace v8 { | 12 namespace v8 { |
| 13 namespace internal { | 13 namespace internal { |
| 14 | 14 |
| 15 const int MemoryReducer::kLongDelayMs = 5000; | 15 const int MemoryReducer::kLongDelayMs = 5000; |
| 16 const int MemoryReducer::kShortDelayMs = 500; | 16 const int MemoryReducer::kShortDelayMs = 500; |
| 17 const int MemoryReducer::kWatchdogDelayMs = 100000; |
| 17 const int MemoryReducer::kMaxNumberOfGCs = 3; | 18 const int MemoryReducer::kMaxNumberOfGCs = 3; |
| 18 | 19 |
| 19 MemoryReducer::TimerTask::TimerTask(MemoryReducer* memory_reducer) | 20 MemoryReducer::TimerTask::TimerTask(MemoryReducer* memory_reducer) |
| 20 : CancelableTask(memory_reducer->heap()->isolate()), | 21 : CancelableTask(memory_reducer->heap()->isolate()), |
| 21 memory_reducer_(memory_reducer) {} | 22 memory_reducer_(memory_reducer) {} |
| 22 | 23 |
| 23 | 24 |
| 24 void MemoryReducer::TimerTask::RunInternal() { | 25 void MemoryReducer::TimerTask::RunInternal() { |
| 25 Heap* heap = memory_reducer_->heap(); | 26 Heap* heap = memory_reducer_->heap(); |
| 26 Event event; | 27 Event event; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 if (FLAG_trace_gc_verbose) { | 100 if (FLAG_trace_gc_verbose) { |
| 100 PrintIsolate(heap()->isolate(), | 101 PrintIsolate(heap()->isolate(), |
| 101 "Memory reducer: started GC #%d" | 102 "Memory reducer: started GC #%d" |
| 102 " (background idle)\n", | 103 " (background idle)\n", |
| 103 state_.started_gcs); | 104 state_.started_gcs); |
| 104 } | 105 } |
| 105 } | 106 } |
| 106 } | 107 } |
| 107 | 108 |
| 108 | 109 |
| 110 bool MemoryReducer::WatchdogGC(const State& state, const Event& event) { |
| 111 return state.last_gc_time_ms != 0 && |
| 112 event.time_ms > state.last_gc_time_ms + kWatchdogDelayMs; |
| 113 } |
| 114 |
| 115 |
| 109 // For specification of this function see the comment for MemoryReducer class. | 116 // For specification of this function see the comment for MemoryReducer class. |
| 110 MemoryReducer::State MemoryReducer::Step(const State& state, | 117 MemoryReducer::State MemoryReducer::Step(const State& state, |
| 111 const Event& event) { | 118 const Event& event) { |
| 112 if (!FLAG_incremental_marking) { | 119 if (!FLAG_incremental_marking) { |
| 113 return State(kDone, 0, 0); | 120 return State(kDone, 0, 0, state.last_gc_time_ms); |
| 114 } | 121 } |
| 115 switch (state.action) { | 122 switch (state.action) { |
| 116 case kDone: | 123 case kDone: |
| 117 if (event.type == kTimer || event.type == kBackgroundIdleNotification) { | 124 if (event.type == kTimer || event.type == kBackgroundIdleNotification) { |
| 118 return state; | 125 return state; |
| 119 } else { | 126 } else { |
| 120 DCHECK(event.type == kContextDisposed || event.type == kMarkCompact); | 127 DCHECK(event.type == kContextDisposed || event.type == kMarkCompact); |
| 121 return State(kWait, 0, event.time_ms + kLongDelayMs); | 128 return State( |
| 129 kWait, 0, event.time_ms + kLongDelayMs, |
| 130 event.type == kMarkCompact ? event.time_ms : state.last_gc_time_ms); |
| 122 } | 131 } |
| 123 case kWait: | 132 case kWait: |
| 124 switch (event.type) { | 133 switch (event.type) { |
| 125 case kContextDisposed: | 134 case kContextDisposed: |
| 126 return state; | 135 return state; |
| 127 case kTimer: | 136 case kTimer: |
| 128 if (state.started_gcs >= kMaxNumberOfGCs) { | 137 if (state.started_gcs >= kMaxNumberOfGCs) { |
| 129 return State(kDone, 0, 0.0); | 138 return State(kDone, 0, 0.0, state.last_gc_time_ms); |
| 130 } else if (event.can_start_incremental_gc && | 139 } else if (event.can_start_incremental_gc && |
| 131 event.low_allocation_rate) { | 140 (event.low_allocation_rate || WatchdogGC(state, event))) { |
| 132 if (state.next_gc_start_ms <= event.time_ms) { | 141 if (state.next_gc_start_ms <= event.time_ms) { |
| 133 return State(kRun, state.started_gcs + 1, 0.0); | 142 return State(kRun, state.started_gcs + 1, 0.0, |
| 143 state.last_gc_time_ms); |
| 134 } else { | 144 } else { |
| 135 return state; | 145 return state; |
| 136 } | 146 } |
| 137 } else { | 147 } else { |
| 138 return State(kWait, state.started_gcs, | 148 return State(kWait, state.started_gcs, event.time_ms + kLongDelayMs, |
| 139 event.time_ms + kLongDelayMs); | 149 state.last_gc_time_ms); |
| 140 } | 150 } |
| 141 case kBackgroundIdleNotification: | 151 case kBackgroundIdleNotification: |
| 142 if (event.can_start_incremental_gc && | 152 if (event.can_start_incremental_gc && |
| 143 state.started_gcs < kMaxNumberOfGCs) { | 153 state.started_gcs < kMaxNumberOfGCs) { |
| 144 return State(kWait, state.started_gcs + 1, | 154 return State(kWait, state.started_gcs + 1, |
| 145 event.time_ms + kLongDelayMs); | 155 event.time_ms + kLongDelayMs, state.last_gc_time_ms); |
| 146 } else { | 156 } else { |
| 147 return state; | 157 return state; |
| 148 } | 158 } |
| 149 case kMarkCompact: | 159 case kMarkCompact: |
| 150 return State(kWait, state.started_gcs, event.time_ms + kLongDelayMs); | 160 return State(kWait, state.started_gcs, event.time_ms + kLongDelayMs, |
| 161 event.time_ms); |
| 151 } | 162 } |
| 152 case kRun: | 163 case kRun: |
| 153 if (event.type != kMarkCompact) { | 164 if (event.type != kMarkCompact) { |
| 154 return state; | 165 return state; |
| 155 } else { | 166 } else { |
| 156 if (state.started_gcs < kMaxNumberOfGCs && | 167 if (state.started_gcs < kMaxNumberOfGCs && |
| 157 (event.next_gc_likely_to_collect_more || state.started_gcs == 1)) { | 168 (event.next_gc_likely_to_collect_more || state.started_gcs == 1)) { |
| 158 return State(kWait, state.started_gcs, event.time_ms + kShortDelayMs); | 169 return State(kWait, state.started_gcs, event.time_ms + kShortDelayMs, |
| 170 event.time_ms); |
| 159 } else { | 171 } else { |
| 160 return State(kDone, 0, 0.0); | 172 return State(kDone, 0, 0.0, event.time_ms); |
| 161 } | 173 } |
| 162 } | 174 } |
| 163 } | 175 } |
| 164 UNREACHABLE(); | 176 UNREACHABLE(); |
| 165 return State(kDone, 0, 0); // Make the compiler happy. | 177 return State(kDone, 0, 0, 0.0); // Make the compiler happy. |
| 166 } | 178 } |
| 167 | 179 |
| 168 | 180 |
| 169 void MemoryReducer::ScheduleTimer(double delay_ms) { | 181 void MemoryReducer::ScheduleTimer(double delay_ms) { |
| 170 DCHECK(delay_ms > 0); | 182 DCHECK(delay_ms > 0); |
| 171 // Leave some room for precision error in task scheduler. | 183 // Leave some room for precision error in task scheduler. |
| 172 const double kSlackMs = 100; | 184 const double kSlackMs = 100; |
| 173 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap()->isolate()); | 185 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap()->isolate()); |
| 174 auto timer_task = new MemoryReducer::TimerTask(this); | 186 auto timer_task = new MemoryReducer::TimerTask(this); |
| 175 V8::GetCurrentPlatform()->CallDelayedOnForegroundThread( | 187 V8::GetCurrentPlatform()->CallDelayedOnForegroundThread( |
| 176 isolate, timer_task, (delay_ms + kSlackMs) / 1000.0); | 188 isolate, timer_task, (delay_ms + kSlackMs) / 1000.0); |
| 177 } | 189 } |
| 178 | 190 |
| 179 | 191 |
| 180 void MemoryReducer::TearDown() { | 192 void MemoryReducer::TearDown() { state_ = State(kDone, 0, 0, 0.0); } |
| 181 state_ = State(kDone, 0, 0); | |
| 182 } | |
| 183 | 193 |
| 184 } // internal | 194 } // internal |
| 185 } // v8 | 195 } // v8 |
| OLD | NEW |