1 /* 2 * Copyright 2019 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 #pragma once 18 19 #include <utils/Timers.h> 20 21 #include <chrono> 22 #include <deque> 23 24 #include "SchedulerUtils.h" 25 26 namespace android { 27 28 class Layer; 29 30 namespace scheduler { 31 32 using namespace std::chrono_literals; 33 34 // Maximum period between presents for a layer to be considered active. 35 constexpr std::chrono::nanoseconds MAX_ACTIVE_LAYER_PERIOD_NS = 1200ms; 36 37 // Earliest present time for a layer to be considered active. getActiveLayerThreshold(nsecs_t now)38constexpr nsecs_t getActiveLayerThreshold(nsecs_t now) { 39 return now - MAX_ACTIVE_LAYER_PERIOD_NS.count(); 40 } 41 42 // Stores history of present times and refresh rates for a layer. 43 class LayerInfo { 44 // Layer is considered frequent if the earliest value in the window of most recent present times 45 // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in 46 // favor of a low refresh rate. 47 static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3; 48 static constexpr std::chrono::nanoseconds MAX_FREQUENT_LAYER_PERIOD_NS = 250ms; 49 50 /** 51 * Struct that keeps the information about the refresh rate for last 52 * HISTORY_SIZE frames. This is used to better determine the refresh rate 53 * for individual layers. 54 */ 55 class RefreshRateHistory { 56 public: RefreshRateHistory(float highRefreshRate)57 explicit RefreshRateHistory(float highRefreshRate) : mHighRefreshRate(highRefreshRate) {} 58 insertRefreshRate(float refreshRate)59 void insertRefreshRate(float refreshRate) { 60 mElements.push_back(refreshRate); 61 if (mElements.size() > HISTORY_SIZE) { 62 mElements.pop_front(); 63 } 64 } 65 getRefreshRateAvg()66 float getRefreshRateAvg() const { 67 return mElements.empty() ? mHighRefreshRate : calculate_mean(mElements); 68 } 69 clearHistory()70 void clearHistory() { mElements.clear(); } 71 72 private: 73 const float mHighRefreshRate; 74 75 static constexpr size_t HISTORY_SIZE = 30; 76 std::deque<float> mElements; 77 }; 78 79 /** 80 * Struct that keeps the information about the present time for last 81 * HISTORY_SIZE frames. This is used to better determine whether the given layer 82 * is still relevant and it's refresh rate should be considered. 83 */ 84 class PresentTimeHistory { 85 public: 86 static constexpr size_t HISTORY_SIZE = 90; 87 insertPresentTime(nsecs_t presentTime)88 void insertPresentTime(nsecs_t presentTime) { 89 mElements.push_back(presentTime); 90 if (mElements.size() > HISTORY_SIZE) { 91 mElements.pop_front(); 92 } 93 } 94 95 // Returns whether the earliest present time is within the active threshold. isRecentlyActive(nsecs_t now)96 bool isRecentlyActive(nsecs_t now) const { 97 if (mElements.size() < 2) { 98 return false; 99 } 100 101 // The layer had to publish at least HISTORY_SIZE or HISTORY_DURATION of updates 102 if (mElements.size() < HISTORY_SIZE && 103 mElements.back() - mElements.front() < HISTORY_DURATION.count()) { 104 return false; 105 } 106 107 return mElements.back() >= getActiveLayerThreshold(now); 108 } 109 isFrequent(nsecs_t now)110 bool isFrequent(nsecs_t now) const { 111 // Assume layer is infrequent if too few present times have been recorded. 112 if (mElements.size() < FREQUENT_LAYER_WINDOW_SIZE) { 113 return false; 114 } 115 116 // Layer is frequent if the earliest value in the window of most recent present times is 117 // within threshold. 118 const auto it = mElements.end() - FREQUENT_LAYER_WINDOW_SIZE; 119 const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count(); 120 return *it >= threshold; 121 } 122 clearHistory()123 void clearHistory() { mElements.clear(); } 124 125 private: 126 std::deque<nsecs_t> mElements; 127 static constexpr std::chrono::nanoseconds HISTORY_DURATION = 1s; 128 }; 129 130 friend class LayerHistoryTest; 131 132 public: 133 LayerInfo(float lowRefreshRate, float highRefreshRate); 134 135 LayerInfo(const LayerInfo&) = delete; 136 LayerInfo& operator=(const LayerInfo&) = delete; 137 138 // Records the last requested oresent time. It also stores information about when 139 // the layer was last updated. If the present time is farther in the future than the 140 // updated time, the updated time is the present time. 141 void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now); 142 isRecentlyActive(nsecs_t now)143 bool isRecentlyActive(nsecs_t now) const { return mPresentTimeHistory.isRecentlyActive(now); } isFrequent(nsecs_t now)144 bool isFrequent(nsecs_t now) const { return mPresentTimeHistory.isFrequent(now); } 145 getRefreshRate(nsecs_t now)146 float getRefreshRate(nsecs_t now) const { 147 return isFrequent(now) ? mRefreshRateHistory.getRefreshRateAvg() : mLowRefreshRate; 148 } 149 150 // Return the last updated time. If the present time is farther in the future than the 151 // updated time, the updated time is the present time. getLastUpdatedTime()152 nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } 153 clearHistory()154 void clearHistory() { 155 mRefreshRateHistory.clearHistory(); 156 mPresentTimeHistory.clearHistory(); 157 } 158 159 private: 160 const float mLowRefreshRate; 161 const float mHighRefreshRate; 162 163 nsecs_t mLastUpdatedTime = 0; 164 nsecs_t mLastPresentTime = 0; 165 RefreshRateHistory mRefreshRateHistory{mHighRefreshRate}; 166 PresentTimeHistory mPresentTimeHistory; 167 }; 168 169 } // namespace scheduler 170 } // namespace android 171