• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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