blob: 820624b9059f5e66e3bc2b86f6ddea63544058d7 [file] [log] [blame]
Ady Abraham09bd3922019-04-08 10:44:56 -07001/*
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
Ady Abraham09bd3922019-04-08 10:44:56 -070019#include <utils/Timers.h>
20
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -070021#include <chrono>
22#include <deque>
23
Ady Abraham09bd3922019-04-08 10:44:56 -070024#include "SchedulerUtils.h"
25
26namespace android {
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -070027
28class Layer;
29
Ady Abraham09bd3922019-04-08 10:44:56 -070030namespace scheduler {
31
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -070032using namespace std::chrono_literals;
33
34// Maximum period between presents for a layer to be considered active.
35constexpr std::chrono::nanoseconds MAX_ACTIVE_LAYER_PERIOD_NS = 1200ms;
36
37// Earliest present time for a layer to be considered active.
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.
Ady Abraham09bd3922019-04-08 10:44:56 -070043class LayerInfo {
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -070044 // 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
Ady Abraham09bd3922019-04-08 10:44:56 -070050 /**
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:
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -070057 explicit RefreshRateHistory(float highRefreshRate) : mHighRefreshRate(highRefreshRate) {}
58
59 void insertRefreshRate(float refreshRate) {
Ady Abraham09bd3922019-04-08 10:44:56 -070060 mElements.push_back(refreshRate);
61 if (mElements.size() > HISTORY_SIZE) {
62 mElements.pop_front();
63 }
64 }
65
66 float getRefreshRateAvg() const {
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -070067 return mElements.empty() ? mHighRefreshRate : calculate_mean(mElements);
Ady Abraham09bd3922019-04-08 10:44:56 -070068 }
Ady Abraham187d2d82019-07-10 16:18:48 -070069
Ady Abraham09bd3922019-04-08 10:44:56 -070070 void clearHistory() { mElements.clear(); }
71
72 private:
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -070073 const float mHighRefreshRate;
74
Ady Abraham09bd3922019-04-08 10:44:56 -070075 static constexpr size_t HISTORY_SIZE = 30;
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -070076 std::deque<float> mElements;
Ady Abraham09bd3922019-04-08 10:44:56 -070077 };
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:
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -070086 static constexpr size_t HISTORY_SIZE = 90;
87
Ady Abraham09bd3922019-04-08 10:44:56 -070088 void insertPresentTime(nsecs_t presentTime) {
89 mElements.push_back(presentTime);
90 if (mElements.size() > HISTORY_SIZE) {
91 mElements.pop_front();
92 }
93 }
94
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -070095 // Returns whether the earliest present time is within the active threshold.
96 bool isRecentlyActive(nsecs_t now) const {
Ady Abraham616b8322019-06-12 13:30:07 -070097 if (mElements.size() < 2) {
98 return false;
Ady Abraham09bd3922019-04-08 10:44:56 -070099 }
Ady Abraham616b8322019-06-12 13:30:07 -0700100
Ady Abraham0ccd79b2020-06-10 10:11:17 -0700101 // The layer had to publish at least HISTORY_SIZE or HISTORY_DURATION of updates
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700102 if (mElements.size() < HISTORY_SIZE &&
Ady Abraham0ccd79b2020-06-10 10:11:17 -0700103 mElements.back() - mElements.front() < HISTORY_DURATION.count()) {
Ady Abraham616b8322019-06-12 13:30:07 -0700104 return false;
105 }
106
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700107 return mElements.back() >= getActiveLayerThreshold(now);
Ady Abraham09bd3922019-04-08 10:44:56 -0700108 }
109
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700110 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) {
Ana Krulecad083c42019-06-26 16:28:08 -0700113 return false;
114 }
115
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700116 // 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;
Ana Krulecad083c42019-06-26 16:28:08 -0700121 }
122
Ady Abraham09bd3922019-04-08 10:44:56 -0700123 void clearHistory() { mElements.clear(); }
124
125 private:
126 std::deque<nsecs_t> mElements;
Ady Abraham0ccd79b2020-06-10 10:11:17 -0700127 static constexpr std::chrono::nanoseconds HISTORY_DURATION = 1s;
Ady Abraham09bd3922019-04-08 10:44:56 -0700128 };
129
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700130 friend class LayerHistoryTest;
131
Ady Abraham09bd3922019-04-08 10:44:56 -0700132public:
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700133 LayerInfo(float lowRefreshRate, float highRefreshRate);
Ady Abraham09bd3922019-04-08 10:44:56 -0700134
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.
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700141 void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now);
Ady Abraham09bd3922019-04-08 10:44:56 -0700142
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700143 bool isRecentlyActive(nsecs_t now) const { return mPresentTimeHistory.isRecentlyActive(now); }
144 bool isFrequent(nsecs_t now) const { return mPresentTimeHistory.isFrequent(now); }
Ady Abrahama315ce72019-04-24 14:35:20 -0700145
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700146 float getRefreshRate(nsecs_t now) const {
147 return isFrequent(now) ? mRefreshRateHistory.getRefreshRateAvg() : mLowRefreshRate;
Ady Abrahama315ce72019-04-24 14:35:20 -0700148 }
149
Ady Abraham09bd3922019-04-08 10:44:56 -0700150 // 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.
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700152 nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }
Ady Abraham09bd3922019-04-08 10:44:56 -0700153
154 void clearHistory() {
Ady Abraham09bd3922019-04-08 10:44:56 -0700155 mRefreshRateHistory.clearHistory();
156 mPresentTimeHistory.clearHistory();
157 }
158
159private:
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700160 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;
Ady Abraham09bd3922019-04-08 10:44:56 -0700167};
168
169} // namespace scheduler
Dominik Laskowskif7a09ed2019-10-07 13:54:18 -0700170} // namespace android