1 /**
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <gtest/gtest.h>
17 #include "libpandabase/utils/utils.h"
18 #include "runtime/mem/gc/g1/g1_analytics.h"
19 #include "runtime/include/runtime_options.h"
20 #include "runtime/include/runtime.h"
21
22 namespace ark::mem {
23 class G1AnalyticsTest : public testing::Test {
24 public:
G1AnalyticsTest()25 G1AnalyticsTest()
26 {
27 RuntimeOptions options;
28 options.SetHeapSizeLimit(HEAP_SIZE);
29 options.SetShouldLoadBootPandaFiles(false);
30 options.SetShouldInitializeIntrinsics(false);
31 options.SetGcType("epsilon");
32 Runtime::Create(options);
33 for (size_t i = 0; i < ALL_REGIONS_NUM; i++) {
34 regions_.emplace_back(nullptr, 0, 0);
35 }
36 }
37
~G1AnalyticsTest()38 ~G1AnalyticsTest() override
39 {
40 Runtime::Destroy();
41 }
42
43 NO_COPY_SEMANTIC(G1AnalyticsTest);
44 NO_MOVE_SEMANTIC(G1AnalyticsTest);
45
CreateCollectionSet(size_t edenLength,size_t oldLength=0)46 CollectionSet CreateCollectionSet(size_t edenLength, size_t oldLength = 0)
47 {
48 ASSERT(edenLength + oldLength < ALL_REGIONS_NUM);
49 PandaVector<Region *> vector;
50 auto it = regions_.begin();
51 for (size_t i = 0; i < edenLength; ++it, ++i) {
52 vector.push_back(&*it);
53 }
54 auto cs = CollectionSet(vector);
55 for (size_t i = 0; i < oldLength; ++it, ++i) {
56 auto ®ion = *it;
57 region.AddFlag(RegionFlag::IS_OLD);
58 cs.AddRegion(®ion);
59 }
60 return cs;
61 }
62
63 static constexpr uint64_t START_TIME = 1686312829587000000U;
64
65 private:
66 static constexpr size_t ALL_REGIONS_NUM = 32;
67 static constexpr size_t HEAP_SIZE = 64_MB;
68 std::list<Region> regions_;
69 };
70
FillAnalyticsUndefinedBehaviorTest(G1Analytics & analytics,const CollectionSet & collectionSet,uint64_t now)71 static void FillAnalyticsUndefinedBehaviorTest(G1Analytics &analytics, const CollectionSet &collectionSet, uint64_t now)
72 {
73 analytics.ReportCollectionStart(now);
74 {
75 const size_t remsetSize = 100;
76 const size_t remsetRefsCount = 1000;
77 analytics.ReportRemsetSize(remsetSize, remsetRefsCount);
78 }
79 {
80 const uint64_t delta = 200'000;
81 analytics.ReportScanDirtyCardsStart(now + delta);
82 }
83 {
84 const uint64_t delta = 250'000;
85 const size_t dirtyCardsCount = 2;
86 analytics.ReportScanDirtyCardsEnd(now + delta, dirtyCardsCount);
87 }
88 {
89 const uint64_t delta = 1'000'000;
90 analytics.ReportMarkingStart(now + delta);
91 }
92 {
93 const uint64_t delta = 2'000'000;
94 const size_t remsetRefsCount = 10000;
95 analytics.ReportMarkingEnd(now + delta, remsetRefsCount);
96 }
97 {
98 const uint64_t delta = 3'000'000;
99 analytics.ReportEvacuationStart(now + delta);
100 }
101 {
102 const uint64_t delta = 6'000'000;
103 analytics.ReportEvacuationEnd(now + delta);
104 analytics.ReportUpdateRefsStart(now + delta);
105 }
106 {
107 const uint64_t delta = 7'000'000;
108 analytics.ReportUpdateRefsEnd(now + delta);
109 }
110 {
111 const uint64_t delta = 10'000'000;
112 analytics.ReportCollectionEnd(GCTaskCause::YOUNG_GC_CAUSE, now + delta, collectionSet);
113 }
114 }
115
TEST_F(G1AnalyticsTest,UndefinedBehaviorTest)116 TEST_F(G1AnalyticsTest, UndefinedBehaviorTest)
117 {
118 const size_t edenLength = 16;
119 uint64_t now = START_TIME;
120 const auto startTimeDelta = -20'000'000;
121 auto startTime = now + startTimeDelta;
122 G1Analytics analytics(startTime);
123 ASSERT_EQ(0, analytics.PredictYoungCollectionTimeInMicros(edenLength));
124
125 auto collectionSet = CreateCollectionSet(edenLength);
126 FillAnalyticsUndefinedBehaviorTest(analytics, collectionSet, now);
127
128 const uint64_t expectedTime = 7'000;
129 ASSERT_EQ(expectedTime, analytics.PredictYoungCollectionTimeInMicros(edenLength));
130 }
131
FillAnalyticsPause0AllPromotedUndefinedBehaviorTest(G1Analytics & analytics,const CollectionSet & collectionSet,uint64_t now)132 static void FillAnalyticsPause0AllPromotedUndefinedBehaviorTest(G1Analytics &analytics,
133 const CollectionSet &collectionSet, uint64_t now)
134 {
135 analytics.ReportCollectionStart(now);
136 {
137 const size_t remsetSize = 100;
138 const size_t remsetRefsCount = 1000;
139 analytics.ReportRemsetSize(remsetSize, remsetRefsCount);
140 }
141 {
142 const uint64_t delta = 200'000;
143 analytics.ReportScanDirtyCardsStart(now + delta);
144 }
145 {
146 const uint64_t delta = 250'000;
147 const size_t dirtyCardsCount = 2;
148 analytics.ReportScanDirtyCardsEnd(now + delta, dirtyCardsCount);
149 }
150 {
151 const uint64_t delta = 1'000'000;
152 analytics.ReportMarkingStart(now + delta);
153 }
154 {
155 const uint64_t delta = 2'000'000;
156 const size_t remsetRefsCount = 12000;
157 analytics.ReportMarkingEnd(now + delta, remsetRefsCount);
158 }
159 {
160 const uint64_t delta = 3'000'000;
161 analytics.ReportEvacuationStart(now + delta);
162 }
163 {
164 const uint64_t delta = 6'000'000;
165 analytics.ReportEvacuationEnd(now + delta);
166 analytics.ReportUpdateRefsStart(now + delta);
167 }
168 {
169 const uint64_t delta = 7'000'000;
170 analytics.ReportUpdateRefsEnd(now + delta);
171 }
172 for (size_t i = 0; i < collectionSet.Young().size(); i++) {
173 analytics.ReportPromotedRegion();
174 }
175 {
176 const uint64_t delta = 10'000'000;
177 analytics.ReportCollectionEnd(GCTaskCause::YOUNG_GC_CAUSE, now + delta, collectionSet);
178 }
179 }
180
FillAnalyticsPause1AllPromotedUndefinedBehaviorTest(G1Analytics & analytics,const CollectionSet & collectionSet,uint64_t now)181 static void FillAnalyticsPause1AllPromotedUndefinedBehaviorTest(G1Analytics &analytics,
182 const CollectionSet &collectionSet, uint64_t now)
183 {
184 analytics.ReportCollectionStart(now);
185 {
186 const size_t liveObjects = 32000;
187 analytics.ReportLiveObjects(liveObjects);
188 }
189 {
190 const size_t remsetSize = 100;
191 const size_t remsetRefsCount = 1000;
192 analytics.ReportRemsetSize(remsetSize, remsetRefsCount);
193 }
194 {
195 const uint64_t delta = 200'000;
196 analytics.ReportScanDirtyCardsStart(now + delta);
197 }
198 {
199 const uint64_t delta = 250'000;
200 const size_t dirtyCardsCount = 2;
201 analytics.ReportScanDirtyCardsEnd(now + delta, dirtyCardsCount);
202 }
203 {
204 const uint64_t delta = 1'000'000;
205 analytics.ReportMarkingStart(now + delta);
206 }
207 {
208 const uint64_t delta = 2'000'000;
209 const size_t remsetRefsCount = 11000;
210 analytics.ReportMarkingEnd(now + delta, remsetRefsCount);
211 }
212 {
213 const uint64_t delta = 3'000'000;
214 analytics.ReportEvacuationStart(now + delta);
215 }
216 {
217 const uint64_t delta = 6'000'000;
218 analytics.ReportEvacuationEnd(now + delta);
219 analytics.ReportUpdateRefsStart(now + delta);
220 }
221 {
222 const uint64_t delta = 7'000'000;
223 analytics.ReportUpdateRefsEnd(now + delta);
224 }
225 {
226 const uint64_t delta = 10'000'000;
227 analytics.ReportCollectionEnd(GCTaskCause::YOUNG_GC_CAUSE, now + delta, collectionSet);
228 }
229 }
230
TEST_F(G1AnalyticsTest,AllPromotedUndefinedBehaviorTest)231 TEST_F(G1AnalyticsTest, AllPromotedUndefinedBehaviorTest)
232 {
233 uint64_t now = START_TIME;
234 const auto startTimeDelta = -20'000'000;
235 auto startTime = now + startTimeDelta;
236 const size_t edenLength = 16;
237 G1Analytics analytics(startTime);
238 ASSERT_EQ(0, analytics.PredictYoungCollectionTimeInMicros(edenLength));
239
240 auto collectionSet = CreateCollectionSet(edenLength);
241 FillAnalyticsPause0AllPromotedUndefinedBehaviorTest(analytics, collectionSet, now);
242 {
243 const uint64_t expectedTime = 7'800;
244 ASSERT_EQ(expectedTime, analytics.PredictYoungCollectionTimeInMicros(edenLength));
245 }
246
247 const uint64_t nextPauseDelta = 20'000'000;
248 now += nextPauseDelta;
249
250 FillAnalyticsPause1AllPromotedUndefinedBehaviorTest(analytics, collectionSet, now);
251
252 {
253 const uint64_t expectedTime = 7'732;
254 ASSERT_EQ(expectedTime, analytics.PredictYoungCollectionTimeInMicros(edenLength));
255 }
256 }
257
FillAnalyticsPause0PredictionTest(G1Analytics & analytics,const CollectionSet & collectionSet,uint64_t now)258 static void FillAnalyticsPause0PredictionTest(G1Analytics &analytics, const CollectionSet &collectionSet, uint64_t now)
259 {
260 analytics.ReportCollectionStart(now);
261 {
262 const size_t remsetSize = 100;
263 const size_t remsetRefsCount = 1000;
264 analytics.ReportRemsetSize(remsetSize, remsetRefsCount);
265 }
266 {
267 const uint64_t delta = 200'000;
268 analytics.ReportScanDirtyCardsStart(now + delta);
269 }
270 {
271 const uint64_t delta = 250'000;
272 const size_t dirtyCardsCount = 2;
273 analytics.ReportScanDirtyCardsEnd(now + delta, dirtyCardsCount);
274 }
275 {
276 const uint64_t delta = 1'000'000;
277 analytics.ReportMarkingStart(now + delta);
278 }
279 {
280 const uint64_t delta = 2'000'000;
281 const size_t remsetRefsCount = 12000;
282 analytics.ReportMarkingEnd(now + delta, remsetRefsCount);
283 }
284 {
285 const uint64_t delta = 3'000'000;
286 analytics.ReportEvacuationStart(now + delta);
287 }
288 {
289 const uint64_t delta = 6'000'000;
290 analytics.ReportEvacuationEnd(now + delta);
291 const size_t evacuatedBytes = 2 * 1024 * 1024;
292 analytics.ReportEvacuatedBytes(evacuatedBytes);
293 const size_t liveObjects = 32000;
294 analytics.ReportLiveObjects(liveObjects);
295 }
296 {
297 const uint64_t delta = 6'000'000;
298 analytics.ReportUpdateRefsStart(now + delta);
299 }
300 {
301 const uint64_t delta = 7'000'000;
302 analytics.ReportUpdateRefsEnd(now + delta);
303 }
304 {
305 const uint64_t delta = 10'000'000;
306 analytics.ReportCollectionEnd(GCTaskCause::YOUNG_GC_CAUSE, now + delta, collectionSet);
307 }
308 }
309
FillAnalyticsPause1PredictionTest(G1Analytics & analytics,const CollectionSet & collectionSet,uint64_t now)310 static void FillAnalyticsPause1PredictionTest(G1Analytics &analytics, const CollectionSet &collectionSet, uint64_t now)
311 {
312 analytics.ReportCollectionStart(now);
313
314 {
315 const size_t remsetSize = 110;
316 const size_t remsetRefsCount = 1500;
317 analytics.ReportRemsetSize(remsetSize, remsetRefsCount);
318 }
319 {
320 const uint64_t delta = 900'000;
321 analytics.ReportScanDirtyCardsStart(now + delta);
322 }
323 {
324 const uint64_t delta = 950'000;
325 const size_t dirtyCardsCount = 2;
326 analytics.ReportScanDirtyCardsEnd(now + delta, dirtyCardsCount);
327 }
328 {
329 const uint64_t delta = 1'000'000;
330 analytics.ReportMarkingStart(now + delta);
331 }
332 {
333 const uint64_t delta = 2'500'000;
334 const size_t remsetRefsCount = 12000;
335 analytics.ReportMarkingEnd(now + delta, remsetRefsCount);
336 }
337 {
338 const uint64_t delta = 3'000'000;
339 analytics.ReportEvacuationStart(now + delta);
340 }
341 {
342 const uint64_t delta = 6'500'000;
343 analytics.ReportEvacuationEnd(now + delta);
344 const size_t evacuatedBytes = 2 * 1024 * 1024;
345 analytics.ReportEvacuatedBytes(evacuatedBytes);
346 analytics.ReportPromotedRegion();
347 analytics.ReportPromotedRegion();
348 const size_t liveObjects = 30000;
349 analytics.ReportLiveObjects(liveObjects);
350 }
351 {
352 const uint64_t delta = 6'000'000;
353 analytics.ReportUpdateRefsStart(now + delta);
354 }
355 {
356 const uint64_t delta = 7'500'000;
357 analytics.ReportUpdateRefsEnd(now + delta);
358 }
359 const uint64_t delta = 10'000'000;
360 analytics.ReportCollectionEnd(GCTaskCause::YOUNG_GC_CAUSE, now + delta, collectionSet);
361 }
362
FillAnalyticsPause2PredictionTest(G1Analytics & analytics,const CollectionSet & collectionSet,uint64_t now)363 static void FillAnalyticsPause2PredictionTest(G1Analytics &analytics, const CollectionSet &collectionSet, uint64_t now)
364 {
365 analytics.ReportCollectionStart(now);
366 {
367 const size_t remsetSize = 120;
368 const size_t remsetRefsCount = 1600;
369 analytics.ReportRemsetSize(remsetSize, remsetRefsCount);
370 }
371 {
372 const uint64_t delta = 900'000;
373 analytics.ReportScanDirtyCardsStart(now + delta);
374 }
375 {
376 const uint64_t delta = 950'000;
377 const size_t dirtyCardsCount = 2;
378 analytics.ReportScanDirtyCardsEnd(now + delta, dirtyCardsCount);
379 }
380 {
381 const uint64_t delta = 1'000'000;
382 analytics.ReportMarkingStart(now + delta);
383 }
384 {
385 const uint64_t delta = 3'000'000;
386 const size_t remsetRefsCount = 13000;
387 analytics.ReportMarkingEnd(now + delta, remsetRefsCount);
388 }
389 {
390 const uint64_t delta = 3'000'000;
391 analytics.ReportEvacuationStart(now + delta);
392 }
393 {
394 const uint64_t delta = 7'000'000;
395 analytics.ReportEvacuationEnd(now + delta);
396 const size_t evacuatedBytes = 2 * 1024 * 1024;
397 analytics.ReportEvacuatedBytes(evacuatedBytes);
398 analytics.ReportPromotedRegion();
399 const size_t liveObjects = 33000;
400 analytics.ReportLiveObjects(liveObjects);
401 }
402 {
403 const uint64_t delta = 7'000'000;
404 analytics.ReportUpdateRefsStart(now + delta);
405 }
406 {
407 const uint64_t delta = 8'500'000;
408 analytics.ReportUpdateRefsEnd(now + delta);
409 }
410 const uint64_t delta = 11'000'000;
411 analytics.ReportCollectionEnd(GCTaskCause::YOUNG_GC_CAUSE, now + delta, collectionSet);
412 }
413
TEST_F(G1AnalyticsTest,PredictionTest)414 TEST_F(G1AnalyticsTest, PredictionTest)
415 {
416 uint64_t now = START_TIME;
417 const auto startTimeDelta = -20'000'000;
418 auto startTime = now + startTimeDelta;
419 G1Analytics analytics(startTime);
420
421 {
422 const size_t edenLength = 16;
423 auto collectionSet = CreateCollectionSet(edenLength);
424 FillAnalyticsPause0PredictionTest(analytics, collectionSet, now);
425
426 const size_t expectedTime = 10'000;
427 ASSERT_EQ(expectedTime, analytics.PredictYoungCollectionTimeInMicros(edenLength));
428 const double expectedAllocationRate = 0.0008;
429 const double maxError = 1e-6;
430 ASSERT_NEAR(expectedAllocationRate, analytics.PredictAllocationRate(), maxError);
431 }
432
433 const uint64_t nextPauseDelta = 20'000'000;
434 now += nextPauseDelta;
435
436 {
437 const size_t edenLength = 10;
438 auto collectionSet = CreateCollectionSet(edenLength);
439 FillAnalyticsPause1PredictionTest(analytics, collectionSet, now);
440
441 const uint64_t expectedTime = 9'266;
442 ASSERT_EQ(expectedTime, analytics.PredictYoungCollectionTimeInMicros(edenLength));
443 const double expectedAllocationRate = 0.000905;
444 const double maxError = 1e-6;
445 ASSERT_NEAR(expectedAllocationRate, analytics.PredictAllocationRate(), maxError);
446 }
447
448 now += nextPauseDelta;
449
450 const size_t edenLength = 14;
451 const size_t oldLength = 10;
452 auto collectionSet = CreateCollectionSet(edenLength, oldLength);
453 FillAnalyticsPause2PredictionTest(analytics, collectionSet, now);
454
455 const uint64_t expectedTime = 10'772;
456 ASSERT_EQ(expectedTime, analytics.PredictYoungCollectionTimeInMicros(edenLength));
457 const uint64_t expectedOldTime = 110;
458 const size_t remsetSize = 50;
459 const size_t liveBytes = 64 * 1024;
460 const size_t liveObjects = 100;
461 ASSERT_EQ(expectedOldTime, analytics.PredictOldCollectionTimeInMicros(remsetSize, liveBytes, liveObjects));
462 const double expectedAllocationRate = 0.001151;
463 const double maxError = 1e-6;
464 ASSERT_NEAR(expectedAllocationRate, analytics.PredictAllocationRate(), maxError);
465 }
466 } // namespace ark::mem
467