Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: src/heap/gc-idle-time-handler.cc

Issue 1105293004: Add mode to reduce memory usage in idle notification. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Add checks in tests Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/heap/gc-idle-time-handler.h ('k') | src/heap/heap.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 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 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/gc-idle-time-handler.h" 5 #include "src/heap/gc-idle-time-handler.h"
6 #include "src/heap/gc-tracer.h" 6 #include "src/heap/gc-tracer.h"
7 #include "src/utils.h" 7 #include "src/utils.h"
8 8
9 namespace v8 { 9 namespace v8 {
10 namespace internal { 10 namespace internal {
11 11
12 const double GCIdleTimeHandler::kConservativeTimeRatio = 0.9; 12 const double GCIdleTimeHandler::kConservativeTimeRatio = 0.9;
13 const size_t GCIdleTimeHandler::kMaxMarkCompactTimeInMs = 1000; 13 const size_t GCIdleTimeHandler::kMaxMarkCompactTimeInMs = 1000;
14 const size_t GCIdleTimeHandler::kMaxFinalIncrementalMarkCompactTimeInMs = 1000; 14 const size_t GCIdleTimeHandler::kMaxFinalIncrementalMarkCompactTimeInMs = 1000;
15 const int GCIdleTimeHandler::kMaxMarkCompactsInIdleRound = 2;
16 const int GCIdleTimeHandler::kIdleScavengeThreshold = 5;
17 const double GCIdleTimeHandler::kHighContextDisposalRate = 100; 15 const double GCIdleTimeHandler::kHighContextDisposalRate = 100;
18 const size_t GCIdleTimeHandler::kMinTimeForOverApproximatingWeakClosureInMs = 1; 16 const size_t GCIdleTimeHandler::kMinTimeForOverApproximatingWeakClosureInMs = 1;
19 17
20 18
21 void GCIdleTimeAction::Print() { 19 void GCIdleTimeAction::Print() {
22 switch (type) { 20 switch (type) {
23 case DONE: 21 case DONE:
24 PrintF("done"); 22 PrintF("done");
25 break; 23 break;
26 case DO_NOTHING: 24 case DO_NOTHING:
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 } 178 }
181 179
182 180
183 bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure( 181 bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure(
184 size_t idle_time_in_ms) { 182 size_t idle_time_in_ms) {
185 // TODO(jochen): Estimate the time it will take to build the object groups. 183 // TODO(jochen): Estimate the time it will take to build the object groups.
186 return idle_time_in_ms >= kMinTimeForOverApproximatingWeakClosureInMs; 184 return idle_time_in_ms >= kMinTimeForOverApproximatingWeakClosureInMs;
187 } 185 }
188 186
189 187
190 GCIdleTimeAction GCIdleTimeHandler::NothingOrDone() { 188 // The idle time handler has three modes and transitions between them
191 if (idle_times_which_made_no_progress_since_last_idle_round_ >= 189 // as shown in the diagram:
192 kMaxNoProgressIdleTimesPerIdleRound) { 190 //
191 // kReduceLatency -----> kReduceMemory -----> kDone
192 // ^ ^ | |
193 // | | | |
194 // | +------------------+ |
195 // | |
196 // +----------------------------------------+
197 //
198 // In kReduceLatency mode the handler only starts incremental marking
199 // if can_start_incremental_marking is false.
200 // In kReduceMemory mode the handler can force a new GC cycle by starting
201 // incremental marking even if can_start_incremental_marking is false. It can
202 // cause at most X idle GCs.
203 // In kDone mode the idle time handler does nothing.
204 //
205 // The initial mode is kReduceLatency.
206 //
207 // kReduceLatency => kReduceMemory transition happens if there were Y
208 // consecutive long idle notifications without any mutator GC. This is our
209 // notion of "mutator is idle".
210 //
211 // kReduceMemory => kDone transition happens after X idle GCs.
212 //
213 // kReduceMemory => kReduceLatency transition happens if N mutator GCs
214 // were performed meaning that the mutator is active.
215 //
216 // kDone => kReduceLatency transition happens if there were M mutator GCs or
217 // context was disposed.
218 //
219 // X = kMaxIdleMarkCompacts
220 // Y = kLongIdleNotificationsBeforeMutatorIsIdle
221 // N = #(idle GCs)
222 // M = kGCsBeforeMutatorIsActive
223 GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms,
224 HeapState heap_state) {
225 Mode next_mode = NextMode(heap_state);
226
227 if (next_mode != mode_) {
228 mode_ = next_mode;
229 ResetCounters();
230 }
231
232 UpdateCounters(idle_time_in_ms);
233
234 if (mode_ == kDone) {
193 return GCIdleTimeAction::Done(); 235 return GCIdleTimeAction::Done();
194 } else { 236 } else {
195 idle_times_which_made_no_progress_since_last_idle_round_++; 237 return Action(idle_time_in_ms, heap_state, mode_ == kReduceMemory);
196 return GCIdleTimeAction::Nothing();
197 } 238 }
198 } 239 }
199 240
200 241
201 // The following logic is implemented by the controller: 242 // The following logic is implemented by the controller:
202 // (1) If we don't have any idle time, do nothing, unless a context was 243 // (1) If we don't have any idle time, do nothing, unless a context was
203 // disposed, incremental marking is stopped, and the heap is small. Then do 244 // disposed, incremental marking is stopped, and the heap is small. Then do
204 // a full GC. 245 // a full GC.
205 // (2) If the new space is almost full and we can afford a Scavenge or if the 246 // (2) If the new space is almost full and we can afford a Scavenge or if the
206 // next Scavenge will very likely take long, then a Scavenge is performed. 247 // next Scavenge will very likely take long, then a Scavenge is performed.
207 // (3) If there is currently no MarkCompact idle round going on, we start a 248 // (3) If incremental marking is done, we perform a full garbage collection
208 // new idle round if enough garbage was created. Otherwise we do not perform
209 // garbage collection to keep system utilization low.
210 // (4) If incremental marking is done, we perform a full garbage collection
211 // if we are allowed to still do full garbage collections during this idle 249 // if we are allowed to still do full garbage collections during this idle
212 // round or if we are not allowed to start incremental marking. Otherwise we 250 // round or if we are not allowed to start incremental marking. Otherwise we
213 // do not perform garbage collection to keep system utilization low. 251 // do not perform garbage collection to keep system utilization low.
214 // (5) If sweeping is in progress and we received a large enough idle time 252 // (4) If sweeping is in progress and we received a large enough idle time
215 // request, we finalize sweeping here. 253 // request, we finalize sweeping here.
216 // (6) If incremental marking is in progress, we perform a marking step. Note, 254 // (5) If incremental marking is in progress, we perform a marking step. Note,
217 // that this currently may trigger a full garbage collection. 255 // that this currently may trigger a full garbage collection.
218 GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms, 256 GCIdleTimeAction GCIdleTimeHandler::Action(double idle_time_in_ms,
219 HeapState heap_state) { 257 const HeapState& heap_state,
258 bool reduce_memory) {
220 if (static_cast<int>(idle_time_in_ms) <= 0) { 259 if (static_cast<int>(idle_time_in_ms) <= 0) {
221 if (heap_state.contexts_disposed > 0) {
222 StartIdleRound();
223 }
224 if (heap_state.incremental_marking_stopped) { 260 if (heap_state.incremental_marking_stopped) {
225 if (ShouldDoContextDisposalMarkCompact( 261 if (ShouldDoContextDisposalMarkCompact(
226 heap_state.contexts_disposed, 262 heap_state.contexts_disposed,
227 heap_state.contexts_disposal_rate)) { 263 heap_state.contexts_disposal_rate)) {
228 return GCIdleTimeAction::FullGC(); 264 return GCIdleTimeAction::FullGC(false);
229 } 265 }
230 } 266 }
231 return GCIdleTimeAction::Nothing(); 267 return GCIdleTimeAction::Nothing();
232 } 268 }
233 269
234 if (ShouldDoScavenge( 270 if (ShouldDoScavenge(
235 static_cast<size_t>(idle_time_in_ms), heap_state.new_space_capacity, 271 static_cast<size_t>(idle_time_in_ms), heap_state.new_space_capacity,
236 heap_state.used_new_space_size, 272 heap_state.used_new_space_size,
237 heap_state.scavenge_speed_in_bytes_per_ms, 273 heap_state.scavenge_speed_in_bytes_per_ms,
238 heap_state.new_space_allocation_throughput_in_bytes_per_ms)) { 274 heap_state.new_space_allocation_throughput_in_bytes_per_ms)) {
239 return GCIdleTimeAction::Scavenge(); 275 return GCIdleTimeAction::Scavenge();
240 } 276 }
241 277
242 if (IsMarkCompactIdleRoundFinished()) { 278 if (heap_state.incremental_marking_stopped && reduce_memory) {
243 if (EnoughGarbageSinceLastIdleRound()) { 279 if (ShouldDoMarkCompact(static_cast<size_t>(idle_time_in_ms),
244 StartIdleRound(); 280 heap_state.size_of_objects,
245 } else { 281 heap_state.mark_compact_speed_in_bytes_per_ms)) {
246 return GCIdleTimeAction::Done(); 282 return GCIdleTimeAction::FullGC(reduce_memory);
247 } 283 }
248 } 284 }
249 285
250 if (heap_state.incremental_marking_stopped) {
251 if (ShouldDoMarkCompact(static_cast<size_t>(idle_time_in_ms),
252 heap_state.size_of_objects,
253 heap_state.mark_compact_speed_in_bytes_per_ms)) {
254 return GCIdleTimeAction::FullGC();
255 }
256 }
257 if (heap_state.sweeping_in_progress) { 286 if (heap_state.sweeping_in_progress) {
258 if (heap_state.sweeping_completed) { 287 if (heap_state.sweeping_completed) {
259 return GCIdleTimeAction::FinalizeSweeping(); 288 return GCIdleTimeAction::FinalizeSweeping();
260 } else { 289 } else {
261 return NothingOrDone(); 290 return GCIdleTimeAction::Nothing();
262 } 291 }
263 } 292 }
293
264 if (heap_state.incremental_marking_stopped && 294 if (heap_state.incremental_marking_stopped &&
265 !heap_state.can_start_incremental_marking) { 295 !heap_state.can_start_incremental_marking && !reduce_memory) {
266 return NothingOrDone(); 296 return GCIdleTimeAction::Nothing();
267 } 297 }
268 298
269 size_t step_size = EstimateMarkingStepSize( 299 size_t step_size = EstimateMarkingStepSize(
270 static_cast<size_t>(kIncrementalMarkingStepTimeInMs), 300 static_cast<size_t>(kIncrementalMarkingStepTimeInMs),
271 heap_state.incremental_marking_speed_in_bytes_per_ms); 301 heap_state.incremental_marking_speed_in_bytes_per_ms);
272 return GCIdleTimeAction::IncrementalMarking(step_size); 302 return GCIdleTimeAction::IncrementalMarking(step_size, reduce_memory);
303 }
304
305
306 void GCIdleTimeHandler::UpdateCounters(double idle_time_in_ms) {
307 if (mode_ == kReduceLatency) {
308 int mutator_gcs = scavenges_ + mark_compacts_ - idle_mark_compacts_;
309 if (mutator_gcs > 0) {
310 // There was a mutator GC since the last notification.
311 long_idle_notifications_ = 0;
312 }
313 idle_mark_compacts_ = 0;
314 mark_compacts_ = 0;
315 scavenges_ = 0;
316 if (idle_time_in_ms >= kMinLongIdleTime) {
317 long_idle_notifications_ +=
318 (idle_time_in_ms >= kLargeLongIdleTime)
319 ? kLongIdleNotificationsBeforeMutatorIsIdle
320 : 1;
321 }
322 }
323 }
324
325
326 void GCIdleTimeHandler::ResetCounters() {
327 long_idle_notifications_ = 0;
328 idle_mark_compacts_ = 0;
329 mark_compacts_ = 0;
330 scavenges_ = 0;
331 }
332
333
334 bool GCIdleTimeHandler::IsMutatorActive(int contexts_disposed, int gcs) {
335 return contexts_disposed > 0 || gcs >= kGCsBeforeMutatorIsActive;
336 }
337
338
339 bool GCIdleTimeHandler::IsMutatorIdle(int long_idle_notifications, int gcs) {
340 return gcs == 0 &&
341 long_idle_notifications >= kLongIdleNotificationsBeforeMutatorIsIdle;
342 }
343
344
345 GCIdleTimeHandler::Mode GCIdleTimeHandler::NextMode(
346 const HeapState& heap_state) {
347 DCHECK(mark_compacts_ >= idle_mark_compacts_);
348 int mutator_gcs = scavenges_ + mark_compacts_ - idle_mark_compacts_;
349 switch (mode_) {
350 case kDone:
351 DCHECK(idle_mark_compacts_ == 0);
352 if (IsMutatorActive(heap_state.contexts_disposed, mutator_gcs)) {
353 return kReduceLatency;
354 }
355 break;
356 case kReduceLatency:
357 if (IsMutatorIdle(long_idle_notifications_, mutator_gcs)) {
358 return kReduceMemory;
359 }
360 break;
361 case kReduceMemory:
362 if (idle_mark_compacts_ >= kMaxIdleMarkCompacts) {
363 return kDone;
364 }
365 if (mutator_gcs > idle_mark_compacts_) {
366 return kReduceLatency;
367 }
368 break;
369 }
370 return mode_;
273 } 371 }
274 } 372 }
275 } 373 }
OLDNEW
« no previous file with comments | « src/heap/gc-idle-time-handler.h ('k') | src/heap/heap.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698