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/flags.h" 8 #include "src/heap/memory-reducer.h" 9 #include "testing/gtest/include/gtest/gtest.h" 10 11 namespace v8 { 12 namespace internal { 13 14 MemoryReducer::State DoneState() { 15 return MemoryReducer::State(MemoryReducer::kDone, 0, 0.0, 1.0); 16 } 17 18 19 MemoryReducer::State WaitState(int started_gcs, double next_gc_start_ms) { 20 return MemoryReducer::State(MemoryReducer::kWait, started_gcs, 21 next_gc_start_ms, 1.0); 22 } 23 24 25 MemoryReducer::State RunState(int started_gcs, double next_gc_start_ms) { 26 return MemoryReducer::State(MemoryReducer::kRun, started_gcs, 27 next_gc_start_ms, 1.0); 28 } 29 30 31 MemoryReducer::Event MarkCompactEvent(double time_ms, 32 bool next_gc_likely_to_collect_more) { 33 MemoryReducer::Event event; 34 event.type = MemoryReducer::kMarkCompact; 35 event.time_ms = time_ms; 36 event.next_gc_likely_to_collect_more = next_gc_likely_to_collect_more; 37 return event; 38 } 39 40 41 MemoryReducer::Event MarkCompactEventGarbageLeft(double time_ms) { 42 return MarkCompactEvent(time_ms, true); 43 } 44 45 46 MemoryReducer::Event MarkCompactEventNoGarbageLeft(double time_ms) { 47 return MarkCompactEvent(time_ms, false); 48 } 49 50 51 MemoryReducer::Event TimerEvent(double time_ms, 52 bool should_start_incremental_gc, 53 bool can_start_incremental_gc) { 54 MemoryReducer::Event event; 55 event.type = MemoryReducer::kTimer; 56 event.time_ms = time_ms; 57 event.should_start_incremental_gc = should_start_incremental_gc; 58 event.can_start_incremental_gc = can_start_incremental_gc; 59 return event; 60 } 61 62 63 MemoryReducer::Event TimerEventLowAllocationRate(double time_ms) { 64 return TimerEvent(time_ms, true, true); 65 } 66 67 68 MemoryReducer::Event TimerEventHighAllocationRate(double time_ms) { 69 return TimerEvent(time_ms, false, true); 70 } 71 72 73 MemoryReducer::Event TimerEventPendingGC(double time_ms) { 74 return TimerEvent(time_ms, true, false); 75 } 76 77 MemoryReducer::Event PossibleGarbageEvent(double time_ms) { 78 MemoryReducer::Event event; 79 event.type = MemoryReducer::kPossibleGarbage; 80 event.time_ms = time_ms; 81 return event; 82 } 83 84 85 TEST(MemoryReducer, FromDoneToDone) { 86 MemoryReducer::State state0(DoneState()), state1(DoneState()); 87 88 state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(0)); 89 EXPECT_EQ(MemoryReducer::kDone, state1.action); 90 91 state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(0)); 92 EXPECT_EQ(MemoryReducer::kDone, state1.action); 93 94 state1 = MemoryReducer::Step(state0, TimerEventPendingGC(0)); 95 EXPECT_EQ(MemoryReducer::kDone, state1.action); 96 } 97 98 99 TEST(MemoryReducer, FromDoneToWait) { 100 if (!FLAG_incremental_marking) return; 101 102 MemoryReducer::State state0(DoneState()), state1(DoneState()); 103 104 state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2)); 105 EXPECT_EQ(MemoryReducer::kWait, state1.action); 106 EXPECT_EQ(MemoryReducer::kLongDelayMs + 2, state1.next_gc_start_ms); 107 EXPECT_EQ(0, state1.started_gcs); 108 EXPECT_EQ(2, state1.last_gc_time_ms); 109 110 state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2)); 111 EXPECT_EQ(MemoryReducer::kWait, state1.action); 112 EXPECT_EQ(MemoryReducer::kLongDelayMs + 2, state1.next_gc_start_ms); 113 EXPECT_EQ(0, state1.started_gcs); 114 EXPECT_EQ(2, state1.last_gc_time_ms); 115 116 state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(0)); 117 EXPECT_EQ(MemoryReducer::kWait, state1.action); 118 EXPECT_EQ(MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 119 EXPECT_EQ(0, state1.started_gcs); 120 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 121 } 122 123 124 TEST(MemoryReducer, FromWaitToWait) { 125 if (!FLAG_incremental_marking) return; 126 127 MemoryReducer::State state0(WaitState(2, 1000.0)), state1(DoneState()); 128 129 state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(2000)); 130 EXPECT_EQ(MemoryReducer::kWait, state1.action); 131 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 132 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 133 134 state1 = MemoryReducer::Step( 135 state0, TimerEventLowAllocationRate(state0.next_gc_start_ms - 1)); 136 EXPECT_EQ(MemoryReducer::kWait, state1.action); 137 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 138 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 139 140 state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); 141 EXPECT_EQ(MemoryReducer::kWait, state1.action); 142 EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 143 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 144 145 state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000)); 146 EXPECT_EQ(MemoryReducer::kWait, state1.action); 147 EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 148 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 149 150 state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000)); 151 EXPECT_EQ(MemoryReducer::kWait, state1.action); 152 EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 153 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 154 EXPECT_EQ(2000, state1.last_gc_time_ms); 155 156 state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000)); 157 EXPECT_EQ(MemoryReducer::kWait, state1.action); 158 EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 159 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 160 EXPECT_EQ(2000, state1.last_gc_time_ms); 161 162 state0.last_gc_time_ms = 0; 163 state1 = MemoryReducer::Step( 164 state0, 165 TimerEventHighAllocationRate(MemoryReducer::kWatchdogDelayMs + 1)); 166 EXPECT_EQ(MemoryReducer::kWait, state1.action); 167 EXPECT_EQ(MemoryReducer::kWatchdogDelayMs + 1 + MemoryReducer::kLongDelayMs, 168 state1.next_gc_start_ms); 169 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 170 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 171 172 state0.last_gc_time_ms = 1; 173 state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); 174 EXPECT_EQ(MemoryReducer::kWait, state1.action); 175 EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 176 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 177 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 178 } 179 180 181 TEST(MemoryReducer, FromWaitToRun) { 182 if (!FLAG_incremental_marking) return; 183 184 MemoryReducer::State state0(WaitState(0, 1000.0)), state1(DoneState()); 185 186 state1 = MemoryReducer::Step( 187 state0, TimerEventLowAllocationRate(state0.next_gc_start_ms + 1)); 188 EXPECT_EQ(MemoryReducer::kRun, state1.action); 189 EXPECT_EQ(0, state1.next_gc_start_ms); 190 EXPECT_EQ(state0.started_gcs + 1, state1.started_gcs); 191 192 state1 = MemoryReducer::Step( 193 state0, 194 TimerEventHighAllocationRate(MemoryReducer::kWatchdogDelayMs + 2)); 195 EXPECT_EQ(MemoryReducer::kRun, state1.action); 196 EXPECT_EQ(0, state1.next_gc_start_ms); 197 EXPECT_EQ(state0.started_gcs + 1, state1.started_gcs); 198 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 199 } 200 201 202 TEST(MemoryReducer, FromWaitToDone) { 203 if (!FLAG_incremental_marking) return; 204 205 MemoryReducer::State state0(WaitState(2, 0.0)), state1(DoneState()); 206 207 state0.started_gcs = MemoryReducer::kMaxNumberOfGCs; 208 209 state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(2000)); 210 EXPECT_EQ(MemoryReducer::kDone, state1.action); 211 EXPECT_EQ(0, state1.next_gc_start_ms); 212 EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); 213 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 214 215 state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); 216 EXPECT_EQ(MemoryReducer::kDone, state1.action); 217 EXPECT_EQ(0, state1.next_gc_start_ms); 218 EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); 219 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 220 221 state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000)); 222 EXPECT_EQ(MemoryReducer::kDone, state1.action); 223 EXPECT_EQ(0, state1.next_gc_start_ms); 224 EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); 225 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 226 } 227 228 229 TEST(MemoryReducer, FromRunToRun) { 230 if (!FLAG_incremental_marking) return; 231 232 MemoryReducer::State state0(RunState(1, 0.0)), state1(DoneState()); 233 234 state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(2000)); 235 EXPECT_EQ(MemoryReducer::kRun, state1.action); 236 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 237 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 238 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 239 240 state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); 241 EXPECT_EQ(MemoryReducer::kRun, state1.action); 242 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 243 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 244 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 245 246 state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000)); 247 EXPECT_EQ(MemoryReducer::kRun, state1.action); 248 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 249 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 250 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 251 252 state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(2000)); 253 EXPECT_EQ(MemoryReducer::kRun, state1.action); 254 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 255 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 256 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 257 } 258 259 260 TEST(MemoryReducer, FromRunToDone) { 261 if (!FLAG_incremental_marking) return; 262 263 MemoryReducer::State state0(RunState(2, 0.0)), state1(DoneState()); 264 265 state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000)); 266 EXPECT_EQ(MemoryReducer::kDone, state1.action); 267 EXPECT_EQ(0, state1.next_gc_start_ms); 268 EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); 269 EXPECT_EQ(2000, state1.last_gc_time_ms); 270 271 state0.started_gcs = MemoryReducer::kMaxNumberOfGCs; 272 273 state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000)); 274 EXPECT_EQ(MemoryReducer::kDone, state1.action); 275 EXPECT_EQ(0, state1.next_gc_start_ms); 276 EXPECT_EQ(2000, state1.last_gc_time_ms); 277 } 278 279 280 TEST(MemoryReducer, FromRunToWait) { 281 if (!FLAG_incremental_marking) return; 282 283 MemoryReducer::State state0(RunState(2, 0.0)), state1(DoneState()); 284 285 state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000)); 286 EXPECT_EQ(MemoryReducer::kWait, state1.action); 287 EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms); 288 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 289 EXPECT_EQ(2000, state1.last_gc_time_ms); 290 291 state0.started_gcs = 1; 292 293 state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000)); 294 EXPECT_EQ(MemoryReducer::kWait, state1.action); 295 EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms); 296 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 297 EXPECT_EQ(2000, state1.last_gc_time_ms); 298 } 299 300 } // namespace internal 301 } // namespace v8 302