OLD | NEW |
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 { |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 } | 185 } |
186 | 186 |
187 | 187 |
188 bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure( | 188 bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure( |
189 size_t idle_time_in_ms) { | 189 size_t idle_time_in_ms) { |
190 // TODO(jochen): Estimate the time it will take to build the object groups. | 190 // TODO(jochen): Estimate the time it will take to build the object groups. |
191 return idle_time_in_ms >= kMinTimeForOverApproximatingWeakClosureInMs; | 191 return idle_time_in_ms >= kMinTimeForOverApproximatingWeakClosureInMs; |
192 } | 192 } |
193 | 193 |
194 | 194 |
| 195 GCIdleTimeAction GCIdleTimeHandler::NothingOrDone() { |
| 196 if (idle_times_which_made_no_progress_per_mode_ >= |
| 197 kMaxNoProgressIdleTimesPerMode) { |
| 198 return GCIdleTimeAction::Done(); |
| 199 } else { |
| 200 idle_times_which_made_no_progress_per_mode_++; |
| 201 return GCIdleTimeAction::Nothing(); |
| 202 } |
| 203 } |
| 204 |
| 205 |
195 // The idle time handler has three modes and transitions between them | 206 // The idle time handler has three modes and transitions between them |
196 // as shown in the diagram: | 207 // as shown in the diagram: |
197 // | 208 // |
198 // kReduceLatency -----> kReduceMemory -----> kDone | 209 // kReduceLatency -----> kReduceMemory -----> kDone |
199 // ^ ^ | | | 210 // ^ ^ | | |
200 // | | | | | 211 // | | | | |
201 // | +------------------+ | | 212 // | +------------------+ | |
202 // | | | 213 // | | |
203 // +----------------------------------------+ | 214 // +----------------------------------------+ |
204 // | 215 // |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 return GCIdleTimeAction::FullGC(false); | 287 return GCIdleTimeAction::FullGC(false); |
277 } | 288 } |
278 } | 289 } |
279 return GCIdleTimeAction::Nothing(); | 290 return GCIdleTimeAction::Nothing(); |
280 } | 291 } |
281 | 292 |
282 // We are in a context disposal GC scenario. Don't do anything if we do not | 293 // We are in a context disposal GC scenario. Don't do anything if we do not |
283 // get the right idle signal. | 294 // get the right idle signal. |
284 if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed, | 295 if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed, |
285 heap_state.contexts_disposal_rate)) { | 296 heap_state.contexts_disposal_rate)) { |
286 return GCIdleTimeAction::Nothing(); | 297 return NothingOrDone(); |
287 } | 298 } |
288 | 299 |
289 if (ShouldDoScavenge( | 300 if (ShouldDoScavenge( |
290 static_cast<size_t>(idle_time_in_ms), heap_state.new_space_capacity, | 301 static_cast<size_t>(idle_time_in_ms), heap_state.new_space_capacity, |
291 heap_state.used_new_space_size, | 302 heap_state.used_new_space_size, |
292 heap_state.scavenge_speed_in_bytes_per_ms, | 303 heap_state.scavenge_speed_in_bytes_per_ms, |
293 heap_state.new_space_allocation_throughput_in_bytes_per_ms)) { | 304 heap_state.new_space_allocation_throughput_in_bytes_per_ms)) { |
294 return GCIdleTimeAction::Scavenge(); | 305 return GCIdleTimeAction::Scavenge(); |
295 } | 306 } |
296 | 307 |
297 if (heap_state.incremental_marking_stopped && reduce_memory) { | 308 if (heap_state.incremental_marking_stopped && reduce_memory) { |
298 if (ShouldDoMarkCompact(static_cast<size_t>(idle_time_in_ms), | 309 if (ShouldDoMarkCompact(static_cast<size_t>(idle_time_in_ms), |
299 heap_state.size_of_objects, | 310 heap_state.size_of_objects, |
300 heap_state.mark_compact_speed_in_bytes_per_ms)) { | 311 heap_state.mark_compact_speed_in_bytes_per_ms)) { |
301 return GCIdleTimeAction::FullGC(reduce_memory); | 312 return GCIdleTimeAction::FullGC(reduce_memory); |
302 } | 313 } |
303 } | 314 } |
304 | 315 |
305 if (heap_state.sweeping_in_progress) { | 316 if (heap_state.sweeping_in_progress) { |
306 if (heap_state.sweeping_completed) { | 317 if (heap_state.sweeping_completed) { |
307 return GCIdleTimeAction::FinalizeSweeping(); | 318 return GCIdleTimeAction::FinalizeSweeping(); |
308 } else { | 319 } else { |
309 return GCIdleTimeAction::Nothing(); | 320 return NothingOrDone(); |
310 } | 321 } |
311 } | 322 } |
312 | 323 |
313 if (heap_state.incremental_marking_stopped && | 324 if (heap_state.incremental_marking_stopped && |
314 !heap_state.can_start_incremental_marking && !reduce_memory) { | 325 !heap_state.can_start_incremental_marking && !reduce_memory) { |
315 return GCIdleTimeAction::Nothing(); | 326 return NothingOrDone(); |
316 } | 327 } |
317 | 328 |
318 size_t step_size = EstimateMarkingStepSize( | 329 size_t step_size = EstimateMarkingStepSize( |
319 static_cast<size_t>(kIncrementalMarkingStepTimeInMs), | 330 static_cast<size_t>(kIncrementalMarkingStepTimeInMs), |
320 heap_state.incremental_marking_speed_in_bytes_per_ms); | 331 heap_state.incremental_marking_speed_in_bytes_per_ms); |
321 return GCIdleTimeAction::IncrementalMarking(step_size, reduce_memory); | 332 return GCIdleTimeAction::IncrementalMarking(step_size, reduce_memory); |
322 } | 333 } |
323 | 334 |
324 | 335 |
325 void GCIdleTimeHandler::UpdateCounters(double idle_time_in_ms) { | 336 void GCIdleTimeHandler::UpdateCounters(double idle_time_in_ms) { |
326 if (mode_ == kReduceLatency) { | 337 if (mode_ == kReduceLatency) { |
327 int mutator_gcs = scavenges_ + mark_compacts_ - idle_mark_compacts_; | 338 int gcs = scavenges_ + mark_compacts_; |
328 if (mutator_gcs > 0) { | 339 if (gcs > 0) { |
329 // There was a mutator GC since the last notification. | 340 // There was a GC since the last notification. |
330 long_idle_notifications_ = 0; | 341 long_idle_notifications_ = 0; |
| 342 background_idle_notifications_ = 0; |
331 } | 343 } |
332 idle_mark_compacts_ = 0; | 344 idle_mark_compacts_ = 0; |
333 mark_compacts_ = 0; | 345 mark_compacts_ = 0; |
334 scavenges_ = 0; | 346 scavenges_ = 0; |
335 if (idle_time_in_ms >= kMinLongIdleTime) { | 347 if (idle_time_in_ms >= kMinBackgroundIdleTime) { |
336 long_idle_notifications_ += | 348 background_idle_notifications_++; |
337 (idle_time_in_ms >= kLargeLongIdleTime) | 349 } else if (idle_time_in_ms >= kMinLongIdleTime) { |
338 ? kLongIdleNotificationsBeforeMutatorIsIdle | 350 long_idle_notifications_++; |
339 : 1; | |
340 } | 351 } |
341 } | 352 } |
342 } | 353 } |
343 | 354 |
344 | 355 |
345 void GCIdleTimeHandler::ResetCounters() { | 356 void GCIdleTimeHandler::ResetCounters() { |
346 long_idle_notifications_ = 0; | 357 long_idle_notifications_ = 0; |
| 358 background_idle_notifications_ = 0; |
347 idle_mark_compacts_ = 0; | 359 idle_mark_compacts_ = 0; |
348 mark_compacts_ = 0; | 360 mark_compacts_ = 0; |
349 scavenges_ = 0; | 361 scavenges_ = 0; |
| 362 idle_times_which_made_no_progress_per_mode_ = 0; |
350 } | 363 } |
351 | 364 |
352 | 365 |
353 bool GCIdleTimeHandler::IsMutatorActive(int contexts_disposed, int gcs) { | 366 bool GCIdleTimeHandler::IsMutatorActive(int contexts_disposed, |
354 return contexts_disposed > 0 || gcs >= kGCsBeforeMutatorIsActive; | 367 int mark_compacts) { |
| 368 return contexts_disposed > 0 || |
| 369 mark_compacts >= kMarkCompactsBeforeMutatorIsActive; |
355 } | 370 } |
356 | 371 |
357 | 372 |
358 bool GCIdleTimeHandler::IsMutatorIdle(int long_idle_notifications, int gcs) { | 373 bool GCIdleTimeHandler::IsMutatorIdle(int long_idle_notifications, |
359 return gcs == 0 && | 374 int background_idle_notifications, |
360 long_idle_notifications >= kLongIdleNotificationsBeforeMutatorIsIdle; | 375 int mutator_gcs) { |
| 376 return mutator_gcs == 0 && |
| 377 (long_idle_notifications >= |
| 378 kLongIdleNotificationsBeforeMutatorIsIdle || |
| 379 background_idle_notifications >= |
| 380 kBackgroundIdleNotificationsBeforeMutatorIsIdle); |
361 } | 381 } |
362 | 382 |
363 | 383 |
364 GCIdleTimeHandler::Mode GCIdleTimeHandler::NextMode( | 384 GCIdleTimeHandler::Mode GCIdleTimeHandler::NextMode( |
365 const HeapState& heap_state) { | 385 const HeapState& heap_state) { |
366 DCHECK(mark_compacts_ >= idle_mark_compacts_); | 386 DCHECK(mark_compacts_ >= idle_mark_compacts_); |
367 int mutator_gcs = scavenges_ + mark_compacts_ - idle_mark_compacts_; | 387 int mutator_gcs = scavenges_ + mark_compacts_ - idle_mark_compacts_; |
368 switch (mode_) { | 388 switch (mode_) { |
369 case kDone: | 389 case kDone: |
370 DCHECK(idle_mark_compacts_ == 0); | 390 DCHECK(idle_mark_compacts_ == 0); |
371 if (IsMutatorActive(heap_state.contexts_disposed, mutator_gcs)) { | 391 if (IsMutatorActive(heap_state.contexts_disposed, mark_compacts_)) { |
372 return kReduceLatency; | 392 return kReduceLatency; |
373 } | 393 } |
374 break; | 394 break; |
375 case kReduceLatency: | 395 case kReduceLatency: |
376 if (IsMutatorIdle(long_idle_notifications_, mutator_gcs)) { | 396 if (IsMutatorIdle(long_idle_notifications_, |
| 397 background_idle_notifications_, mutator_gcs)) { |
377 return kReduceMemory; | 398 return kReduceMemory; |
378 } | 399 } |
379 break; | 400 break; |
380 case kReduceMemory: | 401 case kReduceMemory: |
381 if (idle_mark_compacts_ >= kMaxIdleMarkCompacts) { | 402 if (idle_mark_compacts_ >= kMaxIdleMarkCompacts) { |
382 return kDone; | 403 return kDone; |
383 } | 404 } |
384 if (mutator_gcs > idle_mark_compacts_) { | 405 if (mutator_gcs > idle_mark_compacts_) { |
385 return kReduceLatency; | 406 return kReduceLatency; |
386 } | 407 } |
387 break; | 408 break; |
388 } | 409 } |
389 return mode_; | 410 return mode_; |
390 } | 411 } |
391 } | 412 } |
392 } | 413 } |
OLD | NEW |