• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdlib.h>
18 
19 #include "DisplayStateResidencyProvider.h"
20 
21 namespace android::hardware::graphics::composer {
22 
23 // Currently, the FPS ranges from [1, |kMaxFrameRate| = 120], and the maximum TE
24 // frequency(|kMaxTefrequency|) = 240. We express fps by dividing the maximum TE by the number of
25 // vsync. Here, the numerator is set to |kMaxTefrequency|, fraction reduction is not needed here.
26 const std::set<Fraction<int>> DisplayStateResidencyProvider::kFpsMappingTable =
27         {{240, 240}, {240, 120}, {240, 24}, {240, 10}, {240, 8}, {240, 7},
28          {240, 6},   {240, 5},   {240, 4},  {240, 3},  {240, 2}};
29 
30 const std::unordered_set<int> DisplayStateResidencyProvider::kFpsLowPowerModeMappingTable = {1, 30};
31 
32 const std::unordered_set<int> DisplayStateResidencyProvider::kActivePowerModes =
33         {HWC2_POWER_MODE_DOZE, HWC2_POWER_MODE_ON};
34 
35 namespace {
36 
37 static constexpr uint64_t MilliToNano = 1000000;
38 
39 }
40 
DisplayStateResidencyProvider(std::shared_ptr<CommonDisplayContextProvider> displayContextProvider,std::shared_ptr<StatisticsProvider> statisticsProvider)41 DisplayStateResidencyProvider::DisplayStateResidencyProvider(
42         std::shared_ptr<CommonDisplayContextProvider> displayContextProvider,
43         std::shared_ptr<StatisticsProvider> statisticsProvider)
44       : mDisplayContextProvider(displayContextProvider), mStatisticsProvider(statisticsProvider) {
45     if (parseDisplayStateResidencyPattern()) {
46         generatePowerStatsStates();
47     }
48     mStartStatisticTimeNs = mStatisticsProvider->getStartStatisticTimeNs();
49 }
50 
getStateResidency(std::vector<StateResidency> * stats)51 void DisplayStateResidencyProvider::getStateResidency(std::vector<StateResidency>* stats) {
52     mapStatistics();
53 
54     int64_t powerStatsTotalTimeNs = aggregateStatistics();
55 #ifdef DEBUG_VRR_POWERSTATS
56     uint64_t statisticDurationNs = getBootClockTimeNs() - mStartStatisticTimeNs;
57     ALOGD("DisplayStateResidencyProvider: total power stats time = %ld ms, time lapse = %ld ms",
58           powerStatsTotalTimeNs / MilliToNano, statisticDurationNs / MilliToNano);
59     if (mLastGetStateResidencyTimeNs != -1) {
60         int64_t timePassedNs = (getSteadyClockTimeNs() - mLastGetStateResidencyTimeNs);
61         int64_t statisticAccumulatedTimeNs = (powerStatsTotalTimeNs - mLastPowerStatsTotalTimeNs);
62         ALOGD("DisplayStateResidencyProvider: The time interval between successive calls to "
63               "getStateResidency() = %ld ms",
64               (timePassedNs / MilliToNano));
65         ALOGD("DisplayStateResidencyProvider: The accumulated statistic time interval between "
66               "successive calls to "
67               "getStateResidency() = %ld ms",
68               (statisticAccumulatedTimeNs / MilliToNano));
69     }
70     mLastGetStateResidencyTimeNs = getSteadyClockTimeNs();
71     mLastPowerStatsTotalTimeNs = powerStatsTotalTimeNs;
72 #endif
73     *stats = mStateResidency;
74 }
75 
getStates()76 const std::vector<State>& DisplayStateResidencyProvider::getStates() {
77     return mStates;
78 }
79 
mapStatistics()80 void DisplayStateResidencyProvider::mapStatistics() {
81     auto mUpdatedStatistics = mStatisticsProvider->getUpdatedStatistics();
82 #ifdef DEBUG_VRR_POWERSTATS
83     for (const auto& item : mUpdatedStatistics) {
84         ALOGI("DisplayStateResidencyProvider : update key %s value %s",
85               item.first.toString().c_str(), item.second.toString().c_str());
86     }
87 #endif
88     mRemappedStatistics.clear();
89     for (const auto& item : mUpdatedStatistics) {
90         mStatistics[item.first] = item.second;
91     }
92 
93     for (const auto& item : mStatistics) {
94         const auto& displayPresentProfile = item.first;
95         PowerStatsPresentProfile powerStatsPresentProfile;
96         if (displayPresentProfile.mNumVsync <
97             0) { // To address the specific scenario of powering off.
98             powerStatsPresentProfile.mFps = -1;
99             mRemappedStatistics[powerStatsPresentProfile] += item.second;
100             mRemappedStatistics[powerStatsPresentProfile].mUpdated = true;
101             continue;
102         }
103         const auto& configId = displayPresentProfile.mCurrentDisplayConfig.mActiveConfigId;
104         powerStatsPresentProfile.mWidth = mDisplayContextProvider->getWidth(configId);
105         powerStatsPresentProfile.mHeight = mDisplayContextProvider->getHeight(configId);
106         powerStatsPresentProfile.mPowerMode =
107                 displayPresentProfile.mCurrentDisplayConfig.mPowerMode;
108         powerStatsPresentProfile.mBrightnessMode =
109                 displayPresentProfile.mCurrentDisplayConfig.mBrightnessMode;
110         auto teFrequency = mDisplayContextProvider->getTeFrequency(configId);
111         Fraction fps(teFrequency, displayPresentProfile.mNumVsync);
112         if ((kFpsMappingTable.count(fps) > 0)) {
113             powerStatsPresentProfile.mFps = fps.round();
114             mRemappedStatistics[powerStatsPresentProfile] += item.second;
115             mRemappedStatistics[powerStatsPresentProfile].mUpdated = true;
116         } else {
117             // Others.
118             auto key = powerStatsPresentProfile;
119             const auto& value = item.second;
120             key.mFps = 0;
121             mRemappedStatistics[key].mUpdated = true;
122             mRemappedStatistics[key].mCount += value.mCount;
123             mRemappedStatistics[key].mAccumulatedTimeNs += value.mAccumulatedTimeNs;
124             mRemappedStatistics[key].mLastTimeStampInBootClockNs =
125                     std::max(mRemappedStatistics[key].mLastTimeStampInBootClockNs,
126                              value.mLastTimeStampInBootClockNs);
127         }
128     }
129 }
130 
aggregateStatistics()131 uint64_t DisplayStateResidencyProvider::aggregateStatistics() {
132     uint64_t totalTimeNs = 0;
133     for (auto& statistic : mRemappedStatistics) {
134         if (!statistic.second.mUpdated) {
135             continue;
136         }
137         auto it = mPowerStatsPresentProfileToIdMap.find(statistic.first);
138         if (it == mPowerStatsPresentProfileToIdMap.end()) {
139             ALOGE("DisplayStateResidencyProvider %s(): unregistered powerstats state [%s]",
140                   __func__, statistic.first.toString().c_str());
141             continue;
142         }
143         int id = it->second;
144         const auto& displayPresentRecord = statistic.second;
145 
146         auto& stateResidency = mStateResidency[id];
147         stateResidency.totalStateEntryCount = displayPresentRecord.mCount;
148         stateResidency.lastEntryTimestampMs =
149                 displayPresentRecord.mLastTimeStampInBootClockNs / MilliToNano;
150         stateResidency.totalTimeInStateMs = displayPresentRecord.mAccumulatedTimeNs / MilliToNano;
151         statistic.second.mUpdated = false;
152         totalTimeNs += displayPresentRecord.mAccumulatedTimeNs;
153     }
154     return totalTimeNs;
155 }
156 
generatePowerStatsStates()157 void DisplayStateResidencyProvider::generatePowerStatsStates() {
158     auto configs = mDisplayContextProvider->getDisplayConfigs();
159     if (!configs) return;
160     std::set<PowerStatsPresentProfile> powerStatsPresentProfileCandidates;
161     PowerStatsPresentProfile powerStatsPresentProfile;
162 
163     // Generate a list of potential DisplayConfigProfiles.
164     // Include the special case 'OFF'.
165     powerStatsPresentProfile.mPowerMode = HWC2_POWER_MODE_OFF;
166     powerStatsPresentProfileCandidates.insert(powerStatsPresentProfile);
167     for (auto powerMode : kActivePowerModes) {
168         powerStatsPresentProfile.mPowerMode = powerMode;
169         for (int brightnesrMode = static_cast<int>(BrightnessMode::kNormalBrightnessMode);
170              brightnesrMode < BrightnessMode::kInvalidBrightnessMode; ++brightnesrMode) {
171             powerStatsPresentProfile.mBrightnessMode = static_cast<BrightnessMode>(brightnesrMode);
172             for (const auto& config : *configs) {
173                 powerStatsPresentProfile.mWidth = mDisplayContextProvider->getWidth(config.first);
174                 powerStatsPresentProfile.mHeight = mDisplayContextProvider->getHeight(config.first);
175                 // Handle the special case LPM(Low Power Mode).
176                 if (powerMode == HWC_POWER_MODE_DOZE) {
177                     for (auto fps : kFpsLowPowerModeMappingTable) {
178                         powerStatsPresentProfile.mFps = fps;
179                         powerStatsPresentProfileCandidates.insert(powerStatsPresentProfile);
180                     }
181                     continue;
182                 }
183                 // Include the special case: other fps.
184                 powerStatsPresentProfile.mFps = 0;
185                 powerStatsPresentProfileCandidates.insert(powerStatsPresentProfile);
186                 for (auto fps : kFpsMappingTable) {
187                     powerStatsPresentProfile.mFps = fps.round();
188                     powerStatsPresentProfileCandidates.insert(powerStatsPresentProfile);
189                 }
190             }
191         }
192     }
193 
194     auto uniqueComp = [](const std::pair<std::string, PowerStatsPresentProfile>& v1,
195                          const std::pair<std::string, PowerStatsPresentProfile>& v2) {
196         return v1.first < v2.first;
197     };
198 
199     // Transform candidate DisplayConfigProfiles into a string and eliminate duplicates.
200     std::set<std::pair<std::string, PowerStatsPresentProfile>, decltype(uniqueComp)> uniqueStates;
201     for (const auto& powerStatsPresentProfile : powerStatsPresentProfileCandidates) {
202         std::string stateName;
203         mPowerStatsPresentProfileTokenGenerator.setPowerStatsPresentProfile(
204                 &powerStatsPresentProfile);
205         for (const auto& pattern : mDisplayStateResidencyPattern) {
206             const auto token = mPowerStatsPresentProfileTokenGenerator.generateToken(pattern.first);
207             if (token.has_value()) {
208                 stateName += token.value();
209                 // Handle special case when mode is 'OFF'.
210                 if (pattern.first == "mode" && token.value() == "OFF") {
211                     break;
212                 }
213             } else {
214                 ALOGE("DisplayStateResidencyProvider %s(): cannot find token with label %s",
215                       __func__, pattern.first.c_str());
216                 continue;
217             }
218             stateName += pattern.second;
219         }
220         uniqueStates.insert(std::make_pair(stateName, powerStatsPresentProfile));
221     }
222 
223     auto sortComp = [](const std::pair<std::string, PowerStatsPresentProfile>& v1,
224                        const std::pair<std::string, PowerStatsPresentProfile>& v2) {
225         return v1.second < v2.second;
226     };
227     std::set<std::pair<std::string, PowerStatsPresentProfile>, decltype(sortComp)> sortedStates;
228     // Sort power stats according to a predefined order.
229     std::for_each(uniqueStates.begin(), uniqueStates.end(),
230                   [&](const std::pair<std::string, PowerStatsPresentProfile>& item) {
231                       sortedStates.insert(item);
232                   });
233 
234     // Sort and assign a unique identifier to each state string.
235     mStateResidency.resize(sortedStates.size());
236     int id = 0;
237     int index = 0;
238     for (const auto& state : sortedStates) {
239         mStates.push_back({id, state.first});
240         mPowerStatsPresentProfileToIdMap[state.second] = id;
241         mStateResidency[index++].id = id;
242         ++id;
243     }
244 
245 #ifdef DEBUG_VRR_POWERSTATS
246     for (const auto& state : mStates) {
247         ALOGI("DisplayStateResidencyProvider state id = %d, content = %s, len = %ld", state.id,
248               state.name.c_str(), state.name.length());
249     }
250 #endif
251 }
252 
parseDisplayStateResidencyPattern()253 bool DisplayStateResidencyProvider::parseDisplayStateResidencyPattern() {
254     size_t start, end;
255     start = 0;
256     end = -1;
257     while (true) {
258         start = kDisplayStateResidencyPattern.find_first_of(kTokenLabelStart, end + 1);
259         if (start == std::string::npos) {
260             break;
261         }
262         ++start;
263         end = kDisplayStateResidencyPattern.find_first_of(kTokenLabelEnd, start);
264         if (end == std::string::npos) {
265             break;
266         }
267         std::string tokenLabel(kDisplayStateResidencyPattern.substr(start, end - start));
268 
269         start = kDisplayStateResidencyPattern.find_first_of(kDelimiterStart, end + 1);
270         if (start == std::string::npos) {
271             break;
272         }
273         ++start;
274         end = kDisplayStateResidencyPattern.find_first_of(kDelimiterEnd, start);
275         if (end == std::string::npos) {
276             break;
277         }
278         std::string delimiter(kDisplayStateResidencyPattern.substr(start, end - start));
279         mDisplayStateResidencyPattern.emplace_back(std::make_pair(tokenLabel, delimiter));
280     }
281     return (end == kDisplayStateResidencyPattern.length() - 1);
282 }
283 
284 } // namespace android::hardware::graphics::composer
285