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 GCIdleTimeHeapState DefaultHeapState() { 23 GCIdleTimeHeapState result; 24 result.contexts_disposed = 0; 25 result.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate; 26 result.incremental_marking_stopped = false; 27 return result; 28 } 29 30 static const size_t kSizeOfObjects = 100 * MB; 31 static const size_t kMarkCompactSpeed = 200 * KB; 32 static const size_t kMarkingSpeed = 200 * KB; 33 static const int kMaxNotifications = 100; 34 35 private: 36 GCIdleTimeHandler handler_; 37 }; 38 39 } // namespace 40 41 42 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeInitial) { 43 size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(1, 0); 44 EXPECT_EQ( 45 static_cast<size_t>(GCIdleTimeHandler::kInitialConservativeMarkingSpeed * 46 GCIdleTimeHandler::kConservativeTimeRatio), 47 step_size); 48 } 49 50 51 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeNonZero) { 52 size_t marking_speed_in_bytes_per_millisecond = 100; 53 size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize( 54 1, marking_speed_in_bytes_per_millisecond); 55 EXPECT_EQ(static_cast<size_t>(marking_speed_in_bytes_per_millisecond * 56 GCIdleTimeHandler::kConservativeTimeRatio), 57 step_size); 58 } 59 60 61 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow1) { 62 size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize( 63 10, std::numeric_limits<size_t>::max()); 64 EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize), 65 step_size); 66 } 67 68 69 TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow2) { 70 size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize( 71 std::numeric_limits<size_t>::max(), 10); 72 EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize), 73 step_size); 74 } 75 76 77 TEST_F(GCIdleTimeHandlerTest, ShouldDoFinalIncrementalMarkCompact) { 78 size_t idle_time_ms = 16; 79 EXPECT_TRUE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact( 80 idle_time_ms, 0, 0)); 81 } 82 83 84 TEST_F(GCIdleTimeHandlerTest, DontDoFinalIncrementalMarkCompact) { 85 size_t idle_time_ms = 1; 86 EXPECT_FALSE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact( 87 idle_time_ms, kSizeOfObjects, kMarkingSpeed)); 88 } 89 90 91 TEST_F(GCIdleTimeHandlerTest, ContextDisposeLowRate) { 92 GCIdleTimeHeapState heap_state = DefaultHeapState(); 93 heap_state.contexts_disposed = 1; 94 heap_state.incremental_marking_stopped = true; 95 double idle_time_ms = 0; 96 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 97 EXPECT_EQ(DO_NOTHING, action.type); 98 } 99 100 101 TEST_F(GCIdleTimeHandlerTest, ContextDisposeHighRate) { 102 GCIdleTimeHeapState heap_state = DefaultHeapState(); 103 heap_state.contexts_disposed = 1; 104 heap_state.contexts_disposal_rate = 105 GCIdleTimeHandler::kHighContextDisposalRate - 1; 106 heap_state.incremental_marking_stopped = true; 107 double idle_time_ms = 0; 108 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 109 EXPECT_EQ(DO_FULL_GC, action.type); 110 } 111 112 113 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeZeroIdleTime) { 114 GCIdleTimeHeapState heap_state = DefaultHeapState(); 115 heap_state.contexts_disposed = 1; 116 heap_state.contexts_disposal_rate = 1.0; 117 heap_state.incremental_marking_stopped = true; 118 double idle_time_ms = 0; 119 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 120 EXPECT_EQ(DO_FULL_GC, action.type); 121 } 122 123 124 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) { 125 GCIdleTimeHeapState heap_state = DefaultHeapState(); 126 heap_state.contexts_disposed = 1; 127 heap_state.contexts_disposal_rate = 128 GCIdleTimeHandler::kHighContextDisposalRate; 129 size_t speed = kMarkCompactSpeed; 130 double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1); 131 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 132 EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); 133 } 134 135 136 TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) { 137 GCIdleTimeHeapState heap_state = DefaultHeapState(); 138 heap_state.contexts_disposed = 1; 139 heap_state.contexts_disposal_rate = 140 GCIdleTimeHandler::kHighContextDisposalRate; 141 size_t speed = kMarkCompactSpeed; 142 double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1); 143 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 144 EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); 145 } 146 147 148 TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) { 149 GCIdleTimeHeapState heap_state = DefaultHeapState(); 150 double idle_time_ms = 10; 151 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 152 EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); 153 } 154 155 156 TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) { 157 GCIdleTimeHeapState heap_state = DefaultHeapState(); 158 heap_state.incremental_marking_stopped = true; 159 size_t speed = kMarkCompactSpeed; 160 double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1); 161 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 162 EXPECT_EQ(DONE, action.type); 163 } 164 165 166 TEST_F(GCIdleTimeHandlerTest, DoNotStartIncrementalMarking) { 167 GCIdleTimeHeapState heap_state = DefaultHeapState(); 168 heap_state.incremental_marking_stopped = true; 169 double idle_time_ms = 10.0; 170 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 171 EXPECT_EQ(DONE, action.type); 172 } 173 174 175 TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop) { 176 GCIdleTimeHeapState heap_state = DefaultHeapState(); 177 heap_state.incremental_marking_stopped = true; 178 double idle_time_ms = 10.0; 179 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 180 EXPECT_EQ(DONE, action.type); 181 heap_state.incremental_marking_stopped = false; 182 action = handler()->Compute(idle_time_ms, heap_state); 183 EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); 184 } 185 186 187 TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) { 188 GCIdleTimeHeapState heap_state = DefaultHeapState(); 189 for (int i = 0; i < kMaxNotifications; i++) { 190 GCIdleTimeAction action = handler()->Compute(0, heap_state); 191 EXPECT_EQ(DO_NOTHING, action.type); 192 } 193 } 194 195 196 TEST_F(GCIdleTimeHandlerTest, SmallIdleTimeNothingToDo) { 197 GCIdleTimeHeapState heap_state = DefaultHeapState(); 198 heap_state.incremental_marking_stopped = true; 199 for (int i = 0; i < kMaxNotifications; i++) { 200 GCIdleTimeAction action = handler()->Compute(10, heap_state); 201 EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type); 202 } 203 } 204 205 206 TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnIncrementalMarking) { 207 // Regression test for crbug.com/489323. 208 GCIdleTimeHeapState heap_state = DefaultHeapState(); 209 210 // Simulate incremental marking stopped and not eligible to start. 211 heap_state.incremental_marking_stopped = true; 212 double idle_time_ms = 10.0; 213 // We should return DONE if we cannot start incremental marking. 214 GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); 215 EXPECT_EQ(DONE, action.type); 216 } 217 218 } // namespace internal 219 } // namespace v8 220