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 78 MemoryReducer::Event ContextDisposedEvent(double time_ms) { 79 MemoryReducer::Event event; 80 event.type = MemoryReducer::kContextDisposed; 81 event.time_ms = time_ms; 82 return event; 83 } 84 85 86 TEST(MemoryReducer, FromDoneToDone) { 87 MemoryReducer::State state0(DoneState()), state1(DoneState()); 88 89 state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(0)); 90 EXPECT_EQ(MemoryReducer::kDone, state1.action); 91 92 state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(0)); 93 EXPECT_EQ(MemoryReducer::kDone, state1.action); 94 95 state1 = MemoryReducer::Step(state0, TimerEventPendingGC(0)); 96 EXPECT_EQ(MemoryReducer::kDone, state1.action); 97 } 98 99 100 TEST(MemoryReducer, FromDoneToWait) { 101 if (!FLAG_incremental_marking) return; 102 103 MemoryReducer::State state0(DoneState()), state1(DoneState()); 104 105 state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2)); 106 EXPECT_EQ(MemoryReducer::kWait, state1.action); 107 EXPECT_EQ(MemoryReducer::kLongDelayMs + 2, state1.next_gc_start_ms); 108 EXPECT_EQ(0, state1.started_gcs); 109 EXPECT_EQ(2, state1.last_gc_time_ms); 110 111 state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2)); 112 EXPECT_EQ(MemoryReducer::kWait, state1.action); 113 EXPECT_EQ(MemoryReducer::kLongDelayMs + 2, state1.next_gc_start_ms); 114 EXPECT_EQ(0, state1.started_gcs); 115 EXPECT_EQ(2, state1.last_gc_time_ms); 116 117 state1 = MemoryReducer::Step(state0, ContextDisposedEvent(0)); 118 EXPECT_EQ(MemoryReducer::kWait, state1.action); 119 EXPECT_EQ(MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 120 EXPECT_EQ(0, state1.started_gcs); 121 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 122 } 123 124 125 TEST(MemoryReducer, FromWaitToWait) { 126 if (!FLAG_incremental_marking) return; 127 128 MemoryReducer::State state0(WaitState(2, 1000.0)), state1(DoneState()); 129 130 state1 = MemoryReducer::Step(state0, ContextDisposedEvent(2000)); 131 EXPECT_EQ(MemoryReducer::kWait, state1.action); 132 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 133 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 134 135 state1 = MemoryReducer::Step( 136 state0, TimerEventLowAllocationRate(state0.next_gc_start_ms - 1)); 137 EXPECT_EQ(MemoryReducer::kWait, state1.action); 138 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 139 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 140 141 state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); 142 EXPECT_EQ(MemoryReducer::kWait, state1.action); 143 EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 144 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 145 146 state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000)); 147 EXPECT_EQ(MemoryReducer::kWait, state1.action); 148 EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 149 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 150 151 state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000)); 152 EXPECT_EQ(MemoryReducer::kWait, state1.action); 153 EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 154 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 155 EXPECT_EQ(2000, state1.last_gc_time_ms); 156 157 state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000)); 158 EXPECT_EQ(MemoryReducer::kWait, state1.action); 159 EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 160 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 161 EXPECT_EQ(2000, state1.last_gc_time_ms); 162 163 state0.last_gc_time_ms = 0; 164 state1 = MemoryReducer::Step( 165 state0, 166 TimerEventHighAllocationRate(MemoryReducer::kWatchdogDelayMs + 1)); 167 EXPECT_EQ(MemoryReducer::kWait, state1.action); 168 EXPECT_EQ(MemoryReducer::kWatchdogDelayMs + 1 + MemoryReducer::kLongDelayMs, 169 state1.next_gc_start_ms); 170 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 171 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 172 173 state0.last_gc_time_ms = 1; 174 state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); 175 EXPECT_EQ(MemoryReducer::kWait, state1.action); 176 EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); 177 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 178 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 179 } 180 181 182 TEST(MemoryReducer, FromWaitToRun) { 183 if (!FLAG_incremental_marking) return; 184 185 MemoryReducer::State state0(WaitState(0, 1000.0)), state1(DoneState()); 186 187 state1 = MemoryReducer::Step( 188 state0, TimerEventLowAllocationRate(state0.next_gc_start_ms + 1)); 189 EXPECT_EQ(MemoryReducer::kRun, state1.action); 190 EXPECT_EQ(0, state1.next_gc_start_ms); 191 EXPECT_EQ(state0.started_gcs + 1, state1.started_gcs); 192 193 state1 = MemoryReducer::Step( 194 state0, 195 TimerEventHighAllocationRate(MemoryReducer::kWatchdogDelayMs + 2)); 196 EXPECT_EQ(MemoryReducer::kRun, state1.action); 197 EXPECT_EQ(0, state1.next_gc_start_ms); 198 EXPECT_EQ(state0.started_gcs + 1, state1.started_gcs); 199 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 200 } 201 202 203 TEST(MemoryReducer, FromWaitToDone) { 204 if (!FLAG_incremental_marking) return; 205 206 MemoryReducer::State state0(WaitState(2, 0.0)), state1(DoneState()); 207 208 state0.started_gcs = MemoryReducer::kMaxNumberOfGCs; 209 210 state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(2000)); 211 EXPECT_EQ(MemoryReducer::kDone, state1.action); 212 EXPECT_EQ(0, state1.next_gc_start_ms); 213 EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); 214 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 215 216 state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); 217 EXPECT_EQ(MemoryReducer::kDone, state1.action); 218 EXPECT_EQ(0, state1.next_gc_start_ms); 219 EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); 220 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 221 222 state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000)); 223 EXPECT_EQ(MemoryReducer::kDone, state1.action); 224 EXPECT_EQ(0, state1.next_gc_start_ms); 225 EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); 226 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 227 } 228 229 230 TEST(MemoryReducer, FromRunToRun) { 231 if (!FLAG_incremental_marking) return; 232 233 MemoryReducer::State state0(RunState(1, 0.0)), state1(DoneState()); 234 235 state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(2000)); 236 EXPECT_EQ(MemoryReducer::kRun, state1.action); 237 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 238 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 239 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 240 241 state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000)); 242 EXPECT_EQ(MemoryReducer::kRun, state1.action); 243 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 244 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 245 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 246 247 state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000)); 248 EXPECT_EQ(MemoryReducer::kRun, state1.action); 249 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 250 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 251 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 252 253 state1 = MemoryReducer::Step(state0, ContextDisposedEvent(2000)); 254 EXPECT_EQ(MemoryReducer::kRun, state1.action); 255 EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); 256 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 257 EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); 258 } 259 260 261 TEST(MemoryReducer, FromRunToDone) { 262 if (!FLAG_incremental_marking) return; 263 264 MemoryReducer::State state0(RunState(2, 0.0)), state1(DoneState()); 265 266 state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000)); 267 EXPECT_EQ(MemoryReducer::kDone, state1.action); 268 EXPECT_EQ(0, state1.next_gc_start_ms); 269 EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs); 270 EXPECT_EQ(2000, state1.last_gc_time_ms); 271 272 state0.started_gcs = MemoryReducer::kMaxNumberOfGCs; 273 274 state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000)); 275 EXPECT_EQ(MemoryReducer::kDone, state1.action); 276 EXPECT_EQ(0, state1.next_gc_start_ms); 277 EXPECT_EQ(2000, state1.last_gc_time_ms); 278 } 279 280 281 TEST(MemoryReducer, FromRunToWait) { 282 if (!FLAG_incremental_marking) return; 283 284 MemoryReducer::State state0(RunState(2, 0.0)), state1(DoneState()); 285 286 state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000)); 287 EXPECT_EQ(MemoryReducer::kWait, state1.action); 288 EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms); 289 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 290 EXPECT_EQ(2000, state1.last_gc_time_ms); 291 292 state0.started_gcs = 1; 293 294 state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000)); 295 EXPECT_EQ(MemoryReducer::kWait, state1.action); 296 EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms); 297 EXPECT_EQ(state0.started_gcs, state1.started_gcs); 298 EXPECT_EQ(2000, state1.last_gc_time_ms); 299 } 300 301 } // namespace internal 302 } // namespace v8 303