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 <limits> | 5 #include <limits> |
6 | 6 |
7 #include "src/heap/gc-idle-time-handler.h" | 7 #include "src/heap/gc-idle-time-handler.h" |
8 #include "testing/gtest/include/gtest/gtest.h" | 8 #include "testing/gtest/include/gtest/gtest.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
11 namespace internal { | 11 namespace internal { |
12 | 12 |
13 namespace { | 13 namespace { |
14 | 14 |
15 class GCIdleTimeHandlerTest : public ::testing::Test { | 15 class GCIdleTimeHandlerTest : public ::testing::Test { |
16 public: | 16 public: |
17 GCIdleTimeHandlerTest() {} | 17 GCIdleTimeHandlerTest() {} |
18 virtual ~GCIdleTimeHandlerTest() {} | 18 virtual ~GCIdleTimeHandlerTest() {} |
19 | 19 |
20 GCIdleTimeHandler* handler() { return &handler_; } | 20 GCIdleTimeHandler* handler() { return &handler_; } |
21 | 21 |
22 GCIdleTimeHandler::HeapState DefaultHeapState() { | 22 GCIdleTimeHandler::HeapState DefaultHeapState() { |
23 GCIdleTimeHandler::HeapState result; | 23 GCIdleTimeHandler::HeapState result; |
24 result.contexts_disposed = 0; | 24 result.contexts_disposed = 0; |
25 result.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate; | 25 result.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate; |
26 result.size_of_objects = kSizeOfObjects; | 26 result.size_of_objects = kSizeOfObjects; |
27 result.incremental_marking_stopped = false; | 27 result.incremental_marking_stopped = false; |
| 28 result.can_start_incremental_marking = true; |
28 result.sweeping_in_progress = false; | 29 result.sweeping_in_progress = false; |
29 result.sweeping_completed = false; | 30 result.sweeping_completed = false; |
30 result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed; | 31 result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed; |
31 result.incremental_marking_speed_in_bytes_per_ms = kMarkingSpeed; | 32 result.incremental_marking_speed_in_bytes_per_ms = kMarkingSpeed; |
32 result.scavenge_speed_in_bytes_per_ms = kScavengeSpeed; | 33 result.scavenge_speed_in_bytes_per_ms = kScavengeSpeed; |
33 result.used_new_space_size = 0; | 34 result.used_new_space_size = 0; |
34 result.new_space_capacity = kNewSpaceCapacity; | 35 result.new_space_capacity = kNewSpaceCapacity; |
35 result.new_space_allocation_throughput_in_bytes_per_ms = | 36 result.new_space_allocation_throughput_in_bytes_per_ms = |
36 kNewSpaceAllocationThroughput; | 37 kNewSpaceAllocationThroughput; |
37 return result; | 38 return result; |
38 } | 39 } |
39 | 40 |
| 41 void TransitionToReduceMemoryMode( |
| 42 const GCIdleTimeHandler::HeapState& heap_state) { |
| 43 handler()->NotifyScavenge(); |
| 44 EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); |
| 45 double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; |
| 46 int limit = GCIdleTimeHandler::kLongIdleNotificationsBeforeMutatorIsIdle; |
| 47 bool incremental = !heap_state.incremental_marking_stopped || |
| 48 heap_state.can_start_incremental_marking; |
| 49 for (int i = 0; i < limit; i++) { |
| 50 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 51 if (incremental) { |
| 52 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 53 } else { |
| 54 EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type); |
| 55 } |
| 56 } |
| 57 handler()->Compute(idle_time_ms, heap_state); |
| 58 EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode()); |
| 59 } |
| 60 |
| 61 void TransitionToDoneMode(const GCIdleTimeHandler::HeapState& heap_state, |
| 62 double idle_time_ms, |
| 63 GCIdleTimeActionType expected) { |
| 64 EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode()); |
| 65 int limit = GCIdleTimeHandler::kMaxIdleMarkCompacts; |
| 66 for (int i = 0; i < limit; i++) { |
| 67 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 68 EXPECT_EQ(expected, action.type); |
| 69 EXPECT_TRUE(action.reduce_memory); |
| 70 handler()->NotifyMarkCompact(true); |
| 71 handler()->NotifyIdleMarkCompact(); |
| 72 } |
| 73 handler()->Compute(idle_time_ms, heap_state); |
| 74 EXPECT_EQ(GCIdleTimeHandler::kDone, handler()->mode()); |
| 75 } |
| 76 |
| 77 void TransitionToReduceLatencyMode( |
| 78 const GCIdleTimeHandler::HeapState& heap_state) { |
| 79 EXPECT_EQ(GCIdleTimeHandler::kDone, handler()->mode()); |
| 80 int limit = GCIdleTimeHandler::kMarkCompactsBeforeMutatorIsActive; |
| 81 double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; |
| 82 for (int i = 0; i < limit; i++) { |
| 83 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 84 EXPECT_EQ(DONE, action.type); |
| 85 handler()->NotifyMarkCompact(true); |
| 86 } |
| 87 handler()->Compute(idle_time_ms, heap_state); |
| 88 EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); |
| 89 } |
| 90 |
40 static const size_t kSizeOfObjects = 100 * MB; | 91 static const size_t kSizeOfObjects = 100 * MB; |
41 static const size_t kMarkCompactSpeed = 200 * KB; | 92 static const size_t kMarkCompactSpeed = 200 * KB; |
42 static const size_t kMarkingSpeed = 200 * KB; | 93 static const size_t kMarkingSpeed = 200 * KB; |
43 static const size_t kScavengeSpeed = 100 * KB; | 94 static const size_t kScavengeSpeed = 100 * KB; |
44 static const size_t kNewSpaceCapacity = 1 * MB; | 95 static const size_t kNewSpaceCapacity = 1 * MB; |
45 static const size_t kNewSpaceAllocationThroughput = 10 * KB; | 96 static const size_t kNewSpaceAllocationThroughput = 10 * KB; |
46 static const int kMaxNotifications = 100; | 97 static const int kMaxNotifications = 1000; |
47 | 98 |
48 private: | 99 private: |
49 GCIdleTimeHandler handler_; | 100 GCIdleTimeHandler handler_; |
50 }; | 101 }; |
51 | 102 |
52 } // namespace | 103 } // namespace |
53 | 104 |
54 | 105 |
55 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeInitial) { | 106 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeInitial) { |
56 size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(1, 0); | 107 size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(1, 0); |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 EXPECT_FALSE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact( | 256 EXPECT_FALSE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact( |
206 idle_time_ms, kSizeOfObjects, kMarkingSpeed)); | 257 idle_time_ms, kSizeOfObjects, kMarkingSpeed)); |
207 } | 258 } |
208 | 259 |
209 | 260 |
210 TEST_F(GCIdleTimeHandlerTest, ContextDisposeLowRate) { | 261 TEST_F(GCIdleTimeHandlerTest, ContextDisposeLowRate) { |
211 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | 262 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
212 heap_state.contexts_disposed = 1; | 263 heap_state.contexts_disposed = 1; |
213 heap_state.incremental_marking_stopped = true; | 264 heap_state.incremental_marking_stopped = true; |
214 double idle_time_ms = 0; | 265 double idle_time_ms = 0; |
215 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 266 for (int mode = 0; mode < 1; mode++) { |
216 EXPECT_EQ(DO_NOTHING, action.type); | 267 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 268 EXPECT_EQ(DO_NOTHING, action.type); |
| 269 TransitionToReduceMemoryMode(heap_state); |
| 270 } |
217 } | 271 } |
218 | 272 |
219 | 273 |
220 TEST_F(GCIdleTimeHandlerTest, ContextDisposeHighRate) { | 274 TEST_F(GCIdleTimeHandlerTest, ContextDisposeHighRate) { |
221 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | 275 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
222 heap_state.contexts_disposed = 1; | 276 heap_state.contexts_disposed = 1; |
223 heap_state.contexts_disposal_rate = | 277 heap_state.contexts_disposal_rate = |
224 GCIdleTimeHandler::kHighContextDisposalRate - 1; | 278 GCIdleTimeHandler::kHighContextDisposalRate - 1; |
225 heap_state.incremental_marking_stopped = true; | 279 heap_state.incremental_marking_stopped = true; |
226 double idle_time_ms = 0; | 280 double idle_time_ms = 0; |
227 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 281 for (int mode = 0; mode < 1; mode++) { |
228 EXPECT_EQ(DO_FULL_GC, action.type); | 282 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 283 EXPECT_EQ(DO_FULL_GC, action.type); |
| 284 heap_state.contexts_disposal_rate = 0.0; |
| 285 TransitionToReduceMemoryMode(heap_state); |
| 286 } |
229 } | 287 } |
230 | 288 |
231 | 289 |
232 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeZeroIdleTime) { | 290 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeZeroIdleTime) { |
233 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | 291 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
234 heap_state.contexts_disposed = 1; | 292 heap_state.contexts_disposed = 1; |
235 heap_state.contexts_disposal_rate = 1.0; | 293 heap_state.contexts_disposal_rate = 1.0; |
236 heap_state.incremental_marking_stopped = true; | 294 heap_state.incremental_marking_stopped = true; |
237 double idle_time_ms = 0; | 295 double idle_time_ms = 0; |
238 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 296 for (int mode = 0; mode < 1; mode++) { |
239 EXPECT_EQ(DO_FULL_GC, action.type); | 297 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 298 EXPECT_EQ(DO_FULL_GC, action.type); |
| 299 heap_state.contexts_disposal_rate = 0.0; |
| 300 TransitionToReduceMemoryMode(heap_state); |
| 301 } |
240 } | 302 } |
241 | 303 |
242 | 304 |
243 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) { | 305 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) { |
244 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | 306 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
245 heap_state.contexts_disposed = 1; | 307 heap_state.contexts_disposed = 1; |
246 heap_state.contexts_disposal_rate = | 308 heap_state.contexts_disposal_rate = |
| 309 GCIdleTimeHandler::kHighContextDisposalRate; |
| 310 heap_state.incremental_marking_stopped = true; |
| 311 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; |
| 312 double idle_time_ms = |
| 313 static_cast<double>(heap_state.size_of_objects / speed - 1); |
| 314 for (int mode = 0; mode < 1; mode++) { |
| 315 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 316 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 317 heap_state.contexts_disposal_rate = 0.0; |
| 318 TransitionToReduceMemoryMode(heap_state); |
| 319 } |
| 320 } |
| 321 |
| 322 |
| 323 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) { |
| 324 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 325 heap_state.contexts_disposed = 1; |
| 326 heap_state.contexts_disposal_rate = |
247 GCIdleTimeHandler::kHighContextDisposalRate; | 327 GCIdleTimeHandler::kHighContextDisposalRate; |
248 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; | 328 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; |
249 double idle_time_ms = | 329 double idle_time_ms = |
250 static_cast<double>(heap_state.size_of_objects / speed - 1); | 330 static_cast<double>(heap_state.size_of_objects / speed - 1); |
251 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 331 for (int mode = 0; mode < 1; mode++) { |
252 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); | 332 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
253 } | 333 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
254 | 334 heap_state.contexts_disposal_rate = 0.0; |
255 | 335 TransitionToReduceMemoryMode(heap_state); |
256 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) { | 336 } |
257 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | 337 } |
258 heap_state.contexts_disposed = 1; | 338 |
259 heap_state.contexts_disposal_rate = | 339 |
260 GCIdleTimeHandler::kHighContextDisposalRate; | 340 TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) { |
| 341 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 342 size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms; |
| 343 double idle_time_ms = 10; |
| 344 for (int mode = 0; mode < 1; mode++) { |
| 345 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 346 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 347 EXPECT_GT(speed * static_cast<size_t>(idle_time_ms), |
| 348 static_cast<size_t>(action.parameter)); |
| 349 EXPECT_LT(0, action.parameter); |
| 350 TransitionToReduceMemoryMode(heap_state); |
| 351 } |
| 352 } |
| 353 |
| 354 |
| 355 TEST_F(GCIdleTimeHandlerTest, IncrementalMarking2) { |
| 356 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 357 heap_state.incremental_marking_stopped = true; |
| 358 size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms; |
| 359 double idle_time_ms = 10; |
| 360 for (int mode = 0; mode < 1; mode++) { |
| 361 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 362 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 363 EXPECT_GT(speed * static_cast<size_t>(idle_time_ms), |
| 364 static_cast<size_t>(action.parameter)); |
| 365 EXPECT_LT(0, action.parameter); |
| 366 TransitionToReduceMemoryMode(heap_state); |
| 367 } |
| 368 } |
| 369 |
| 370 |
| 371 TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) { |
| 372 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 373 heap_state.incremental_marking_stopped = true; |
| 374 heap_state.can_start_incremental_marking = false; |
261 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; | 375 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; |
262 double idle_time_ms = | 376 double idle_time_ms = |
263 static_cast<double>(heap_state.size_of_objects / speed - 1); | 377 static_cast<double>(heap_state.size_of_objects / speed - 1); |
264 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 378 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 379 EXPECT_EQ(DO_NOTHING, action.type); |
| 380 TransitionToReduceMemoryMode(heap_state); |
| 381 action = handler()->Compute(idle_time_ms, heap_state); |
265 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); | 382 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
266 } | 383 } |
267 | 384 |
268 | 385 |
269 TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) { | 386 TEST_F(GCIdleTimeHandlerTest, FinalizeSweeping) { |
270 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | 387 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
271 size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms; | 388 heap_state.incremental_marking_stopped = true; |
272 double idle_time_ms = 10; | 389 heap_state.can_start_incremental_marking = false; |
273 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 390 for (int mode = 0; mode < 1; mode++) { |
274 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); | 391 heap_state.sweeping_in_progress = true; |
275 EXPECT_GT(speed * static_cast<size_t>(idle_time_ms), | 392 heap_state.sweeping_completed = true; |
276 static_cast<size_t>(action.parameter)); | 393 double idle_time_ms = 10.0; |
277 EXPECT_LT(0, action.parameter); | 394 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
278 } | 395 EXPECT_EQ(DO_FINALIZE_SWEEPING, action.type); |
279 | 396 heap_state.sweeping_in_progress = false; |
280 | 397 heap_state.sweeping_completed = false; |
281 TEST_F(GCIdleTimeHandlerTest, IncrementalMarking2) { | 398 TransitionToReduceMemoryMode(heap_state); |
282 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | 399 } |
283 size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms; | 400 } |
284 double idle_time_ms = 10; | 401 |
285 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 402 |
286 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); | 403 TEST_F(GCIdleTimeHandlerTest, CannotFinalizeSweeping) { |
287 EXPECT_GT(speed * static_cast<size_t>(idle_time_ms), | 404 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
288 static_cast<size_t>(action.parameter)); | 405 heap_state.incremental_marking_stopped = true; |
289 EXPECT_LT(0, action.parameter); | 406 heap_state.can_start_incremental_marking = false; |
290 } | 407 for (int mode = 0; mode < 1; mode++) { |
291 | 408 heap_state.sweeping_in_progress = true; |
292 | 409 heap_state.sweeping_completed = false; |
293 TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) { | 410 double idle_time_ms = 10.0; |
294 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | 411 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
295 heap_state.incremental_marking_stopped = true; | 412 EXPECT_EQ(DO_NOTHING, action.type); |
| 413 heap_state.sweeping_in_progress = false; |
| 414 heap_state.sweeping_completed = false; |
| 415 TransitionToReduceMemoryMode(heap_state); |
| 416 } |
| 417 } |
| 418 |
| 419 |
| 420 TEST_F(GCIdleTimeHandlerTest, Scavenge) { |
| 421 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 422 int idle_time_ms = 10; |
| 423 for (int mode = 0; mode < 1; mode++) { |
| 424 heap_state.used_new_space_size = |
| 425 heap_state.new_space_capacity - |
| 426 (kNewSpaceAllocationThroughput * idle_time_ms); |
| 427 GCIdleTimeAction action = |
| 428 handler()->Compute(static_cast<double>(idle_time_ms), heap_state); |
| 429 EXPECT_EQ(DO_SCAVENGE, action.type); |
| 430 heap_state.used_new_space_size = 0; |
| 431 TransitionToReduceMemoryMode(heap_state); |
| 432 } |
| 433 } |
| 434 |
| 435 |
| 436 TEST_F(GCIdleTimeHandlerTest, ScavengeAndDone) { |
| 437 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 438 int idle_time_ms = 10; |
| 439 heap_state.can_start_incremental_marking = false; |
| 440 heap_state.incremental_marking_stopped = true; |
| 441 for (int mode = 0; mode < 1; mode++) { |
| 442 heap_state.used_new_space_size = |
| 443 heap_state.new_space_capacity - |
| 444 (kNewSpaceAllocationThroughput * idle_time_ms); |
| 445 GCIdleTimeAction action = |
| 446 handler()->Compute(static_cast<double>(idle_time_ms), heap_state); |
| 447 EXPECT_EQ(DO_SCAVENGE, action.type); |
| 448 heap_state.used_new_space_size = 0; |
| 449 action = handler()->Compute(static_cast<double>(idle_time_ms), heap_state); |
| 450 EXPECT_EQ(DO_NOTHING, action.type); |
| 451 TransitionToReduceMemoryMode(heap_state); |
| 452 } |
| 453 } |
| 454 |
| 455 |
| 456 TEST_F(GCIdleTimeHandlerTest, StopEventually1) { |
| 457 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 458 heap_state.incremental_marking_stopped = true; |
| 459 heap_state.can_start_incremental_marking = false; |
| 460 double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; |
| 461 bool stopped = false; |
| 462 for (int i = 0; i < kMaxNotifications && !stopped; i++) { |
| 463 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 464 if (action.type == DO_INCREMENTAL_MARKING || action.type == DO_FULL_GC) { |
| 465 handler()->NotifyMarkCompact(true); |
| 466 handler()->NotifyIdleMarkCompact(); |
| 467 } |
| 468 if (action.type == DONE) stopped = true; |
| 469 } |
| 470 EXPECT_TRUE(stopped); |
| 471 } |
| 472 |
| 473 |
| 474 TEST_F(GCIdleTimeHandlerTest, StopEventually2) { |
| 475 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 476 heap_state.incremental_marking_stopped = true; |
| 477 heap_state.can_start_incremental_marking = false; |
296 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; | 478 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; |
297 double idle_time_ms = | 479 double idle_time_ms = |
298 static_cast<double>(heap_state.size_of_objects / speed - 1); | 480 static_cast<double>(heap_state.size_of_objects / speed + 1); |
299 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 481 TransitionToReduceMemoryMode(heap_state); |
300 EXPECT_EQ(DONE, action.type); | 482 TransitionToDoneMode(heap_state, idle_time_ms, DO_FULL_GC); |
301 } | 483 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
302 | 484 EXPECT_EQ(DONE, action.type); |
303 | 485 } |
304 TEST_F(GCIdleTimeHandlerTest, FinalizeSweeping) { | 486 |
305 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | 487 |
306 heap_state.incremental_marking_stopped = true; | 488 TEST_F(GCIdleTimeHandlerTest, StopEventually3) { |
307 heap_state.sweeping_in_progress = true; | 489 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
308 heap_state.sweeping_completed = true; | 490 heap_state.incremental_marking_stopped = true; |
309 double idle_time_ms = 10.0; | 491 heap_state.can_start_incremental_marking = false; |
310 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 492 double idle_time_ms = 10; |
311 EXPECT_EQ(DO_FINALIZE_SWEEPING, action.type); | 493 TransitionToReduceMemoryMode(heap_state); |
312 } | 494 TransitionToDoneMode(heap_state, idle_time_ms, DO_INCREMENTAL_MARKING); |
313 | 495 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
314 | 496 EXPECT_EQ(DONE, action.type); |
315 TEST_F(GCIdleTimeHandlerTest, CannotFinalizeSweeping) { | 497 } |
316 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | 498 |
317 heap_state.incremental_marking_stopped = true; | 499 |
| 500 TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop1) { |
| 501 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 502 heap_state.incremental_marking_stopped = true; |
| 503 heap_state.can_start_incremental_marking = false; |
| 504 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms; |
| 505 double idle_time_ms = |
| 506 static_cast<double>(heap_state.size_of_objects / speed + 1); |
| 507 TransitionToReduceMemoryMode(heap_state); |
| 508 TransitionToDoneMode(heap_state, idle_time_ms, DO_FULL_GC); |
| 509 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 510 EXPECT_EQ(DONE, action.type); |
| 511 TransitionToReduceLatencyMode(heap_state); |
| 512 heap_state.can_start_incremental_marking = true; |
| 513 action = handler()->Compute(idle_time_ms, heap_state); |
| 514 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 515 EXPECT_FALSE(action.reduce_memory); |
| 516 EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); |
| 517 } |
| 518 |
| 519 |
| 520 TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop2) { |
| 521 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 522 heap_state.incremental_marking_stopped = true; |
| 523 heap_state.can_start_incremental_marking = false; |
| 524 double idle_time_ms = 10; |
| 525 TransitionToReduceMemoryMode(heap_state); |
| 526 TransitionToDoneMode(heap_state, idle_time_ms, DO_INCREMENTAL_MARKING); |
| 527 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 528 EXPECT_EQ(DONE, action.type); |
| 529 TransitionToReduceLatencyMode(heap_state); |
| 530 heap_state.can_start_incremental_marking = true; |
| 531 action = handler()->Compute(idle_time_ms, heap_state); |
| 532 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 533 EXPECT_FALSE(action.reduce_memory); |
| 534 EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); |
| 535 } |
| 536 |
| 537 |
| 538 TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) { |
| 539 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 540 for (int i = 0; i < kMaxNotifications; i++) { |
| 541 GCIdleTimeAction action = handler()->Compute(0, heap_state); |
| 542 EXPECT_EQ(DO_NOTHING, action.type); |
| 543 } |
| 544 } |
| 545 |
| 546 |
| 547 TEST_F(GCIdleTimeHandlerTest, SmallIdleTimeNothingToDo) { |
| 548 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 549 heap_state.incremental_marking_stopped = true; |
| 550 heap_state.can_start_incremental_marking = false; |
| 551 for (int i = 0; i < kMaxNotifications; i++) { |
| 552 GCIdleTimeAction action = handler()->Compute(10, heap_state); |
| 553 EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type); |
| 554 } |
| 555 } |
| 556 |
| 557 |
| 558 TEST_F(GCIdleTimeHandlerTest, StayInReduceLatencyModeBecauseOfScavenges) { |
| 559 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 560 heap_state.incremental_marking_stopped = true; |
| 561 heap_state.can_start_incremental_marking = false; |
| 562 double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; |
| 563 int limit = GCIdleTimeHandler::kLongIdleNotificationsBeforeMutatorIsIdle; |
| 564 for (int i = 0; i < kMaxNotifications; i++) { |
| 565 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 566 EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type); |
| 567 if ((i + 1) % limit == 0) handler()->NotifyScavenge(); |
| 568 EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); |
| 569 } |
| 570 } |
| 571 |
| 572 |
| 573 TEST_F(GCIdleTimeHandlerTest, StayInReduceLatencyModeBecauseOfMarkCompacts) { |
| 574 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 575 heap_state.incremental_marking_stopped = true; |
| 576 heap_state.can_start_incremental_marking = false; |
| 577 double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; |
| 578 int limit = GCIdleTimeHandler::kLongIdleNotificationsBeforeMutatorIsIdle; |
| 579 for (int i = 0; i < kMaxNotifications; i++) { |
| 580 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 581 EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type); |
| 582 if ((i + 1) % limit == 0) handler()->NotifyMarkCompact(true); |
| 583 EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); |
| 584 } |
| 585 } |
| 586 |
| 587 |
| 588 TEST_F(GCIdleTimeHandlerTest, ReduceMemoryToReduceLatency) { |
| 589 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 590 heap_state.incremental_marking_stopped = true; |
| 591 heap_state.can_start_incremental_marking = false; |
| 592 double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; |
| 593 int limit = GCIdleTimeHandler::kMaxIdleMarkCompacts; |
| 594 for (int idle_gc = 0; idle_gc < limit; idle_gc++) { |
| 595 TransitionToReduceMemoryMode(heap_state); |
| 596 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 597 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 598 EXPECT_TRUE(action.reduce_memory); |
| 599 EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode()); |
| 600 for (int i = 0; i < idle_gc; i++) { |
| 601 action = handler()->Compute(idle_time_ms, heap_state); |
| 602 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 603 EXPECT_TRUE(action.reduce_memory); |
| 604 // ReduceMemory mode should tolerate one mutator GC per idle GC. |
| 605 handler()->NotifyScavenge(); |
| 606 // Notify idle GC. |
| 607 handler()->NotifyMarkCompact(true); |
| 608 handler()->NotifyIdleMarkCompact(); |
| 609 } |
| 610 // Transition to ReduceLatency mode after doing |idle_gc| idle GCs. |
| 611 handler()->NotifyScavenge(); |
| 612 action = handler()->Compute(idle_time_ms, heap_state); |
| 613 EXPECT_EQ(DO_NOTHING, action.type); |
| 614 EXPECT_FALSE(action.reduce_memory); |
| 615 EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); |
| 616 } |
| 617 } |
| 618 |
| 619 |
| 620 TEST_F(GCIdleTimeHandlerTest, ReduceMemoryToDone) { |
| 621 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 622 heap_state.incremental_marking_stopped = true; |
| 623 heap_state.can_start_incremental_marking = false; |
| 624 double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; |
| 625 int limit = GCIdleTimeHandler::kMaxIdleMarkCompacts; |
| 626 TransitionToReduceMemoryMode(heap_state); |
| 627 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 628 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 629 EXPECT_TRUE(action.reduce_memory); |
| 630 for (int i = 0; i < limit; i++) { |
| 631 action = handler()->Compute(idle_time_ms, heap_state); |
| 632 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 633 EXPECT_TRUE(action.reduce_memory); |
| 634 EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode()); |
| 635 // ReduceMemory mode should tolerate one mutator GC per idle GC. |
| 636 handler()->NotifyScavenge(); |
| 637 // Notify idle GC. |
| 638 handler()->NotifyMarkCompact(true); |
| 639 handler()->NotifyIdleMarkCompact(); |
| 640 } |
| 641 action = handler()->Compute(idle_time_ms, heap_state); |
| 642 EXPECT_EQ(DONE, action.type); |
| 643 } |
| 644 |
| 645 |
| 646 TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnSweeping) { |
| 647 // Regression test for crbug.com/489323. |
| 648 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 649 |
| 650 // Simulate sweeping being in-progress but not complete. |
| 651 heap_state.incremental_marking_stopped = true; |
| 652 heap_state.can_start_incremental_marking = false; |
318 heap_state.sweeping_in_progress = true; | 653 heap_state.sweeping_in_progress = true; |
319 heap_state.sweeping_completed = false; | 654 heap_state.sweeping_completed = false; |
320 double idle_time_ms = 10.0; | 655 double idle_time_ms = 10.0; |
321 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 656 for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimesPerMode; i++) { |
322 EXPECT_EQ(DO_NOTHING, action.type); | 657 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
323 } | 658 EXPECT_EQ(DO_NOTHING, action.type); |
324 | 659 } |
325 | |
326 TEST_F(GCIdleTimeHandlerTest, Scavenge) { | |
327 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | |
328 int idle_time_ms = 10; | |
329 heap_state.used_new_space_size = | |
330 heap_state.new_space_capacity - | |
331 (kNewSpaceAllocationThroughput * idle_time_ms); | |
332 GCIdleTimeAction action = | |
333 handler()->Compute(static_cast<double>(idle_time_ms), heap_state); | |
334 EXPECT_EQ(DO_SCAVENGE, action.type); | |
335 heap_state.used_new_space_size = 0; | |
336 } | |
337 | |
338 | |
339 TEST_F(GCIdleTimeHandlerTest, ScavengeAndDone) { | |
340 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | |
341 int idle_time_ms = 10; | |
342 heap_state.incremental_marking_stopped = true; | |
343 heap_state.used_new_space_size = | |
344 heap_state.new_space_capacity - | |
345 (kNewSpaceAllocationThroughput * idle_time_ms); | |
346 GCIdleTimeAction action = | |
347 handler()->Compute(static_cast<double>(idle_time_ms), heap_state); | |
348 EXPECT_EQ(DO_SCAVENGE, action.type); | |
349 heap_state.used_new_space_size = 0; | |
350 action = handler()->Compute(static_cast<double>(idle_time_ms), heap_state); | |
351 EXPECT_EQ(DONE, action.type); | |
352 } | |
353 | |
354 | |
355 TEST_F(GCIdleTimeHandlerTest, DoNotStartIncrementalMarking) { | |
356 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | |
357 heap_state.incremental_marking_stopped = true; | |
358 double idle_time_ms = 10.0; | |
359 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | |
360 EXPECT_EQ(DONE, action.type); | |
361 } | |
362 | |
363 | |
364 TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop) { | |
365 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | |
366 heap_state.incremental_marking_stopped = true; | |
367 double idle_time_ms = 10.0; | |
368 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | |
369 EXPECT_EQ(DONE, action.type); | |
370 heap_state.incremental_marking_stopped = false; | |
371 action = handler()->Compute(idle_time_ms, heap_state); | |
372 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); | |
373 } | |
374 | |
375 | |
376 TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) { | |
377 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | |
378 for (int i = 0; i < kMaxNotifications; i++) { | |
379 GCIdleTimeAction action = handler()->Compute(0, heap_state); | |
380 EXPECT_EQ(DO_NOTHING, action.type); | |
381 } | |
382 } | |
383 | |
384 | |
385 TEST_F(GCIdleTimeHandlerTest, SmallIdleTimeNothingToDo) { | |
386 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | |
387 heap_state.incremental_marking_stopped = true; | |
388 for (int i = 0; i < kMaxNotifications; i++) { | |
389 GCIdleTimeAction action = handler()->Compute(10, heap_state); | |
390 EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type); | |
391 } | |
392 } | |
393 | |
394 | |
395 TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnSweeping) { | |
396 // Regression test for crbug.com/489323. | |
397 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | |
398 | |
399 // Simulate sweeping being in-progress but not complete. | |
400 heap_state.incremental_marking_stopped = true; | |
401 heap_state.sweeping_in_progress = true; | |
402 heap_state.sweeping_completed = false; | |
403 double idle_time_ms = 10.0; | |
404 for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimes; i++) { | |
405 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | |
406 EXPECT_EQ(DO_NOTHING, action.type); | |
407 } | |
408 // We should return DONE after not making progress for some time. | 660 // We should return DONE after not making progress for some time. |
409 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 661 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
410 EXPECT_EQ(DONE, action.type); | 662 EXPECT_EQ(DONE, action.type); |
411 } | 663 } |
412 | 664 |
413 | 665 |
414 TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnIncrementalMarking) { | 666 TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnIncrementalMarking) { |
415 // Regression test for crbug.com/489323. | 667 // Regression test for crbug.com/489323. |
416 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); | 668 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
417 | 669 |
418 // Simulate incremental marking stopped and not eligible to start. | 670 // Simulate incremental marking stopped and not eligible to start. |
419 heap_state.incremental_marking_stopped = true; | 671 heap_state.incremental_marking_stopped = true; |
| 672 heap_state.can_start_incremental_marking = false; |
420 double idle_time_ms = 10.0; | 673 double idle_time_ms = 10.0; |
421 // We should return DONE if we cannot start incremental marking. | 674 for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimesPerMode; i++) { |
| 675 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 676 EXPECT_EQ(DO_NOTHING, action.type); |
| 677 } |
| 678 // We should return DONE after not making progress for some time. |
422 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); | 679 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
423 EXPECT_EQ(DONE, action.type); | 680 EXPECT_EQ(DONE, action.type); |
424 } | 681 } |
425 | 682 |
| 683 |
| 684 TEST_F(GCIdleTimeHandlerTest, BackgroundReduceLatencyToReduceMemory) { |
| 685 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 686 heap_state.incremental_marking_stopped = false; |
| 687 heap_state.can_start_incremental_marking = true; |
| 688 double idle_time_ms = GCIdleTimeHandler::kMinBackgroundIdleTime; |
| 689 handler()->NotifyScavenge(); |
| 690 EXPECT_EQ(GCIdleTimeHandler::kReduceLatency, handler()->mode()); |
| 691 int limit = |
| 692 GCIdleTimeHandler::kBackgroundIdleNotificationsBeforeMutatorIsIdle; |
| 693 for (int i = 0; i < limit; i++) { |
| 694 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 695 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 696 } |
| 697 handler()->Compute(idle_time_ms, heap_state); |
| 698 EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode()); |
| 699 } |
| 700 |
| 701 |
| 702 TEST_F(GCIdleTimeHandlerTest, SkipUselessGCs) { |
| 703 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); |
| 704 heap_state.incremental_marking_stopped = false; |
| 705 heap_state.can_start_incremental_marking = true; |
| 706 TransitionToReduceMemoryMode(heap_state); |
| 707 EXPECT_EQ(GCIdleTimeHandler::kReduceMemory, handler()->mode()); |
| 708 double idle_time_ms = GCIdleTimeHandler::kMinLongIdleTime; |
| 709 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); |
| 710 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type); |
| 711 handler()->NotifyMarkCompact(false); |
| 712 handler()->NotifyIdleMarkCompact(); |
| 713 action = handler()->Compute(idle_time_ms, heap_state); |
| 714 EXPECT_EQ(DONE, action.type); |
| 715 } |
| 716 |
426 } // namespace internal | 717 } // namespace internal |
427 } // namespace v8 | 718 } // namespace v8 |
OLD | NEW |