• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DoneState()14 MemoryReducer::State DoneState() {
15   return MemoryReducer::State(MemoryReducer::kDone, 0, 0.0, 1.0);
16 }
17 
18 
WaitState(int started_gcs,double next_gc_start_ms)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 
RunState(int started_gcs,double next_gc_start_ms)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 
MarkCompactEvent(double time_ms,bool next_gc_likely_to_collect_more)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 
MarkCompactEventGarbageLeft(double time_ms)41 MemoryReducer::Event MarkCompactEventGarbageLeft(double time_ms) {
42   return MarkCompactEvent(time_ms, true);
43 }
44 
45 
MarkCompactEventNoGarbageLeft(double time_ms)46 MemoryReducer::Event MarkCompactEventNoGarbageLeft(double time_ms) {
47   return MarkCompactEvent(time_ms, false);
48 }
49 
50 
TimerEvent(double time_ms,bool should_start_incremental_gc,bool can_start_incremental_gc)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 
TimerEventLowAllocationRate(double time_ms)63 MemoryReducer::Event TimerEventLowAllocationRate(double time_ms) {
64   return TimerEvent(time_ms, true, true);
65 }
66 
67 
TimerEventHighAllocationRate(double time_ms)68 MemoryReducer::Event TimerEventHighAllocationRate(double time_ms) {
69   return TimerEvent(time_ms, false, true);
70 }
71 
72 
TimerEventPendingGC(double time_ms)73 MemoryReducer::Event TimerEventPendingGC(double time_ms) {
74   return TimerEvent(time_ms, true, false);
75 }
76 
77 
ContextDisposedEvent(double time_ms)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 
TEST(MemoryReducer,FromDoneToDone)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 
TEST(MemoryReducer,FromDoneToWait)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 
TEST(MemoryReducer,FromWaitToWait)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 
TEST(MemoryReducer,FromWaitToRun)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 
TEST(MemoryReducer,FromWaitToDone)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 
TEST(MemoryReducer,FromRunToRun)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 
TEST(MemoryReducer,FromRunToDone)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 
TEST(MemoryReducer,FromRunToWait)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