• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 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 #ifndef LIBPANDABASE_MEM_WEIGHTED_ADAPTIVE_TLAB_AVERAGE_H
17 #define LIBPANDABASE_MEM_WEIGHTED_ADAPTIVE_TLAB_AVERAGE_H
18 
19 #include <algorithm>
20 #include "libpandabase/macros.h"
21 #include "runtime/include/mem/panda_containers.h"
22 
23 namespace ark {
24 class WeightedAdaptiveTlabAverage {
25 public:
WeightedAdaptiveTlabAverage(float initTlabSize,float upperSumBorder,float maxGrowRatio,float weight,float desiredFillFraction)26     explicit WeightedAdaptiveTlabAverage(float initTlabSize, float upperSumBorder, float maxGrowRatio, float weight,
27                                          float desiredFillFraction)
28         : maxGrowRatio_(maxGrowRatio),
29           lowerSumBorder_(initTlabSize),
30           upperSumBorder_(upperSumBorder),
31           lastCountedSum_(initTlabSize),
32           weight_(weight),
33           desiredFillFraction_(desiredFillFraction)
34     {
35         ASSERT(maxGrowRatio_ > 1.0);
36     }
37 
StoreNewSample(size_t occupiedSize,size_t maxSize)38     void StoreNewSample(size_t occupiedSize, size_t maxSize)
39     {
40         // Supposed that this method is called only in case of slow path
41         ASSERT(occupiedSize <= maxSize);
42         samples_.emplace_back(std::make_pair(occupiedSize, maxSize));
43     }
44 
45     /**
46      * @brief Estimates new TLAB size using saved TLABs' information
47      *
48      * If vector with samples is not empty, we start estimating TLABs' average fill fraction
49      * If average fill fraction is less than desiredFillFraction_, then we increase TLABs' size
50      * Else, we reduce TLABs' size
51      */
ComputeNewSumAndResetSamples()52     void ComputeNewSumAndResetSamples()
53     {
54         float newCountedSum = lastCountedSum_;
55         if (!samples_.empty()) {
56             float averageFillFraction = -1.0;
57             // Average fill fraction estimation
58             for (auto &sample : samples_) {
59                 if (sample.second != 0) {
60                     averageFillFraction = averageFillFraction < 0
61                                               ? static_cast<float>(sample.first) / sample.second
62                                               : static_cast<float>(sample.first) / sample.second * weight_ +
63                                                     averageFillFraction * (1.0F - weight_);
64                 }
65             }
66             if (averageFillFraction < 0) {
67                 // it means that zero tlab is the only sample that we currently have
68                 // in this case we don't have enough information to calculate new TLAB size
69                 samples_.clear();
70                 return;
71             }
72             if (averageFillFraction < desiredFillFraction_) {
73                 // Should increase TLABs' size
74                 newCountedSum = std::clamp(lastCountedSum_ * (desiredFillFraction_ / averageFillFraction),
75                                            lastCountedSum_ / maxGrowRatio_, lastCountedSum_ * maxGrowRatio_);
76             } else {
77                 // In this case we have few TLABs with good average fill fraction
78                 // It means that we should consider reducing TLABs' size
79                 newCountedSum = lastCountedSum_ * REDUCTION_RATE;
80             }
81         }
82         // Mind lower and upper borders
83         lastCountedSum_ =
84             std::clamp(newCountedSum * weight_ + lastCountedSum_ * (1.0F - weight_), lowerSumBorder_, upperSumBorder_);
85         samples_.clear();
86     }
87 
GetLastCountedSum()88     float GetLastCountedSum() const
89     {
90         return lastCountedSum_;
91     }
92 
GetLastCountedSumInSizeT()93     size_t GetLastCountedSumInSizeT() const
94     {
95         ASSERT(lowerSumBorder_ <= lastCountedSum_);
96         ASSERT(lastCountedSum_ <= upperSumBorder_);
97         return static_cast<size_t>(lastCountedSum_);
98     }
99 
100 private:
101     static constexpr float REDUCTION_RATE = 0.75;     // Value used for size reduction
102     float maxGrowRatio_;                              // Max change ratio when new average is estimated
103                                                       // (means that (newAverage / average) < maxGrowRatio_)
104     float lowerSumBorder_;                            // Min value that sum may take
105     float upperSumBorder_;                            // Max value that sum may take
106     float lastCountedSum_;                            // Last estimated sum
107     float weight_;                                    // From 0 to 1
108                                                       // Used for better average estimation
109                                                       // Recently observed samples should have greater weight
110     float desiredFillFraction_;                       // From 0 to 1
111                                                       // If (occupiedSize / maxSize) < desiredFillFraction_ then
112                                                       // lastCountedSum_ should grow
113     PandaVector<std::pair<size_t, size_t>> samples_;  // Saved samples. Used for estimation of a new sum
114 };
115 
116 }  // namespace ark
117 #endif  // LIBPANDABASE_MEM_WEIGHTED_ADAPTIVE_TLAB_AVERAGE_H
118