Line data Source code
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 :
10 : namespace v8 {
11 : namespace internal {
12 :
13 : namespace {
14 :
15 : class GCIdleTimeHandlerTest : public ::testing::Test {
16 : public:
17 15 : GCIdleTimeHandlerTest() = default;
18 15 : ~GCIdleTimeHandlerTest() override = default;
19 :
20 : GCIdleTimeHandler* handler() { return &handler_; }
21 :
22 : GCIdleTimeHeapState DefaultHeapState() {
23 : GCIdleTimeHeapState result;
24 13 : result.contexts_disposed = 0;
25 13 : result.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate;
26 13 : result.incremental_marking_stopped = false;
27 13 : result.size_of_objects = kSizeOfObjects;
28 : return result;
29 : }
30 :
31 : static const size_t kSizeOfObjects = 100 * MB;
32 : static const size_t kMarkCompactSpeed = 200 * KB;
33 : static const size_t kMarkingSpeed = 200 * KB;
34 : static const int kMaxNotifications = 100;
35 :
36 : private:
37 : GCIdleTimeHandler handler_;
38 : };
39 :
40 : } // namespace
41 :
42 :
43 15128 : TEST(GCIdleTimeHandler, EstimateMarkingStepSizeInitial) {
44 1 : size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(1, 0);
45 2 : EXPECT_EQ(
46 : static_cast<size_t>(GCIdleTimeHandler::kInitialConservativeMarkingSpeed *
47 : GCIdleTimeHandler::kConservativeTimeRatio),
48 0 : step_size);
49 1 : }
50 :
51 :
52 15128 : TEST(GCIdleTimeHandler, EstimateMarkingStepSizeNonZero) {
53 : size_t marking_speed_in_bytes_per_millisecond = 100;
54 : size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
55 1 : 1, marking_speed_in_bytes_per_millisecond);
56 2 : EXPECT_EQ(static_cast<size_t>(marking_speed_in_bytes_per_millisecond *
57 : GCIdleTimeHandler::kConservativeTimeRatio),
58 0 : step_size);
59 1 : }
60 :
61 :
62 15128 : TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow1) {
63 : size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
64 1 : 10, std::numeric_limits<size_t>::max());
65 2 : EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
66 0 : step_size);
67 1 : }
68 :
69 :
70 15128 : TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow2) {
71 : size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
72 1 : std::numeric_limits<size_t>::max(), 10);
73 2 : EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
74 0 : step_size);
75 1 : }
76 :
77 :
78 15129 : TEST_F(GCIdleTimeHandlerTest, ShouldDoFinalIncrementalMarkCompact) {
79 : size_t idle_time_ms = 16;
80 2 : EXPECT_TRUE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
81 0 : idle_time_ms, 0, 0));
82 1 : }
83 :
84 :
85 15129 : TEST_F(GCIdleTimeHandlerTest, DontDoFinalIncrementalMarkCompact) {
86 : size_t idle_time_ms = 1;
87 2 : EXPECT_FALSE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
88 0 : idle_time_ms, kSizeOfObjects, kMarkingSpeed));
89 1 : }
90 :
91 :
92 15129 : TEST_F(GCIdleTimeHandlerTest, ContextDisposeLowRate) {
93 1 : if (!handler()->Enabled()) return;
94 : GCIdleTimeHeapState heap_state = DefaultHeapState();
95 1 : heap_state.contexts_disposed = 1;
96 1 : heap_state.incremental_marking_stopped = true;
97 : double idle_time_ms = 0;
98 1 : GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
99 2 : EXPECT_EQ(DO_NOTHING, action.type);
100 : }
101 :
102 :
103 15129 : TEST_F(GCIdleTimeHandlerTest, ContextDisposeHighRate) {
104 1 : if (!handler()->Enabled()) return;
105 : GCIdleTimeHeapState heap_state = DefaultHeapState();
106 1 : heap_state.contexts_disposed = 1;
107 : heap_state.contexts_disposal_rate =
108 1 : GCIdleTimeHandler::kHighContextDisposalRate - 1;
109 1 : heap_state.incremental_marking_stopped = true;
110 : double idle_time_ms = 0;
111 1 : GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
112 2 : EXPECT_EQ(DO_FULL_GC, action.type);
113 : }
114 :
115 :
116 15129 : TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeZeroIdleTime) {
117 1 : if (!handler()->Enabled()) return;
118 : GCIdleTimeHeapState heap_state = DefaultHeapState();
119 1 : heap_state.contexts_disposed = 1;
120 1 : heap_state.contexts_disposal_rate = 1.0;
121 1 : heap_state.incremental_marking_stopped = true;
122 : double idle_time_ms = 0;
123 1 : GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
124 2 : EXPECT_EQ(DO_FULL_GC, action.type);
125 : }
126 :
127 :
128 15129 : TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) {
129 1 : if (!handler()->Enabled()) return;
130 : GCIdleTimeHeapState heap_state = DefaultHeapState();
131 1 : heap_state.contexts_disposed = 1;
132 : heap_state.contexts_disposal_rate =
133 : GCIdleTimeHandler::kHighContextDisposalRate;
134 : size_t speed = kMarkCompactSpeed;
135 : double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1);
136 1 : GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
137 2 : EXPECT_EQ(DO_INCREMENTAL_STEP, action.type);
138 : }
139 :
140 :
141 15129 : TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) {
142 1 : if (!handler()->Enabled()) return;
143 : GCIdleTimeHeapState heap_state = DefaultHeapState();
144 1 : heap_state.contexts_disposed = 1;
145 : heap_state.contexts_disposal_rate =
146 : GCIdleTimeHandler::kHighContextDisposalRate;
147 : size_t speed = kMarkCompactSpeed;
148 : double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1);
149 1 : GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
150 2 : EXPECT_EQ(DO_INCREMENTAL_STEP, action.type);
151 : }
152 :
153 15129 : TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeHeap) {
154 1 : if (!handler()->Enabled()) return;
155 : GCIdleTimeHeapState heap_state = DefaultHeapState();
156 1 : heap_state.contexts_disposed = 1;
157 1 : heap_state.contexts_disposal_rate = 1.0;
158 1 : heap_state.incremental_marking_stopped = true;
159 1 : heap_state.size_of_objects = 101 * MB;
160 : double idle_time_ms = 0;
161 1 : GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
162 2 : EXPECT_EQ(DO_NOTHING, action.type);
163 : }
164 :
165 15129 : TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) {
166 1 : if (!handler()->Enabled()) return;
167 : GCIdleTimeHeapState heap_state = DefaultHeapState();
168 : double idle_time_ms = 10;
169 1 : GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
170 2 : EXPECT_EQ(DO_INCREMENTAL_STEP, action.type);
171 : }
172 :
173 :
174 15129 : TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) {
175 1 : if (!handler()->Enabled()) return;
176 : GCIdleTimeHeapState heap_state = DefaultHeapState();
177 1 : heap_state.incremental_marking_stopped = true;
178 : size_t speed = kMarkCompactSpeed;
179 : double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1);
180 1 : GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
181 2 : EXPECT_EQ(DONE, action.type);
182 : }
183 :
184 :
185 15129 : TEST_F(GCIdleTimeHandlerTest, DoNotStartIncrementalMarking) {
186 1 : if (!handler()->Enabled()) return;
187 : GCIdleTimeHeapState heap_state = DefaultHeapState();
188 1 : heap_state.incremental_marking_stopped = true;
189 : double idle_time_ms = 10.0;
190 1 : GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
191 2 : EXPECT_EQ(DONE, action.type);
192 : }
193 :
194 :
195 15129 : TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop) {
196 1 : if (!handler()->Enabled()) return;
197 : GCIdleTimeHeapState heap_state = DefaultHeapState();
198 1 : heap_state.incremental_marking_stopped = true;
199 : double idle_time_ms = 10.0;
200 1 : GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
201 2 : EXPECT_EQ(DONE, action.type);
202 1 : heap_state.incremental_marking_stopped = false;
203 1 : action = handler()->Compute(idle_time_ms, heap_state);
204 2 : EXPECT_EQ(DO_INCREMENTAL_STEP, action.type);
205 : }
206 :
207 :
208 15129 : TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) {
209 1 : if (!handler()->Enabled()) return;
210 : GCIdleTimeHeapState heap_state = DefaultHeapState();
211 101 : for (int i = 0; i < kMaxNotifications; i++) {
212 100 : GCIdleTimeAction action = handler()->Compute(0, heap_state);
213 200 : EXPECT_EQ(DO_NOTHING, action.type);
214 : }
215 : }
216 :
217 :
218 15129 : TEST_F(GCIdleTimeHandlerTest, SmallIdleTimeNothingToDo) {
219 1 : if (!handler()->Enabled()) return;
220 : GCIdleTimeHeapState heap_state = DefaultHeapState();
221 1 : heap_state.incremental_marking_stopped = true;
222 101 : for (int i = 0; i < kMaxNotifications; i++) {
223 100 : GCIdleTimeAction action = handler()->Compute(10, heap_state);
224 200 : EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type);
225 : }
226 : }
227 :
228 :
229 15129 : TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnIncrementalMarking) {
230 1 : if (!handler()->Enabled()) return;
231 :
232 : // Regression test for crbug.com/489323.
233 : GCIdleTimeHeapState heap_state = DefaultHeapState();
234 :
235 : // Simulate incremental marking stopped and not eligible to start.
236 1 : heap_state.incremental_marking_stopped = true;
237 : double idle_time_ms = 10.0;
238 : // We should return DONE if we cannot start incremental marking.
239 1 : GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
240 2 : EXPECT_EQ(DONE, action.type);
241 : }
242 :
243 : } // namespace internal
244 9075 : } // namespace v8
|