2076e604faa06d92e29e499c5d12a5eae4420694
[platform/upstream/nodejs.git] / deps / v8 / test / unittests / heap / gc-idle-time-handler-unittest.cc
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.
4
5 #include <limits>
6
7 #include "src/heap/gc-idle-time-handler.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9
10 namespace v8 {
11 namespace internal {
12
13 namespace {
14
15 class GCIdleTimeHandlerTest : public ::testing::Test {
16  public:
17   GCIdleTimeHandlerTest() {}
18   virtual ~GCIdleTimeHandlerTest() {}
19
20   GCIdleTimeHandler* handler() { return &handler_; }
21
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;
37     return result;
38   }
39
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;
46
47  private:
48   GCIdleTimeHandler handler_;
49 };
50
51 }  // namespace
52
53
54 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeInitial) {
55   size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(1, 0);
56   EXPECT_EQ(
57       static_cast<size_t>(GCIdleTimeHandler::kInitialConservativeMarkingSpeed *
58                           GCIdleTimeHandler::kConservativeTimeRatio),
59       step_size);
60 }
61
62
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),
69             step_size);
70 }
71
72
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),
77             step_size);
78 }
79
80
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),
85             step_size);
86 }
87
88
89 TEST(GCIdleTimeHandler, EstimateMarkCompactTimeInitial) {
90   size_t size = 100 * MB;
91   size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, 0);
92   EXPECT_EQ(size / GCIdleTimeHandler::kInitialConservativeMarkCompactSpeed,
93             time);
94 }
95
96
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);
102 }
103
104
105 TEST(GCIdleTimeHandler, EstimateMarkCompactTimeMax) {
106   size_t size = std::numeric_limits<size_t>::max();
107   size_t speed = 1;
108   size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
109   EXPECT_EQ(GCIdleTimeHandler::kMaxMarkCompactTimeInMs, time);
110 }
111
112
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));
120 }
121
122
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));
131 }
132
133
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));
143 }
144
145
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));
155 }
156
157
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));
167 }
168
169
170 TEST_F(GCIdleTimeHandlerTest, ShouldDoMarkCompact) {
171   size_t idle_time_in_ms = 16;
172   EXPECT_TRUE(GCIdleTimeHandler::ShouldDoMarkCompact(idle_time_in_ms, 0, 0));
173 }
174
175
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));
180 }
181
182
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));
187 }
188
189
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));
194 }
195
196
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);
204 }
205
206
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);
216 }
217
218
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);
230 }
231
232
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);
241 }
242
243
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);
254 }
255
256
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);
266 }
267
268
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);
278 }
279
280
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);
291 }
292
293
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);
303 }
304
305
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();
317   }
318   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
319   EXPECT_EQ(DONE, action.type);
320 }
321
322
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
330     // full gc.
331     handler()->NotifyIdleMarkCompact();
332   }
333   heap_state.can_start_incremental_marking = false;
334   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
335   EXPECT_EQ(DONE, action.type);
336 }
337
338
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();
350   }
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();
356   }
357   action = handler()->Compute(idle_time_ms, heap_state);
358   EXPECT_EQ(DO_FULL_GC, action.type);
359 }
360
361
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
370     // a full gc.
371     handler()->NotifyIdleMarkCompact();
372   }
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();
379   }
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);
383 }
384
385
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);
395 }
396
397
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);
412 }
413
414
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);
420 }
421
422
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
431     // a full gc.
432     handler()->NotifyIdleMarkCompact();
433   }
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();
438   }
439   action = handler()->Compute(0, heap_state);
440   EXPECT_EQ(DO_NOTHING, action.type);
441 }
442
443 }  // namespace internal
444 }  // namespace v8