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 10namespace v8 { 11namespace internal { 12 13namespace { 14 15class 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 53TEST(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 62TEST(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 72TEST(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 80TEST(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 88TEST(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 96TEST(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 104TEST(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 112TEST(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 119TEST(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 127TEST(GCIdleTimeHandler, ScavangeMayHappenSoonInitial) { 128 size_t available = 100 * KB; 129 EXPECT_FALSE(GCIdleTimeHandler::ScavangeMayHappenSoon(available, 0)); 130} 131 132 133TEST(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 140TEST(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 147TEST_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 159TEST_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 170TEST_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 180TEST_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 192TEST_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 205TEST_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 216TEST_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 232TEST_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 248TEST_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 270TEST_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 294TEST_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 304TEST_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 319TEST_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 327TEST_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