1 /*
2 * Copyright (C) 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 <gtest/gtest.h>
18
19 #include "aidl/SessionTaskMap.h"
20
21 using std::literals::chrono_literals::operator""ms;
22 using std::literals::chrono_literals::operator""ns;
23
24 namespace aidl {
25 namespace google {
26 namespace hardware {
27 namespace power {
28 namespace impl {
29 namespace pixel {
30
makeSession(int tg)31 SessionValueEntry makeSession(int tg) {
32 SessionValueEntry sv;
33 sv.tgid = tg;
34 sv.uid = tg + 1;
35 sv.idString = "Sess" + std::to_string(tg);
36 sv.isActive = true;
37 sv.isAppSession = false;
38 sv.lastUpdatedTime = std::chrono::steady_clock::now();
39 sv.votes = std::make_shared<Votes>();
40 return sv;
41 }
42
43 // Get all sessions associated with taskId
getSessions(int taskId,const SessionTaskMap & m)44 std::vector<int64_t> getSessions(int taskId, const SessionTaskMap &m) {
45 std::vector<int64_t> sessionIds;
46 m.forEachSessionInTask(
47 taskId, [&](int sessionId, const auto & /*sve*/) { sessionIds.push_back(sessionId); });
48 std::sort(sessionIds.begin(), sessionIds.end());
49 return sessionIds;
50 }
51
52 // Get all tasks associated with sessionId
getTasks(int64_t sessionId,const SessionTaskMap & m)53 std::vector<int> getTasks(int64_t sessionId, const SessionTaskMap &m) {
54 std::vector<int> tasks;
55 m.forEachSessionValTasks([&](int64_t sessId, const auto & /*sve*/, const auto &linkedTasks) {
56 if (sessId != sessionId)
57 return;
58 tasks.insert(std::end(tasks), std::begin(linkedTasks), std::end(linkedTasks));
59 });
60 std::sort(tasks.begin(), tasks.end());
61 return tasks;
62 }
63
64 // Tests ...
TEST(SessionTaskMapTest,add)65 TEST(SessionTaskMapTest, add) {
66 SessionTaskMap m;
67 EXPECT_TRUE(m.add(1, makeSession(1000), {10, 20, 30}));
68 EXPECT_TRUE(m.add(2, makeSession(2000), {40, 50}));
69 EXPECT_TRUE(m.add(3, makeSession(2000), {60}));
70 EXPECT_FALSE(m.add(3, makeSession(2000), {70}));
71 }
72
TEST(SessionTaskMapTest,threeWayMappingSessions)73 TEST(SessionTaskMapTest, threeWayMappingSessions) {
74 SessionTaskMap m;
75 m.add(1, makeSession(1000), {10, 20, 30});
76 m.add(2, makeSession(2000), {40, 50, 60});
77 m.add(3, makeSession(3000), {50});
78
79 // Check three tasks map properly to sessions
80 EXPECT_EQ(std::vector<int64_t>({1}), getSessions(10, m));
81 EXPECT_EQ(std::vector<int64_t>({1}), getSessions(20, m));
82 EXPECT_EQ(std::vector<int64_t>({1}), getSessions(30, m));
83 EXPECT_EQ(std::vector<int64_t>({2}), getSessions(40, m));
84 EXPECT_EQ(std::vector<int64_t>({2, 3}), getSessions(50, m));
85 EXPECT_EQ(std::vector<int64_t>({2}), getSessions(60, m));
86 }
87
TEST(SessionTaskMapTest,threeWayMappingTasks)88 TEST(SessionTaskMapTest, threeWayMappingTasks) {
89 SessionTaskMap m;
90 m.add(1, makeSession(1000), {10, 20, 30});
91 m.add(2, makeSession(2000), {40, 50, 60});
92 m.add(3, makeSession(3000), {50});
93
94 // Check three sessions map properly to tasks
95 EXPECT_EQ(std::vector<int>({10, 20, 30}), getTasks(1, m));
96 EXPECT_EQ(std::vector<int>({40, 50, 60}), getTasks(2, m));
97 EXPECT_EQ(std::vector<int>({50}), getTasks(3, m));
98 }
99
TEST(SessionTaskMapTest,removeNonExisting)100 TEST(SessionTaskMapTest, removeNonExisting) {
101 SessionTaskMap m;
102 EXPECT_FALSE(m.remove(1));
103 }
104
TEST(SessionTaskMapTest,removeMappingSessions)105 TEST(SessionTaskMapTest, removeMappingSessions) {
106 SessionTaskMap m;
107 m.add(1, makeSession(1000), {10, 20, 30});
108 m.add(2, makeSession(2000), {40, 50, 60});
109 m.add(3, makeSession(3000), {50});
110
111 // remove
112 EXPECT_TRUE(m.remove(2));
113
114 // Check that remaining tasks map correctly to sessions
115 EXPECT_EQ(std::vector<int64_t>({1}), getSessions(10, m));
116 EXPECT_EQ(std::vector<int64_t>({1}), getSessions(20, m));
117 EXPECT_EQ(std::vector<int64_t>({1}), getSessions(30, m));
118 EXPECT_EQ(std::vector<int64_t>({}), getSessions(40, m));
119 EXPECT_EQ(std::vector<int64_t>({3}), getSessions(50, m));
120 }
121
TEST(SessionTaskMapTest,removeMappingTasks)122 TEST(SessionTaskMapTest, removeMappingTasks) {
123 SessionTaskMap m;
124 EXPECT_FALSE(m.remove(1));
125
126 m.add(1, makeSession(1000), {10, 20, 30});
127 m.add(2, makeSession(2000), {40, 50, 60});
128 m.add(3, makeSession(3000), {50});
129
130 // remove
131 EXPECT_TRUE(m.remove(2));
132 EXPECT_FALSE(m.remove(2));
133
134 // Check that remaining tasks map correctly to sessions
135 EXPECT_EQ(std::vector<int>({10, 20, 30}), getTasks(1, m));
136 EXPECT_EQ(std::vector<int>({}), getTasks(2, m));
137 EXPECT_EQ(std::vector<int>({50}), getTasks(3, m));
138 }
139
TEST(SessionTaskMapTest,findEmpty)140 TEST(SessionTaskMapTest, findEmpty) {
141 SessionTaskMap m;
142 EXPECT_EQ(nullptr, m.findSession(1));
143 }
144
TEST(SessionTaskMapTest,findSessionExists)145 TEST(SessionTaskMapTest, findSessionExists) {
146 SessionTaskMap m;
147 EXPECT_TRUE(m.add(1, makeSession(1000), {}));
148 EXPECT_NE(nullptr, m.findSession(1));
149 }
150
TEST(SessionTaskMapTest,findSessionEmptyExistsEmpty)151 TEST(SessionTaskMapTest, findSessionEmptyExistsEmpty) {
152 SessionTaskMap m;
153 EXPECT_EQ(nullptr, m.findSession(1));
154 EXPECT_TRUE(m.add(1, makeSession(1000), {}));
155 EXPECT_NE(nullptr, m.findSession(1));
156 EXPECT_TRUE(m.remove(1));
157 EXPECT_EQ(nullptr, m.findSession(1));
158 }
159
TEST(SessionTaskMapTest,sizeTasks)160 TEST(SessionTaskMapTest, sizeTasks) {
161 SessionTaskMap m;
162 EXPECT_EQ(0, m.sizeTasks());
163 EXPECT_TRUE(m.add(1, makeSession(1000), {10, 20, 30}));
164 EXPECT_TRUE(m.add(2, makeSession(2000), {40, 50, 60}));
165 EXPECT_EQ(6, m.sizeTasks());
166 }
167
TEST(SessionTaskMapTest,sizeSessions)168 TEST(SessionTaskMapTest, sizeSessions) {
169 SessionTaskMap m;
170 EXPECT_EQ(0, m.sizeSessions());
171 EXPECT_TRUE(m.add(1, makeSession(1000), {10, 20, 30}));
172 EXPECT_TRUE(m.add(2, makeSession(2000), {40, 50, 60}));
173 EXPECT_EQ(2, m.sizeSessions());
174 }
175
TEST(SessionTaskMapTest,replace)176 TEST(SessionTaskMapTest, replace) {
177 SessionTaskMap m;
178
179 // Add three sessions where sessions 2 and 3 have shared threads
180 EXPECT_TRUE(m.add(1, makeSession(1000), {10, 20, 30}));
181 EXPECT_TRUE(m.add(2, makeSession(2000), {20}));
182
183 std::vector<pid_t> addedThreads;
184 std::vector<pid_t> removedThreads;
185
186 m.replace(1, {10, 40}, &addedThreads, &removedThreads);
187 EXPECT_EQ(1, addedThreads.size());
188 EXPECT_EQ(40, addedThreads[0]);
189
190 EXPECT_EQ(1, removedThreads.size());
191 EXPECT_EQ(30, removedThreads[0]);
192 }
193
TEST(SessionTaskMapTest,remove)194 TEST(SessionTaskMapTest, remove) {
195 SessionTaskMap m;
196 auto tNow = std::chrono::steady_clock::now();
197 const int64_t sessionId = 1;
198 SessionValueEntry sve;
199 sve.isAppSession = true;
200 sve.votes = std::make_shared<Votes>();
201 sve.votes->add(sessionId, CpuVote(true, tNow, 400ms, 123, 1024));
202 m.add(sessionId, sve, {10, 20, 30});
203 EXPECT_TRUE(m.isAnyAppSessionActive(tNow));
204 EXPECT_TRUE(m.remove(sessionId));
205 EXPECT_FALSE(m.isAnyAppSessionActive(tNow));
206 }
207
TEST(SessionTaskMapTest,isAnyAppActive)208 TEST(SessionTaskMapTest, isAnyAppActive) {
209 SessionTaskMap m;
210 auto tNow = std::chrono::steady_clock::now();
211
212 EXPECT_FALSE(m.isAnyAppSessionActive(tNow));
213
214 const int sessionId = 1000;
215 SessionValueEntry sv;
216 sv.isActive = true;
217 sv.isAppSession = true;
218 sv.lastUpdatedTime = tNow;
219 sv.votes = std::make_shared<Votes>();
220 sv.votes->add(1, CpuVote(true, tNow, 400ms, 123, 1024));
221
222 EXPECT_TRUE(m.add(sessionId, sv, {10, 20, 30}));
223 EXPECT_TRUE(m.isAnyAppSessionActive(tNow));
224 EXPECT_FALSE(m.isAnyAppSessionActive(tNow + 500ms));
225 }
226
getVoteMin(const SessionTaskMap & m,int64_t taskId,std::chrono::steady_clock::time_point t)227 int getVoteMin(const SessionTaskMap &m, int64_t taskId, std::chrono::steady_clock::time_point t) {
228 UclampRange range;
229 std::optional<int32_t> fakeEfficiencyParam = std::nullopt;
230 m.getTaskVoteRange(taskId, t, range, fakeEfficiencyParam, fakeEfficiencyParam);
231 return range.uclampMin;
232 }
233
TEST(SessionTaskMapTest,votesEdgeCaseOverlap)234 TEST(SessionTaskMapTest, votesEdgeCaseOverlap) {
235 SessionTaskMap m;
236
237 // Sess 1: 10
238 EXPECT_TRUE(m.add(1, makeSession(1000), {10}));
239 const auto t0 = std::chrono::steady_clock::now();
240 const int voteMax = 1000;
241
242 // Session Vote UClamp [Time start----------------Time End] Delta
243 // 1 1 111 [20----60] 40
244 // 1 2 122 [60-85] 25
245 // 1 3 133 [60--90] 30
246 m.addVote(1, 1, 111, voteMax, t0 + 20ns, 40ns);
247 m.addVote(1, 2, 122, voteMax, t0 + 60ns, 25ns);
248 m.addVote(1, 3, 133, voteMax, t0 + 60ns, 30ns);
249
250 // Before any votes active
251 EXPECT_EQ(0, getVoteMin(m, 10, t0 + 0ns));
252 // First vote active
253 EXPECT_EQ(111, getVoteMin(m, 10, t0 + 20ns));
254 // In middle of first vote
255 EXPECT_EQ(111, getVoteMin(m, 10, t0 + 35ns));
256 // First, second, and third votes active
257 EXPECT_EQ(133, getVoteMin(m, 10, t0 + 60ns));
258 // Second and third votes are being used
259 EXPECT_EQ(133, getVoteMin(m, 10, t0 + 61ns));
260 // Third vote is being used
261 EXPECT_EQ(133, getVoteMin(m, 10, t0 + 86ns));
262 // No votes active
263 EXPECT_EQ(0, getVoteMin(m, 10, t0 + 91ns));
264 }
265
TEST(SessionTaskMapTest,votesEdgeCaseNoOverlap)266 TEST(SessionTaskMapTest, votesEdgeCaseNoOverlap) {
267 SessionTaskMap m;
268 // Sess 2: 30
269 EXPECT_TRUE(m.add(2, makeSession(2000), {20}));
270 const auto t0 = std::chrono::steady_clock::now();
271 const int voteMax = 1000;
272
273 // Session Vote UClamp [Time start----------------Time End] Delta
274 // 2 1 211 [30-55] 25
275 // 2 2 222 [100-135] 35
276 // 2 3 233 [140-180] 40
277 m.addVote(2, 1, 211, voteMax, t0 + 30ns, 25ns);
278 m.addVote(2, 2, 222, voteMax, t0 + 100ns, 35ns);
279 m.addVote(2, 3, 233, voteMax, t0 + 140ns, 40ns);
280
281 // No votes active yet
282 EXPECT_EQ(0, getVoteMin(m, 20, t0 + 0ns));
283 // First vote active
284 EXPECT_EQ(211, getVoteMin(m, 20, t0 + 30ns));
285 // Second vote active
286 EXPECT_EQ(222, getVoteMin(m, 20, t0 + 100ns));
287 // Third vote active
288 EXPECT_EQ(233, getVoteMin(m, 20, t0 + 140ns));
289 // No votes active
290 EXPECT_EQ(0, getVoteMin(m, 20, t0 + 181ns));
291 }
292
TEST(SessionTaskMapTest,TwoSessionsOneInactive)293 TEST(SessionTaskMapTest, TwoSessionsOneInactive) {
294 const auto tNow = std::chrono::steady_clock::now();
295 SessionTaskMap m;
296
297 {
298 SessionValueEntry sv;
299 sv.isActive = true;
300 sv.isAppSession = true;
301 sv.lastUpdatedTime = tNow;
302 sv.votes = std::make_shared<Votes>();
303 sv.votes->add(11, CpuVote(true, tNow, 400ms, 111, 1024));
304 EXPECT_TRUE(m.add(1001, sv, {10, 20, 30}));
305 }
306
307 {
308 SessionValueEntry sv;
309 sv.isActive = true;
310 sv.isAppSession = true;
311 sv.lastUpdatedTime = tNow;
312 sv.votes = std::make_shared<Votes>();
313 sv.votes->add(22, CpuVote(true, tNow, 400ms, 222, 1024));
314 EXPECT_TRUE(m.add(2001, sv, {10, 20, 30}));
315 }
316
317 UclampRange uclampRange;
318 std::optional<int32_t> fakeEfficiencyParam;
319 m.getTaskVoteRange(10, tNow + 10ns, uclampRange, fakeEfficiencyParam, fakeEfficiencyParam);
320 EXPECT_EQ(222, uclampRange.uclampMin);
321
322 auto sessItr = m.findSession(2001);
323 EXPECT_NE(nullptr, sessItr);
324 sessItr->isActive = false;
325
326 uclampRange.uclampMin = 0;
327 uclampRange.uclampMax = 1024;
328 m.getTaskVoteRange(10, tNow + 10ns, uclampRange, fakeEfficiencyParam, fakeEfficiencyParam);
329 EXPECT_EQ(111, uclampRange.uclampMin);
330 }
331
TEST(SessionTaskMapTest,GpuVoteBasic)332 TEST(SessionTaskMapTest, GpuVoteBasic) {
333 const auto now = std::chrono::steady_clock::now();
334 SessionTaskMap m;
335 auto const session_id1 = 1001;
336 auto const session_id2 = 1002;
337 static auto constexpr gpu_vote_id = static_cast<int>(AdpfVoteType::GPU_CAPACITY);
338
339 auto addSessionWithId = [&](int id) {
340 SessionValueEntry sv{.isActive = true,
341 .isAppSession = true,
342 .lastUpdatedTime = now,
343 .votes = std::make_shared<Votes>()};
344 EXPECT_TRUE(m.add(id, sv, {10, 20, 30}));
345 };
346 addSessionWithId(session_id1);
347 addSessionWithId(session_id2);
348
349 m.addGpuVote(session_id1, gpu_vote_id, Cycles(222), now, 400ms);
350 EXPECT_EQ(m.getSessionsGpuCapacity(now + 1ms), Cycles(222));
351 EXPECT_EQ(m.getSessionsGpuCapacity(now + 401ms), Cycles(0));
352
353 m.addGpuVote(session_id1, gpu_vote_id, Cycles(111), now, 100ms);
354 EXPECT_EQ(m.getSessionsGpuCapacity(now + 1ms), Cycles(111));
355 EXPECT_EQ(m.getSessionsGpuCapacity(now + 101ms), Cycles(0));
356
357 m.addGpuVote(session_id2, gpu_vote_id, Cycles(555), now, 50ms);
358 EXPECT_EQ(m.getSessionsGpuCapacity(now + 1ms), Cycles(555));
359 EXPECT_EQ(m.getSessionsGpuCapacity(now + 51ms), Cycles(111));
360 EXPECT_EQ(m.getSessionsGpuCapacity(now + 101ms), Cycles(0));
361 }
362
TEST(SessionTaskMapTest,GpuVoteDifferentHints)363 TEST(SessionTaskMapTest, GpuVoteDifferentHints) {
364 const auto now = std::chrono::steady_clock::now();
365 SessionTaskMap m;
366 auto const session_id1 = 1001;
367 auto const session_id2 = 1002;
368
369 auto const capacity_vote_id = static_cast<int>(AdpfVoteType::GPU_CAPACITY);
370 auto const load_vote_id = static_cast<int>(AdpfVoteType::GPU_LOAD_UP);
371
372 auto addSessionWithId = [&](int id) {
373 SessionValueEntry sv{.isActive = true,
374 .isAppSession = true,
375 .lastUpdatedTime = now,
376 .votes = std::make_shared<Votes>()};
377 EXPECT_TRUE(m.add(id, sv, {10, 20, 30}));
378 };
379 addSessionWithId(session_id1);
380 addSessionWithId(session_id2);
381
382 m.addGpuVote(session_id1, capacity_vote_id, Cycles(222), now, 400ms);
383 m.addGpuVote(session_id1, load_vote_id, Cycles(111), now, 100ms);
384 EXPECT_EQ(m.getSessionsGpuCapacity(now + 1ms), Cycles(333));
385 EXPECT_EQ(m.getSessionsGpuCapacity(now + 101ms), Cycles(222));
386 EXPECT_EQ(m.getSessionsGpuCapacity(now + 401ms), Cycles(0));
387
388 m.addGpuVote(session_id2, capacity_vote_id, Cycles(321), now, 150ms);
389 m.addGpuVote(session_id2, load_vote_id, Cycles(123), now, 50ms);
390 EXPECT_EQ(m.getSessionsGpuCapacity(now + 1ms), Cycles(444));
391 EXPECT_EQ(m.getSessionsGpuCapacity(now + 51ms), Cycles(333));
392 EXPECT_EQ(m.getSessionsGpuCapacity(now + 151ms), Cycles(222));
393 }
394
TEST(SessionTaskMapTest,usesPowerEfficiencyValues)395 TEST(SessionTaskMapTest, usesPowerEfficiencyValues) {
396 SessionTaskMap m;
397 SessionValueEntry entry = makeSession(2000);
398 m.add(2, entry, {20});
399 entry.isPowerEfficient = true;
400 m.add(3, entry, {30});
401
402 const auto t0 = std::chrono::steady_clock::now();
403
404 std::optional<int32_t> maxEfficientBase = 400;
405 std::optional<int32_t> maxEfficientOffset = 200;
406
407 UclampRange baseVote{.uclampMin = 100, .uclampMax = 1024};
408
409 m.addVote(2, 1, baseVote.uclampMin, baseVote.uclampMax, t0, 400ns);
410 m.addVote(3, 1, baseVote.uclampMin, baseVote.uclampMax, t0, 400ns);
411
412 UclampRange range;
413 m.getTaskVoteRange(30, t0 + 10ns, range, maxEfficientBase, maxEfficientOffset);
414 // During the boost we expect it to equal the dynamic value
415 EXPECT_EQ(range.uclampMax, baseVote.uclampMin + *maxEfficientOffset);
416
417 range = UclampRange{};
418 m.getTaskVoteRange(30, t0 + 800ns, range, maxEfficientBase, maxEfficientOffset);
419 // After the boost expires, we expect it to equal the static value
420 EXPECT_EQ(range.uclampMax, *maxEfficientBase);
421
422 range = UclampRange{};
423 m.getTaskVoteRange(20, t0 + 10ns, range, maxEfficientBase, maxEfficientOffset);
424 // We expect this to be unaffected since this session has no power efficiency set
425 EXPECT_EQ(range.uclampMax, baseVote.uclampMax);
426
427 range = UclampRange{};
428 m.getTaskVoteRange(20, t0 + 800ns, range, maxEfficientBase, maxEfficientOffset);
429 // We expect this to be unaffected since this session has no power efficiency set
430 EXPECT_EQ(range.uclampMax, baseVote.uclampMax);
431 }
432
433 } // namespace pixel
434 } // namespace impl
435 } // namespace power
436 } // namespace hardware
437 } // namespace google
438 } // namespace aidl
439