Home | History | Annotate | Download | only in heap
      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.size_of_objects = kSizeOfObjects;
     26     result.incremental_marking_stopped = false;
     27     result.can_start_incremental_marking = true;
     28     result.sweeping_in_progress = false;
     29     result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed;
     30     result.incremental_marking_speed_in_bytes_per_ms = kMarkingSpeed;
     31     result.scavenge_speed_in_bytes_per_ms = kScavengeSpeed;
     32     result.available_new_space_memory = kNewSpaceCapacity;
     33     result.new_space_capacity = kNewSpaceCapacity;
     34     result.new_space_allocation_throughput_in_bytes_per_ms =
     35         kNewSpaceAllocationThroughput;
     36     return result;
     37   }
     38 
     39   static const size_t kSizeOfObjects = 100 * MB;
     40   static const size_t kMarkCompactSpeed = 200 * KB;
     41   static const size_t kMarkingSpeed = 200 * KB;
     42   static const size_t kScavengeSpeed = 100 * KB;
     43   static const size_t kNewSpaceCapacity = 1 * MB;
     44   static const size_t kNewSpaceAllocationThroughput = 10 * KB;
     45 
     46  private:
     47   GCIdleTimeHandler handler_;
     48 };
     49 
     50 }  // namespace
     51 
     52 
     53 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeInitial) {
     54   size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(1, 0);
     55   EXPECT_EQ(
     56       static_cast<size_t>(GCIdleTimeHandler::kInitialConservativeMarkingSpeed *
     57                           GCIdleTimeHandler::kConservativeTimeRatio),
     58       step_size);
     59 }
     60 
     61 
     62 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeNonZero) {
     63   size_t marking_speed_in_bytes_per_millisecond = 100;
     64   size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
     65       1, marking_speed_in_bytes_per_millisecond);
     66   EXPECT_EQ(static_cast<size_t>(marking_speed_in_bytes_per_millisecond *
     67                                 GCIdleTimeHandler::kConservativeTimeRatio),
     68             step_size);
     69 }
     70 
     71 
     72 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow1) {
     73   size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
     74       10, std::numeric_limits<size_t>::max());
     75   EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
     76             step_size);
     77 }
     78 
     79 
     80 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow2) {
     81   size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
     82       std::numeric_limits<size_t>::max(), 10);
     83   EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
     84             step_size);
     85 }
     86 
     87 
     88 TEST(GCIdleTimeHandler, EstimateMarkCompactTimeInitial) {
     89   size_t size = 100 * MB;
     90   size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, 0);
     91   EXPECT_EQ(size / GCIdleTimeHandler::kInitialConservativeMarkCompactSpeed,
     92             time);
     93 }
     94 
     95 
     96 TEST(GCIdleTimeHandler, EstimateMarkCompactTimeNonZero) {
     97   size_t size = 100 * MB;
     98   size_t speed = 1 * MB;
     99   size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
    100   EXPECT_EQ(size / speed, time);
    101 }
    102 
    103 
    104 TEST(GCIdleTimeHandler, EstimateMarkCompactTimeMax) {
    105   size_t size = std::numeric_limits<size_t>::max();
    106   size_t speed = 1;
    107   size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
    108   EXPECT_EQ(GCIdleTimeHandler::kMaxMarkCompactTimeInMs, time);
    109 }
    110 
    111 
    112 TEST(GCIdleTimeHandler, EstimateScavengeTimeInitial) {
    113   size_t size = 1 * MB;
    114   size_t time = GCIdleTimeHandler::EstimateScavengeTime(size, 0);
    115   EXPECT_EQ(size / GCIdleTimeHandler::kInitialConservativeScavengeSpeed, time);
    116 }
    117 
    118 
    119 TEST(GCIdleTimeHandler, EstimateScavengeTimeNonZero) {
    120   size_t size = 1 * MB;
    121   size_t speed = 1 * MB;
    122   size_t time = GCIdleTimeHandler::EstimateScavengeTime(size, speed);
    123   EXPECT_EQ(size / speed, time);
    124 }
    125 
    126 
    127 TEST(GCIdleTimeHandler, ScavangeMayHappenSoonInitial) {
    128   size_t available = 100 * KB;
    129   EXPECT_FALSE(GCIdleTimeHandler::ScavangeMayHappenSoon(available, 0));
    130 }
    131 
    132 
    133 TEST(GCIdleTimeHandler, ScavangeMayHappenSoonNonZeroFalse) {
    134   size_t available = (GCIdleTimeHandler::kMaxFrameRenderingIdleTime + 1) * KB;
    135   size_t speed = 1 * KB;
    136   EXPECT_FALSE(GCIdleTimeHandler::ScavangeMayHappenSoon(available, speed));
    137 }
    138 
    139 
    140 TEST(GCIdleTimeHandler, ScavangeMayHappenSoonNonZeroTrue) {
    141   size_t available = GCIdleTimeHandler::kMaxFrameRenderingIdleTime * KB;
    142   size_t speed = 1 * KB;
    143   EXPECT_TRUE(GCIdleTimeHandler::ScavangeMayHappenSoon(available, speed));
    144 }
    145 
    146 
    147 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeIdleTime) {
    148   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    149   heap_state.contexts_disposed = 1;
    150   heap_state.incremental_marking_stopped = true;
    151   size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
    152   int idle_time_ms =
    153       static_cast<int>((heap_state.size_of_objects + speed - 1) / speed);
    154   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    155   EXPECT_EQ(DO_FULL_GC, action.type);
    156 }
    157 
    158 
    159 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) {
    160   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    161   heap_state.contexts_disposed = 1;
    162   heap_state.incremental_marking_stopped = true;
    163   size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
    164   int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed - 1);
    165   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    166   EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
    167 }
    168 
    169 
    170 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) {
    171   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    172   heap_state.contexts_disposed = 1;
    173   size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
    174   int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed - 1);
    175   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    176   EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
    177 }
    178 
    179 
    180 TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) {
    181   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    182   size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
    183   int idle_time_ms = 10;
    184   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    185   EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
    186   EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
    187             static_cast<size_t>(action.parameter));
    188   EXPECT_LT(0, action.parameter);
    189 }
    190 
    191 
    192 TEST_F(GCIdleTimeHandlerTest, IncrementalMarking2) {
    193   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    194   heap_state.incremental_marking_stopped = true;
    195   size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
    196   int idle_time_ms = 10;
    197   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    198   EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
    199   EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
    200             static_cast<size_t>(action.parameter));
    201   EXPECT_LT(0, action.parameter);
    202 }
    203 
    204 
    205 TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) {
    206   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    207   heap_state.incremental_marking_stopped = true;
    208   heap_state.can_start_incremental_marking = false;
    209   size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
    210   int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed - 1);
    211   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    212   EXPECT_EQ(DO_NOTHING, action.type);
    213 }
    214 
    215 
    216 TEST_F(GCIdleTimeHandlerTest, StopEventually1) {
    217   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    218   heap_state.incremental_marking_stopped = true;
    219   heap_state.can_start_incremental_marking = false;
    220   size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
    221   int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed + 1);
    222   for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
    223     GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    224     EXPECT_EQ(DO_FULL_GC, action.type);
    225     handler()->NotifyIdleMarkCompact();
    226   }
    227   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    228   EXPECT_EQ(DONE, action.type);
    229 }
    230 
    231 
    232 TEST_F(GCIdleTimeHandlerTest, StopEventually2) {
    233   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    234   int idle_time_ms = 10;
    235   for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
    236     GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    237     EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
    238     // In this case we emulate incremental marking steps that finish with a
    239     // full gc.
    240     handler()->NotifyIdleMarkCompact();
    241   }
    242   heap_state.can_start_incremental_marking = false;
    243   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    244   EXPECT_EQ(DONE, action.type);
    245 }
    246 
    247 
    248 TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop1) {
    249   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    250   heap_state.incremental_marking_stopped = true;
    251   heap_state.can_start_incremental_marking = false;
    252   size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
    253   int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed + 1);
    254   for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
    255     GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    256     EXPECT_EQ(DO_FULL_GC, action.type);
    257     handler()->NotifyIdleMarkCompact();
    258   }
    259   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    260   EXPECT_EQ(DONE, action.type);
    261   // Emulate mutator work.
    262   for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
    263     handler()->NotifyScavenge();
    264   }
    265   action = handler()->Compute(idle_time_ms, heap_state);
    266   EXPECT_EQ(DO_FULL_GC, action.type);
    267 }
    268 
    269 
    270 TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop2) {
    271   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    272   int idle_time_ms = 10;
    273   for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
    274     GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    275     if (action.type == DONE) break;
    276     EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
    277     // In this case we try to emulate incremental marking steps the finish with
    278     // a full gc.
    279     handler()->NotifyIdleMarkCompact();
    280   }
    281   heap_state.can_start_incremental_marking = false;
    282   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    283   EXPECT_EQ(DONE, action.type);
    284   // Emulate mutator work.
    285   for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
    286     handler()->NotifyScavenge();
    287   }
    288   heap_state.can_start_incremental_marking = true;
    289   action = handler()->Compute(idle_time_ms, heap_state);
    290   EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
    291 }
    292 
    293 
    294 TEST_F(GCIdleTimeHandlerTest, Scavenge) {
    295   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    296   int idle_time_ms = 10;
    297   heap_state.available_new_space_memory =
    298       kNewSpaceAllocationThroughput * idle_time_ms;
    299   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    300   EXPECT_EQ(DO_SCAVENGE, action.type);
    301 }
    302 
    303 
    304 TEST_F(GCIdleTimeHandlerTest, ScavengeAndDone) {
    305   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    306   int idle_time_ms = 10;
    307   heap_state.can_start_incremental_marking = false;
    308   heap_state.incremental_marking_stopped = true;
    309   heap_state.available_new_space_memory =
    310       kNewSpaceAllocationThroughput * idle_time_ms;
    311   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    312   EXPECT_EQ(DO_SCAVENGE, action.type);
    313   heap_state.available_new_space_memory = kNewSpaceCapacity;
    314   action = handler()->Compute(idle_time_ms, heap_state);
    315   EXPECT_EQ(DO_NOTHING, action.type);
    316 }
    317 
    318 
    319 TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) {
    320   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    321   int idle_time_ms = 0;
    322   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    323   EXPECT_EQ(DO_NOTHING, action.type);
    324 }
    325 
    326 
    327 TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeDoNothingButStartIdleRound) {
    328   GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
    329   int idle_time_ms = 10;
    330   for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
    331     GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    332     if (action.type == DONE) break;
    333     EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
    334     // In this case we try to emulate incremental marking steps the finish with
    335     // a full gc.
    336     handler()->NotifyIdleMarkCompact();
    337   }
    338   GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
    339   // Emulate mutator work.
    340   for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
    341     handler()->NotifyScavenge();
    342   }
    343   action = handler()->Compute(0, heap_state);
    344   EXPECT_EQ(DO_NOTHING, action.type);
    345 }
    346 
    347 }  // namespace internal
    348 }  // namespace v8
    349