1 /**
2 * Copyright (c) 2023 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 "g1_analytics.h"
17 #include "libpandabase/utils/time.h"
18 #include "libpandabase/os/time.h"
19
20 namespace panda::mem {
G1Analytics(uint64_t now)21 G1Analytics::G1Analytics(uint64_t now) : previousYoungCollectionEnd_(now) {}
22
ReportEvacuatedBytes(size_t bytes)23 void G1Analytics::ReportEvacuatedBytes(size_t bytes)
24 {
25 // Atomic with relaxed order reason: data race with no synchronization or ordering constraints imposed
26 // on other reads or writes
27 copiedBytes_.fetch_add(bytes, std::memory_order_relaxed);
28 }
29
ReportScanRemsetStart(uint64_t time)30 void G1Analytics::ReportScanRemsetStart(uint64_t time)
31 {
32 scanRemsetStart_ = time;
33 }
34
ReportScanRemsetEnd(uint64_t time)35 void G1Analytics::ReportScanRemsetEnd(uint64_t time)
36 {
37 scanRemsetEnd_ = time;
38 }
39
ReportMarkingStart(uint64_t time)40 void G1Analytics::ReportMarkingStart(uint64_t time)
41 {
42 markingStart_ = time;
43 }
44
ReportMarkingEnd(uint64_t time)45 void G1Analytics::ReportMarkingEnd(uint64_t time)
46 {
47 markingEnd_ = time;
48 }
49
ReportEvacuationStart(uint64_t time)50 void G1Analytics::ReportEvacuationStart(uint64_t time)
51 {
52 evacuationStart_ = time;
53 }
54
ReportEvacuationEnd(uint64_t time)55 void G1Analytics::ReportEvacuationEnd(uint64_t time)
56 {
57 evacuationEnd_ = time;
58 }
59
ReportUpdateRefsStart(uint64_t time)60 void G1Analytics::ReportUpdateRefsStart(uint64_t time)
61 {
62 updateRefsStart_ = time;
63 }
64
ReportUpdateRefsEnd(uint64_t time)65 void G1Analytics::ReportUpdateRefsEnd(uint64_t time)
66 {
67 updateRefsEnd_ = time;
68 }
69
ReportPromotedRegion()70 void G1Analytics::ReportPromotedRegion()
71 {
72 // Atomic with relaxed order reason: data race with no synchronization or ordering constraints imposed
73 // on other reads or writes
74 promotedRegions_.fetch_add(1, std::memory_order_relaxed);
75 }
76
ReportLiveObjects(size_t num)77 void G1Analytics::ReportLiveObjects(size_t num)
78 {
79 // Atomic with relaxed order reason: data race with no synchronization or ordering constraints imposed
80 // on other reads or writes
81 liveObjects_.fetch_add(num, std::memory_order_relaxed);
82 }
83
PredictAllocationRate() const84 double G1Analytics::PredictAllocationRate() const
85 {
86 return predictor_.Predict(allocationRateSeq_);
87 }
88
EstimatePredictionErrorInMicros() const89 int64_t G1Analytics::EstimatePredictionErrorInMicros() const
90 {
91 return predictor_.Predict(predictionErrorSeq_);
92 }
93
ReportCollectionStart(uint64_t time)94 void G1Analytics::ReportCollectionStart(uint64_t time)
95 {
96 currentYoungCollectionStart_ = time;
97 copiedBytes_ = 0;
98 promotedRegions_ = 0;
99 liveObjects_ = 0;
100 }
101
ReportCollectionEnd(uint64_t endTime,const CollectionSet & collectionSet)102 void G1Analytics::ReportCollectionEnd(uint64_t endTime, const CollectionSet &collectionSet)
103 {
104 auto edenLength = collectionSet.Young().size();
105 auto appTime = (currentYoungCollectionStart_ - previousYoungCollectionEnd_) / panda::os::time::MICRO_TO_NANO;
106 allocationRateSeq_.Add(static_cast<double>(edenLength) / appTime);
107
108 if (collectionSet.Young().size() == collectionSet.size()) {
109 if (edenLength != promotedRegions_) {
110 auto compactedRegions = edenLength - promotedRegions_;
111 liveObjectsSeq_.Add(static_cast<double>(liveObjects_) / compactedRegions);
112 copiedBytesSeq_.Add(static_cast<double>(copiedBytes_) / compactedRegions);
113 auto estimatedPromotionTime = EstimatePromotionTimeInMicros(promotedRegions_);
114 auto evacuationTime = (evacuationEnd_ - evacuationStart_) / panda::os::time::MICRO_TO_NANO;
115 if (evacuationTime > estimatedPromotionTime) {
116 copyingBytesRateSeq_.Add(static_cast<double>(copiedBytes_) / (evacuationTime - estimatedPromotionTime));
117 }
118 }
119
120 auto markingTime = (markingEnd_ - markingStart_) / panda::os::time::MICRO_TO_NANO;
121 markingRateSeq_.Add(static_cast<double>(liveObjects_) / markingTime);
122
123 auto updateRefsTime = (updateRefsEnd_ - updateRefsStart_) / panda::os::time::MICRO_TO_NANO;
124 updateRefsTimeSeq_.Add(static_cast<double>(updateRefsTime));
125
126 ASSERT(edenLength != 0);
127 promotionSeq_.Add(static_cast<double>(promotedRegions_) / edenLength);
128
129 auto pauseTime = (endTime - currentYoungCollectionStart_) / panda::os::time::MICRO_TO_NANO;
130 predictionErrorSeq_.Add(static_cast<double>(pauseTime) - PredictYoungCollectionTimeInMicros(edenLength));
131 }
132
133 auto scanRemsetTime = (scanRemsetEnd_ - scanRemsetStart_) / panda::os::time::MICRO_TO_NANO;
134 scanRemsetTimeSeq_.Add(static_cast<double>(scanRemsetTime) / collectionSet.size());
135
136 previousYoungCollectionEnd_ = endTime;
137 }
138
PredictYoungCollectionTimeInMicros(size_t edenLength) const139 int64_t G1Analytics::PredictYoungCollectionTimeInMicros(size_t edenLength) const
140 {
141 auto expectedPromotedRegions = PredictPromotedRegions(edenLength);
142 auto expectedCompactedRegions = edenLength - expectedPromotedRegions;
143 auto expectedCopiedBytes = expectedCompactedRegions * predictor_.Predict(copiedBytesSeq_);
144 auto expectedLiveObjects = expectedCompactedRegions * predictor_.Predict(liveObjectsSeq_);
145 auto markingRatePrediction = markingRateSeq_.IsEmpty() ? 0 : predictor_.Predict(markingRateSeq_);
146 auto markingCost = markingRatePrediction == 0 ? 0 : expectedLiveObjects / markingRatePrediction;
147 auto copyingBytesRatePrediction = copyingBytesRateSeq_.IsEmpty() ? 0 : predictor_.Predict(copyingBytesRateSeq_);
148 auto copyingCost = copyingBytesRatePrediction == 0 ? 0 : expectedCopiedBytes / copyingBytesRatePrediction;
149 return markingCost + copyingCost + edenLength * predictor_.Predict(scanRemsetTimeSeq_) +
150 predictor_.Predict(updateRefsTimeSeq_) + EstimatePromotionTimeInMicros(expectedPromotedRegions);
151 }
152
PredictOldCollectionTimeInMicros(Region * region) const153 int64_t G1Analytics::PredictOldCollectionTimeInMicros(Region *region) const
154 {
155 auto expectedLiveObjects = region->GetLiveBytes() * region->GetAllocatedObjects() / region->GetAllocatedBytes();
156 return PredictOldCollectionTimeInMicros(region->GetLiveBytes(), expectedLiveObjects);
157 }
158
PredictOldCollectionTimeInMicros(size_t liveBytes,size_t liveObjects) const159 int64_t G1Analytics::PredictOldCollectionTimeInMicros(size_t liveBytes, size_t liveObjects) const
160 {
161 // Currently remset scan esimation is too rough. We can improve it after #11263
162 auto remsetScanCost = predictor_.Predict(scanRemsetTimeSeq_);
163 return liveObjects / predictor_.Predict(markingRateSeq_) + liveBytes / predictor_.Predict(copyingBytesRateSeq_) +
164 remsetScanCost;
165 }
166
PredictPromotedRegions(size_t edenLength) const167 double G1Analytics::PredictPromotedRegions(size_t edenLength) const
168 {
169 return predictor_.Predict(promotionSeq_) * edenLength;
170 }
171
EstimatePromotionTimeInMicros(size_t promotedRegions) const172 size_t G1Analytics::EstimatePromotionTimeInMicros(size_t promotedRegions) const
173 {
174 return promotionCost_ * promotedRegions;
175 }
176 } // namespace panda::mem
177