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