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.
7 #include "src/heap/gc-idle-time-handler.h"
8 #include "testing/gtest/include/gtest/gtest.h"
15 class GCIdleTimeHandlerTest : public ::testing::Test {
17 GCIdleTimeHandlerTest() {}
18 virtual ~GCIdleTimeHandlerTest() {}
20 GCIdleTimeHandler* handler() { return &handler_; }
22 GCIdleTimeHandler::HeapState DefaultHeapState() {
23 GCIdleTimeHandler::HeapState result;
24 result.contexts_disposed = 0;
25 result.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate;
26 result.size_of_objects = kSizeOfObjects;
27 result.incremental_marking_stopped = false;
28 result.can_start_incremental_marking = true;
29 result.sweeping_in_progress = false;
30 result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed;
31 result.incremental_marking_speed_in_bytes_per_ms = kMarkingSpeed;
32 result.scavenge_speed_in_bytes_per_ms = kScavengeSpeed;
33 result.used_new_space_size = 0;
34 result.new_space_capacity = kNewSpaceCapacity;
35 result.new_space_allocation_throughput_in_bytes_per_ms =
36 kNewSpaceAllocationThroughput;
40 static const size_t kSizeOfObjects = 100 * MB;
41 static const size_t kMarkCompactSpeed = 200 * KB;
42 static const size_t kMarkingSpeed = 200 * KB;
43 static const size_t kScavengeSpeed = 100 * KB;
44 static const size_t kNewSpaceCapacity = 1 * MB;
45 static const size_t kNewSpaceAllocationThroughput = 10 * KB;
48 GCIdleTimeHandler handler_;
54 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeInitial) {
55 size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(1, 0);
57 static_cast<size_t>(GCIdleTimeHandler::kInitialConservativeMarkingSpeed *
58 GCIdleTimeHandler::kConservativeTimeRatio),
63 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeNonZero) {
64 size_t marking_speed_in_bytes_per_millisecond = 100;
65 size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
66 1, marking_speed_in_bytes_per_millisecond);
67 EXPECT_EQ(static_cast<size_t>(marking_speed_in_bytes_per_millisecond *
68 GCIdleTimeHandler::kConservativeTimeRatio),
73 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow1) {
74 size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
75 10, std::numeric_limits<size_t>::max());
76 EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
81 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow2) {
82 size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
83 std::numeric_limits<size_t>::max(), 10);
84 EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
89 TEST(GCIdleTimeHandler, EstimateMarkCompactTimeInitial) {
90 size_t size = 100 * MB;
91 size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, 0);
92 EXPECT_EQ(size / GCIdleTimeHandler::kInitialConservativeMarkCompactSpeed,
97 TEST(GCIdleTimeHandler, EstimateMarkCompactTimeNonZero) {
98 size_t size = 100 * MB;
99 size_t speed = 1 * MB;
100 size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
101 EXPECT_EQ(size / speed, time);
105 TEST(GCIdleTimeHandler, EstimateMarkCompactTimeMax) {
106 size_t size = std::numeric_limits<size_t>::max();
108 size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
109 EXPECT_EQ(GCIdleTimeHandler::kMaxMarkCompactTimeInMs, time);
113 TEST_F(GCIdleTimeHandlerTest, DoScavengeEmptyNewSpace) {
114 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
115 int idle_time_in_ms = 16;
116 EXPECT_FALSE(GCIdleTimeHandler::ShouldDoScavenge(
117 idle_time_in_ms, heap_state.new_space_capacity,
118 heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
119 heap_state.new_space_allocation_throughput_in_bytes_per_ms));
123 TEST_F(GCIdleTimeHandlerTest, DoScavengeFullNewSpace) {
124 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
125 heap_state.used_new_space_size = kNewSpaceCapacity;
126 int idle_time_in_ms = 16;
127 EXPECT_TRUE(GCIdleTimeHandler::ShouldDoScavenge(
128 idle_time_in_ms, heap_state.new_space_capacity,
129 heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
130 heap_state.new_space_allocation_throughput_in_bytes_per_ms));
134 TEST_F(GCIdleTimeHandlerTest, DoScavengeUnknownScavengeSpeed) {
135 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
136 heap_state.used_new_space_size = kNewSpaceCapacity;
137 heap_state.scavenge_speed_in_bytes_per_ms = 0;
138 int idle_time_in_ms = 16;
139 EXPECT_FALSE(GCIdleTimeHandler::ShouldDoScavenge(
140 idle_time_in_ms, heap_state.new_space_capacity,
141 heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
142 heap_state.new_space_allocation_throughput_in_bytes_per_ms));
146 TEST_F(GCIdleTimeHandlerTest, DoScavengeLowScavengeSpeed) {
147 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
148 heap_state.used_new_space_size = kNewSpaceCapacity;
149 heap_state.scavenge_speed_in_bytes_per_ms = 1 * KB;
150 int idle_time_in_ms = 16;
151 EXPECT_FALSE(GCIdleTimeHandler::ShouldDoScavenge(
152 idle_time_in_ms, heap_state.new_space_capacity,
153 heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
154 heap_state.new_space_allocation_throughput_in_bytes_per_ms));
158 TEST_F(GCIdleTimeHandlerTest, DoScavengeHighScavengeSpeed) {
159 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
160 heap_state.used_new_space_size = kNewSpaceCapacity;
161 heap_state.scavenge_speed_in_bytes_per_ms = kNewSpaceCapacity;
162 int idle_time_in_ms = 16;
163 EXPECT_TRUE(GCIdleTimeHandler::ShouldDoScavenge(
164 idle_time_in_ms, heap_state.new_space_capacity,
165 heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
166 heap_state.new_space_allocation_throughput_in_bytes_per_ms));
170 TEST_F(GCIdleTimeHandlerTest, ShouldDoMarkCompact) {
171 size_t idle_time_in_ms = 16;
172 EXPECT_TRUE(GCIdleTimeHandler::ShouldDoMarkCompact(idle_time_in_ms, 0, 0));
176 TEST_F(GCIdleTimeHandlerTest, DontDoMarkCompact) {
177 size_t idle_time_in_ms = 1;
178 EXPECT_FALSE(GCIdleTimeHandler::ShouldDoMarkCompact(
179 idle_time_in_ms, kSizeOfObjects, kMarkingSpeed));
183 TEST_F(GCIdleTimeHandlerTest, ShouldDoFinalIncrementalMarkCompact) {
184 size_t idle_time_in_ms = 16;
185 EXPECT_TRUE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
186 idle_time_in_ms, 0, 0));
190 TEST_F(GCIdleTimeHandlerTest, DontDoFinalIncrementalMarkCompact) {
191 size_t idle_time_in_ms = 1;
192 EXPECT_FALSE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
193 idle_time_in_ms, kSizeOfObjects, kMarkingSpeed));
197 TEST_F(GCIdleTimeHandlerTest, ContextDisposeLowRate) {
198 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
199 heap_state.contexts_disposed = 1;
200 heap_state.incremental_marking_stopped = true;
201 double idle_time_ms = 0;
202 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
203 EXPECT_EQ(DO_NOTHING, action.type);
207 TEST_F(GCIdleTimeHandlerTest, ContextDisposeHighRate) {
208 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
209 heap_state.contexts_disposed = 1;
210 heap_state.contexts_disposal_rate =
211 GCIdleTimeHandler::kHighContextDisposalRate - 1;
212 heap_state.incremental_marking_stopped = true;
213 double idle_time_ms = 0;
214 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
215 EXPECT_EQ(DO_FULL_GC, action.type);
219 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeIdleTime) {
220 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
221 heap_state.contexts_disposed = 1;
222 heap_state.contexts_disposal_rate = 1.0;
223 heap_state.incremental_marking_stopped = true;
224 heap_state.can_start_incremental_marking = false;
225 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
226 double idle_time_ms =
227 static_cast<double>((heap_state.size_of_objects + speed - 1) / speed);
228 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
229 EXPECT_EQ(DO_FULL_GC, action.type);
233 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeZeroIdleTime) {
234 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
235 heap_state.contexts_disposed = 1;
236 heap_state.contexts_disposal_rate = 1.0;
237 heap_state.incremental_marking_stopped = true;
238 double idle_time_ms = 0;
239 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
240 EXPECT_EQ(DO_FULL_GC, action.type);
244 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) {
245 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
246 heap_state.contexts_disposed = 1;
247 heap_state.contexts_disposal_rate = 1.0;
248 heap_state.incremental_marking_stopped = true;
249 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
250 double idle_time_ms =
251 static_cast<double>(heap_state.size_of_objects / speed - 1);
252 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
253 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
257 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) {
258 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
259 heap_state.contexts_disposed = 1;
260 heap_state.contexts_disposal_rate = 1.0;
261 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
262 double idle_time_ms =
263 static_cast<double>(heap_state.size_of_objects / speed - 1);
264 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
265 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
269 TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) {
270 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
271 size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
272 double idle_time_ms = 10;
273 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
274 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
275 EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
276 static_cast<size_t>(action.parameter));
277 EXPECT_LT(0, action.parameter);
281 TEST_F(GCIdleTimeHandlerTest, IncrementalMarking2) {
282 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
283 heap_state.incremental_marking_stopped = true;
284 size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
285 double idle_time_ms = 10;
286 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
287 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
288 EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
289 static_cast<size_t>(action.parameter));
290 EXPECT_LT(0, action.parameter);
294 TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) {
295 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
296 heap_state.incremental_marking_stopped = true;
297 heap_state.can_start_incremental_marking = false;
298 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
299 double idle_time_ms =
300 static_cast<double>(heap_state.size_of_objects / speed - 1);
301 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
302 EXPECT_EQ(DO_NOTHING, action.type);
306 TEST_F(GCIdleTimeHandlerTest, StopEventually1) {
307 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
308 heap_state.incremental_marking_stopped = true;
309 heap_state.can_start_incremental_marking = false;
310 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
311 double idle_time_ms =
312 static_cast<double>(heap_state.size_of_objects / speed + 1);
313 for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
314 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
315 EXPECT_EQ(DO_FULL_GC, action.type);
316 handler()->NotifyIdleMarkCompact();
318 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
319 EXPECT_EQ(DONE, action.type);
323 TEST_F(GCIdleTimeHandlerTest, StopEventually2) {
324 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
325 double idle_time_ms = 10;
326 for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
327 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
328 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
329 // In this case we emulate incremental marking steps that finish with a
331 handler()->NotifyIdleMarkCompact();
333 heap_state.can_start_incremental_marking = false;
334 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
335 EXPECT_EQ(DONE, action.type);
339 TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop1) {
340 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
341 heap_state.incremental_marking_stopped = true;
342 heap_state.can_start_incremental_marking = false;
343 size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
344 double idle_time_ms =
345 static_cast<double>(heap_state.size_of_objects / speed + 1);
346 for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
347 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
348 EXPECT_EQ(DO_FULL_GC, action.type);
349 handler()->NotifyIdleMarkCompact();
351 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
352 EXPECT_EQ(DONE, action.type);
353 // Emulate mutator work.
354 for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
355 handler()->NotifyScavenge();
357 action = handler()->Compute(idle_time_ms, heap_state);
358 EXPECT_EQ(DO_FULL_GC, action.type);
362 TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop2) {
363 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
364 double idle_time_ms = 10;
365 for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
366 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
367 if (action.type == DONE) break;
368 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
369 // In this case we try to emulate incremental marking steps the finish with
371 handler()->NotifyIdleMarkCompact();
373 heap_state.can_start_incremental_marking = false;
374 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
375 EXPECT_EQ(DONE, action.type);
376 // Emulate mutator work.
377 for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
378 handler()->NotifyScavenge();
380 heap_state.can_start_incremental_marking = true;
381 action = handler()->Compute(idle_time_ms, heap_state);
382 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
386 TEST_F(GCIdleTimeHandlerTest, Scavenge) {
387 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
388 int idle_time_ms = 10;
389 heap_state.used_new_space_size =
390 heap_state.new_space_capacity -
391 (kNewSpaceAllocationThroughput * idle_time_ms);
392 GCIdleTimeAction action =
393 handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
394 EXPECT_EQ(DO_SCAVENGE, action.type);
398 TEST_F(GCIdleTimeHandlerTest, ScavengeAndDone) {
399 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
400 int idle_time_ms = 10;
401 heap_state.can_start_incremental_marking = false;
402 heap_state.incremental_marking_stopped = true;
403 heap_state.used_new_space_size =
404 heap_state.new_space_capacity -
405 (kNewSpaceAllocationThroughput * idle_time_ms);
406 GCIdleTimeAction action =
407 handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
408 EXPECT_EQ(DO_SCAVENGE, action.type);
409 heap_state.used_new_space_size = 0;
410 action = handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
411 EXPECT_EQ(DO_NOTHING, action.type);
415 TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) {
416 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
417 double idle_time_ms = 0;
418 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
419 EXPECT_EQ(DO_NOTHING, action.type);
423 TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeDoNothingButStartIdleRound) {
424 GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
425 double idle_time_ms = 10;
426 for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
427 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
428 if (action.type == DONE) break;
429 EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
430 // In this case we try to emulate incremental marking steps the finish with
432 handler()->NotifyIdleMarkCompact();
434 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
435 // Emulate mutator work.
436 for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
437 handler()->NotifyScavenge();
439 action = handler()->Compute(0, heap_state);
440 EXPECT_EQ(DO_NOTHING, action.type);
443 } // namespace internal