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 namespace {
24 
25 static constexpr uint64_t MilliToNano = 1000000;
26 
27 }
28 
DisplayStateResidencyProvider(std::shared_ptr<CommonDisplayContextProvider> displayContextProvider,std::shared_ptr<StatisticsProvider> statisticsProvider)29 DisplayStateResidencyProvider::DisplayStateResidencyProvider(
30         std::shared_ptr<CommonDisplayContextProvider> displayContextProvider,
31         std::shared_ptr<StatisticsProvider> statisticsProvider)
32       : mDisplayContextProvider(displayContextProvider), mStatisticsProvider(statisticsProvider) {
33     generatePowerStatsStates();
34     mStartStatisticTimeNs = mStatisticsProvider->getStartStatisticTimeNs();
35 }
36 
getStateResidency(std::vector<StateResidency> * stats)37 void DisplayStateResidencyProvider::getStateResidency(std::vector<StateResidency>* stats) {
38     int64_t powerStatsTotalTimeNs = aggregateStatistics();
39 #ifdef DEBUG_VRR_POWERSTATS
40     uint64_t statisticDurationNs = getBootClockTimeNs() - mStartStatisticTimeNs;
41     ALOGD("DisplayStateResidencyProvider: total power stats time = %ld ms, time lapse = %ld ms",
42           powerStatsTotalTimeNs / MilliToNano, statisticDurationNs / MilliToNano);
43     if (mLastGetStateResidencyTimeNs != -1) {
44         int64_t timePassedNs = (getSteadyClockTimeNs() - mLastGetStateResidencyTimeNs);
45         int64_t statisticAccumulatedTimeNs = (powerStatsTotalTimeNs - mLastPowerStatsTotalTimeNs);
46         ALOGD("DisplayStateResidencyProvider: The time interval between successive calls to "
47               "getStateResidency() = %ld ms",
48               (timePassedNs / MilliToNano));
49         ALOGD("DisplayStateResidencyProvider: The accumulated statistic time interval between "
50               "successive calls to "
51               "getStateResidency() = %ld ms",
52               (statisticAccumulatedTimeNs / MilliToNano));
53     }
54     mLastGetStateResidencyTimeNs = getSteadyClockTimeNs();
55     mLastPowerStatsTotalTimeNs = powerStatsTotalTimeNs;
56 #endif
57     *stats = mStateResidency;
58 }
59 
getStates()60 const std::vector<State>& DisplayStateResidencyProvider::getStates() {
61     return mStates;
62 }
63 
aggregateStatistics()64 uint64_t DisplayStateResidencyProvider::aggregateStatistics() {
65     uint64_t totalTimeNs = 0;
66     std::set<int> firstIteration;
67     auto updatedStatistics = mStatisticsProvider->getUpdatedStatistics();
68     for (auto& statistic : updatedStatistics) {
69         auto it = mPowerStatsProfileToIdMap.find(statistic.first.toPowerStatsProfile());
70         if (it == mPowerStatsProfileToIdMap.end()) {
71             ALOGE("DisplayStateResidencyProvider %s(): unregistered powerstats state [%s]",
72                   __func__, statistic.first.toPowerStatsProfile().toString().c_str());
73             continue;
74         }
75         int id = it->second;
76         const auto& displayPresentRecord = statistic.second;
77 
78         auto& stateResidency = mStateResidency[id];
79         if (firstIteration.count(id) > 0) {
80             stateResidency.totalStateEntryCount += displayPresentRecord.mCount;
81             stateResidency.lastEntryTimestampMs =
82                     std::max<uint64_t>(stateResidency.lastEntryTimestampMs,
83                                        displayPresentRecord.mLastTimeStampInBootClockNs /
84                                                MilliToNano);
85             stateResidency.totalTimeInStateMs +=
86                     displayPresentRecord.mAccumulatedTimeNs / MilliToNano;
87         } else {
88             stateResidency.totalStateEntryCount = displayPresentRecord.mCount;
89             stateResidency.lastEntryTimestampMs =
90                     displayPresentRecord.mLastTimeStampInBootClockNs / MilliToNano;
91             stateResidency.totalTimeInStateMs =
92                     displayPresentRecord.mAccumulatedTimeNs / MilliToNano;
93             firstIteration.insert(id);
94         }
95 
96         statistic.second.mUpdated = false;
97         totalTimeNs += displayPresentRecord.mAccumulatedTimeNs;
98     }
99     return totalTimeNs;
100 }
101 
generateUniqueStates()102 void DisplayStateResidencyProvider::generateUniqueStates() {
103     auto configs = mDisplayContextProvider->getDisplayConfigs();
104     if (!configs) return; // Early return if no configs
105 
106     // Special case: Power mode OFF
107     mUniqueStates.emplace(PowerStatsProfile{.mPowerMode = HWC2_POWER_MODE_OFF}, "OFF");
108 
109     // Iterate through all combinations
110     for (auto refreshSource : android::hardware::graphics::composer::kRefreshSource) {
111         for (auto powerMode : android::hardware::graphics::composer::kActivePowerModes) {
112             // LPM and NP is not possible. skipping
113             if (!isPresentRefresh(refreshSource) && powerMode == HWC2_POWER_MODE_DOZE) {
114                 continue;
115             }
116             for (const auto& config : *configs) {
117                 for (int brightnessMode = static_cast<int>(BrightnessMode::kNormalBrightnessMode);
118                      brightnessMode < static_cast<int>(BrightnessMode::kInvalidBrightnessMode);
119                      ++brightnessMode) {
120                     PowerStatsProfile
121                             profile{.mWidth = mDisplayContextProvider->getWidth(config.first),
122                                     .mHeight = mDisplayContextProvider->getHeight(config.first),
123                                     .mFps = 0, // Initially set to 0
124                                     .mPowerMode = powerMode,
125                                     .mBrightnessMode = static_cast<BrightnessMode>(brightnessMode),
126                                     .mRefreshSource = refreshSource};
127 
128                     if (powerMode == HWC_POWER_MODE_DOZE) {
129                         for (auto fps :
130                              android::hardware::graphics::composer::kFpsLowPowerModeMappingTable) {
131                             profile.mFps = fps;
132                             mUniqueStates.emplace(profile,
133                                                   mPowerStatsProfileTokenGenerator
134                                                           .generateStateName(&profile));
135                         }
136                     } else {
137                         mUniqueStates.emplace(profile,
138                                               mPowerStatsProfileTokenGenerator.generateStateName(
139                                                       &profile));
140                         for (auto fps : android::hardware::graphics::composer::kFpsMappingTable) {
141                             profile.mFps = fps.round();
142                             mUniqueStates.emplace(profile,
143                                                   mPowerStatsProfileTokenGenerator
144                                                           .generateStateName(&profile));
145                         }
146                     }
147                 }
148             }
149         }
150     }
151 }
152 
generatePowerStatsStates()153 void DisplayStateResidencyProvider::generatePowerStatsStates() {
154     generateUniqueStates();
155 
156     // Sort and assign a unique identifier to each state string.
157     std::map<std::string, int> stateNameIDMap;
158     int index = 0;
159     for (const auto& state : mUniqueStates) {
160         auto it = stateNameIDMap.find(state.second);
161         int id = index;
162         // If the stateName already exists, update mPowerStatsProfileToIdMap, and skip
163         // updating mStates/Residency
164         if (it != stateNameIDMap.end()) {
165             id = it->second;
166         } else {
167             stateNameIDMap.insert({state.second, id});
168             index++;
169             mStates.push_back({id, state.second});
170             mStateResidency.emplace_back();
171             mStateResidency.back().id = id;
172         }
173         mPowerStatsProfileToIdMap[state.first] = id;
174     }
175 
176 #ifdef DEBUG_VRR_POWERSTATS
177     for (const auto& state : mStates) {
178         ALOGI("DisplayStateResidencyProvider state id = %d, content = %s, len = %ld", state.id,
179               state.name.c_str(), state.name.length());
180     }
181 #endif
182 }
183 
184 } // namespace android::hardware::graphics::composer
185