1 /*
2 * Copyright 2023 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 "UClampVoter.h"
18
19 namespace aidl {
20 namespace google {
21 namespace hardware {
22 namespace power {
23 namespace impl {
24 namespace pixel {
25
confine(UclampRange & uclampRange,const CpuVote & cpu_vote,std::chrono::steady_clock::time_point t)26 static void confine(UclampRange &uclampRange, const CpuVote &cpu_vote,
27 std::chrono::steady_clock::time_point t) {
28 if (!cpu_vote.isTimeInRange(t)) {
29 return;
30 }
31 uclampRange.uclampMin = std::max(uclampRange.uclampMin, cpu_vote.mUclampRange.uclampMin);
32 uclampRange.uclampMax = std::min(uclampRange.uclampMax, cpu_vote.mUclampRange.uclampMax);
33 }
34
operator <<(std::ostream & o,const UclampRange & uc)35 std::ostream &operator<<(std::ostream &o, const UclampRange &uc) {
36 o << "[" << uc.uclampMin << "," << uc.uclampMax << "]";
37 return o;
38 }
39
Votes()40 Votes::Votes() {}
41
42 constexpr static auto gpu_vote_id = static_cast<int>(AdpfVoteType::GPU_CAPACITY);
43
isGpuVote(int type_raw)44 static inline bool isGpuVote(int type_raw) {
45 AdpfVoteType const type = static_cast<AdpfVoteType>(type_raw);
46 return type == AdpfVoteType::GPU_CAPACITY || type == AdpfVoteType::GPU_LOAD_UP ||
47 type == AdpfVoteType::GPU_LOAD_DOWN || type == AdpfVoteType::GPU_LOAD_RESET;
48 }
49
add(int id,CpuVote const & vote)50 void Votes::add(int id, CpuVote const &vote) {
51 if (!isGpuVote(id)) {
52 mCpuVotes[id] = vote;
53 }
54 }
55
getGpuCapacityRequest(std::chrono::steady_clock::time_point t) const56 std::optional<Cycles> Votes::getGpuCapacityRequest(std::chrono::steady_clock::time_point t) const {
57 std::optional<Cycles> res = std::nullopt;
58
59 constexpr AdpfVoteType gpu_capacity_hints[] = {
60 AdpfVoteType::GPU_CAPACITY,
61 AdpfVoteType::GPU_LOAD_UP,
62 };
63 for (auto const hint : gpu_capacity_hints) {
64 auto it = mGpuVotes.find(static_cast<int>(hint));
65 if (it != mGpuVotes.end() && it->second.isTimeInRange(t)) {
66 res = res.value_or(Cycles(0)) + it->second.mCapacity;
67 }
68 }
69
70 return res;
71 }
72
add(int id,GpuVote const & vote)73 void Votes::add(int id, GpuVote const &vote) {
74 if (isGpuVote(id)) {
75 mGpuVotes[id] = vote;
76 }
77 }
78
updateDuration(int voteId,std::chrono::nanoseconds durationNs)79 void Votes::updateDuration(int voteId, std::chrono::nanoseconds durationNs) {
80 if (isGpuVote(voteId)) {
81 auto const it = mGpuVotes.find(voteId);
82 if (it != mGpuVotes.end()) {
83 it->second.updateDuration(durationNs);
84 }
85 return;
86 }
87
88 auto const voteItr = mCpuVotes.find(voteId);
89 if (voteItr != mCpuVotes.end()) {
90 voteItr->second.updateDuration(durationNs);
91 }
92 }
93
getUclampRange(UclampRange & uclampRange,std::chrono::steady_clock::time_point t) const94 void Votes::getUclampRange(UclampRange &uclampRange,
95 std::chrono::steady_clock::time_point t) const {
96 for (auto it = mCpuVotes.begin(); it != mCpuVotes.end(); it++) {
97 auto timings_it = mCpuVotes.find(it->first);
98 confine(uclampRange, it->second, t);
99 }
100 }
101
anyTimedOut(std::chrono::steady_clock::time_point t) const102 bool Votes::anyTimedOut(std::chrono::steady_clock::time_point t) const {
103 for (const auto &v : mGpuVotes) {
104 if (!v.second.isTimeInRange(t)) {
105 return true;
106 }
107 }
108
109 for (const auto &v : mCpuVotes) {
110 if (!v.second.isTimeInRange(t)) {
111 return true;
112 }
113 }
114 return false;
115 }
116
allTimedOut(std::chrono::steady_clock::time_point t) const117 bool Votes::allTimedOut(std::chrono::steady_clock::time_point t) const {
118 for (const auto &v : mGpuVotes) {
119 if (v.second.isTimeInRange(t)) {
120 return false;
121 }
122 }
123
124 for (const auto &v : mCpuVotes) {
125 if (v.second.isTimeInRange(t)) {
126 return false;
127 }
128 }
129 return true;
130 }
131
remove(int voteId)132 bool Votes::remove(int voteId) {
133 if (isGpuVote(voteId)) {
134 auto const it = mGpuVotes.find(voteId);
135 if (it != mGpuVotes.end()) {
136 mGpuVotes.erase(it);
137 return true;
138 }
139 return false;
140 }
141
142 auto const it = mCpuVotes.find(voteId);
143 if (it != mCpuVotes.end()) {
144 mCpuVotes.erase(it);
145 return true;
146 }
147
148 return false;
149 }
150
setUseVote(int voteId,bool active)151 bool Votes::setUseVote(int voteId, bool active) {
152 if (isGpuVote(voteId)) {
153 auto const itr = mGpuVotes.find(voteId);
154 if (itr == mGpuVotes.end()) {
155 return false;
156 }
157 itr->second.setActive(active);
158 return true;
159 }
160
161 auto const itr = mCpuVotes.find(voteId);
162 if (itr == mCpuVotes.end()) {
163 return false;
164 }
165 itr->second.setActive(active);
166 return true;
167 }
168
size() const169 size_t Votes::size() const {
170 return mCpuVotes.size() + mGpuVotes.size();
171 }
172
voteIsActive(int voteId) const173 bool Votes::voteIsActive(int voteId) const {
174 if (isGpuVote(voteId)) {
175 auto const itr = mGpuVotes.find(voteId);
176 if (itr == mGpuVotes.end()) {
177 return false;
178 }
179 return itr->second.active();
180 }
181
182 auto const itr = mCpuVotes.find(voteId);
183 if (itr == mCpuVotes.end()) {
184 return false;
185 }
186 return itr->second.active();
187 }
188
voteTimeout(int voteId) const189 std::chrono::steady_clock::time_point Votes::voteTimeout(int voteId) const {
190 if (isGpuVote(voteId)) {
191 auto const itr = mGpuVotes.find(voteId);
192 if (itr == mGpuVotes.end()) {
193 return std::chrono::steady_clock::time_point{};
194 }
195 return itr->second.startTime() + itr->second.durationNs();
196 }
197
198 auto const itr = mCpuVotes.find(voteId);
199 if (itr == mCpuVotes.end()) {
200 return std::chrono::steady_clock::time_point{};
201 }
202 return itr->second.startTime() + itr->second.durationNs();
203 }
204
205 } // namespace pixel
206 } // namespace impl
207 } // namespace power
208 } // namespace hardware
209 } // namespace google
210 } // namespace aidl
211