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