blob: 7f7dab3f0ee6ba985cef269bcadb90024b830fb2 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include "aidl/SessionTaskMap.h"
using std::literals::chrono_literals::operator""ms;
using std::literals::chrono_literals::operator""ns;
namespace aidl {
namespace google {
namespace hardware {
namespace power {
namespace impl {
namespace pixel {
SessionValueEntry makeSession(int tg) {
SessionValueEntry sv;
sv.tgid = tg;
sv.uid = tg + 1;
sv.idString = "Sess" + std::to_string(tg);
sv.isActive = true;
sv.isAppSession = false;
sv.lastUpdatedTime = std::chrono::steady_clock::now();
sv.votes = std::make_shared<Votes>();
return sv;
}
// Get all sessions associated with taskId
std::vector<int64_t> getSessions(int taskId, const SessionTaskMap &m) {
std::vector<int64_t> sessionIds;
m.forEachSessionInTask(
taskId, [&](int sessionId, const auto & /*sve*/) { sessionIds.push_back(sessionId); });
std::sort(sessionIds.begin(), sessionIds.end());
return sessionIds;
}
// Get all tasks associated with sessionId
std::vector<int> getTasks(int64_t sessionId, const SessionTaskMap &m) {
std::vector<int> tasks;
m.forEachSessionValTasks([&](int64_t sessId, const auto & /*sve*/, const auto &linkedTasks) {
if (sessId != sessionId)
return;
tasks.insert(std::end(tasks), std::begin(linkedTasks), std::end(linkedTasks));
});
std::sort(tasks.begin(), tasks.end());
return tasks;
}
// Tests ...
TEST(SessionTaskMapTest, add) {
SessionTaskMap m;
EXPECT_TRUE(m.add(1, makeSession(1000), {10, 20, 30}));
EXPECT_TRUE(m.add(2, makeSession(2000), {40, 50}));
EXPECT_TRUE(m.add(3, makeSession(2000), {60}));
EXPECT_FALSE(m.add(3, makeSession(2000), {70}));
}
TEST(SessionTaskMapTest, threeWayMappingSessions) {
SessionTaskMap m;
m.add(1, makeSession(1000), {10, 20, 30});
m.add(2, makeSession(2000), {40, 50, 60});
m.add(3, makeSession(3000), {50});
// Check three tasks map properly to sessions
EXPECT_EQ(std::vector<int64_t>({1}), getSessions(10, m));
EXPECT_EQ(std::vector<int64_t>({1}), getSessions(20, m));
EXPECT_EQ(std::vector<int64_t>({1}), getSessions(30, m));
EXPECT_EQ(std::vector<int64_t>({2}), getSessions(40, m));
EXPECT_EQ(std::vector<int64_t>({2, 3}), getSessions(50, m));
EXPECT_EQ(std::vector<int64_t>({2}), getSessions(60, m));
}
TEST(SessionTaskMapTest, threeWayMappingTasks) {
SessionTaskMap m;
m.add(1, makeSession(1000), {10, 20, 30});
m.add(2, makeSession(2000), {40, 50, 60});
m.add(3, makeSession(3000), {50});
// Check three sessions map properly to tasks
EXPECT_EQ(std::vector<int>({10, 20, 30}), getTasks(1, m));
EXPECT_EQ(std::vector<int>({40, 50, 60}), getTasks(2, m));
EXPECT_EQ(std::vector<int>({50}), getTasks(3, m));
}
TEST(SessionTaskMapTest, removeNonExisting) {
SessionTaskMap m;
EXPECT_FALSE(m.remove(1));
}
TEST(SessionTaskMapTest, removeMappingSessions) {
SessionTaskMap m;
m.add(1, makeSession(1000), {10, 20, 30});
m.add(2, makeSession(2000), {40, 50, 60});
m.add(3, makeSession(3000), {50});
// remove
EXPECT_TRUE(m.remove(2));
// Check that remaining tasks map correctly to sessions
EXPECT_EQ(std::vector<int64_t>({1}), getSessions(10, m));
EXPECT_EQ(std::vector<int64_t>({1}), getSessions(20, m));
EXPECT_EQ(std::vector<int64_t>({1}), getSessions(30, m));
EXPECT_EQ(std::vector<int64_t>({}), getSessions(40, m));
EXPECT_EQ(std::vector<int64_t>({3}), getSessions(50, m));
}
TEST(SessionTaskMapTest, removeMappingTasks) {
SessionTaskMap m;
EXPECT_FALSE(m.remove(1));
m.add(1, makeSession(1000), {10, 20, 30});
m.add(2, makeSession(2000), {40, 50, 60});
m.add(3, makeSession(3000), {50});
// remove
EXPECT_TRUE(m.remove(2));
EXPECT_FALSE(m.remove(2));
// Check that remaining tasks map correctly to sessions
EXPECT_EQ(std::vector<int>({10, 20, 30}), getTasks(1, m));
EXPECT_EQ(std::vector<int>({}), getTasks(2, m));
EXPECT_EQ(std::vector<int>({50}), getTasks(3, m));
}
TEST(SessionTaskMapTest, findEmpty) {
SessionTaskMap m;
EXPECT_EQ(nullptr, m.findSession(1));
}
TEST(SessionTaskMapTest, findSessionExists) {
SessionTaskMap m;
EXPECT_TRUE(m.add(1, makeSession(1000), {}));
EXPECT_NE(nullptr, m.findSession(1));
}
TEST(SessionTaskMapTest, findSessionEmptyExistsEmpty) {
SessionTaskMap m;
EXPECT_EQ(nullptr, m.findSession(1));
EXPECT_TRUE(m.add(1, makeSession(1000), {}));
EXPECT_NE(nullptr, m.findSession(1));
EXPECT_TRUE(m.remove(1));
EXPECT_EQ(nullptr, m.findSession(1));
}
TEST(SessionTaskMapTest, sizeTasks) {
SessionTaskMap m;
EXPECT_EQ(0, m.sizeTasks());
EXPECT_TRUE(m.add(1, makeSession(1000), {10, 20, 30}));
EXPECT_TRUE(m.add(2, makeSession(2000), {40, 50, 60}));
EXPECT_EQ(6, m.sizeTasks());
}
TEST(SessionTaskMapTest, sizeSessions) {
SessionTaskMap m;
EXPECT_EQ(0, m.sizeSessions());
EXPECT_TRUE(m.add(1, makeSession(1000), {10, 20, 30}));
EXPECT_TRUE(m.add(2, makeSession(2000), {40, 50, 60}));
EXPECT_EQ(2, m.sizeSessions());
}
TEST(SessionTaskMapTest, replace) {
SessionTaskMap m;
// Add three sessions where sessions 2 and 3 have shared threads
EXPECT_TRUE(m.add(1, makeSession(1000), {10, 20, 30}));
EXPECT_TRUE(m.add(2, makeSession(2000), {20}));
std::vector<pid_t> addedThreads;
std::vector<pid_t> removedThreads;
m.replace(1, {10, 40}, &addedThreads, &removedThreads);
EXPECT_EQ(1, addedThreads.size());
EXPECT_EQ(40, addedThreads[0]);
EXPECT_EQ(1, removedThreads.size());
EXPECT_EQ(30, removedThreads[0]);
}
TEST(SessionTaskMapTest, remove) {
SessionTaskMap m;
auto tNow = std::chrono::steady_clock::now();
const int64_t sessionId = 1;
SessionValueEntry sve;
sve.isAppSession = true;
sve.votes = std::make_shared<Votes>();
sve.votes->add(sessionId, VoteRange::makeMinRange(123, tNow, 400ms));
m.add(sessionId, sve, {10, 20, 30});
EXPECT_TRUE(m.isAnyAppSessionActive(tNow));
EXPECT_TRUE(m.remove(sessionId));
EXPECT_FALSE(m.isAnyAppSessionActive(tNow));
}
TEST(SessionTaskMapTest, isAnyAppActive) {
SessionTaskMap m;
auto tNow = std::chrono::steady_clock::now();
EXPECT_FALSE(m.isAnyAppSessionActive(tNow));
const int sessionId = 1000;
SessionValueEntry sv;
sv.isActive = true;
sv.isAppSession = true;
sv.lastUpdatedTime = tNow;
sv.votes = std::make_shared<Votes>();
sv.votes->add(1, VoteRange::makeMinRange(123, tNow, 400ms));
EXPECT_TRUE(m.add(sessionId, sv, {10, 20, 30}));
EXPECT_TRUE(m.isAnyAppSessionActive(tNow));
EXPECT_FALSE(m.isAnyAppSessionActive(tNow + 500ms));
}
int getVoteMin(const SessionTaskMap &m, int64_t taskId, std::chrono::steady_clock::time_point t) {
int uclampMin;
int uclampMax;
m.getTaskVoteRange(taskId, t, &uclampMin, &uclampMax);
return uclampMin;
}
TEST(SessionTaskMapTest, votesEdgeCaseOverlap) {
SessionTaskMap m;
// Sess 1: 10
EXPECT_TRUE(m.add(1, makeSession(1000), {10}));
const auto t0 = std::chrono::steady_clock::now();
const int voteMax = 1000;
// Session Vote UClamp [Time start----------------Time End] Delta
// 1 1 111 [20----60] 40
// 1 2 122 [60-85] 25
// 1 3 133 [60--90] 30
m.addVote(1, 1, 111, voteMax, t0 + 20ns, 40ns);
m.addVote(1, 2, 122, voteMax, t0 + 60ns, 25ns);
m.addVote(1, 3, 133, voteMax, t0 + 60ns, 30ns);
// Before any votes active
EXPECT_EQ(0, getVoteMin(m, 10, t0 + 0ns));
// First vote active
EXPECT_EQ(111, getVoteMin(m, 10, t0 + 20ns));
// In middle of first vote
EXPECT_EQ(111, getVoteMin(m, 10, t0 + 35ns));
// First, second, and third votes active
EXPECT_EQ(133, getVoteMin(m, 10, t0 + 60ns));
// Second and third votes are being used
EXPECT_EQ(133, getVoteMin(m, 10, t0 + 61ns));
// Third vote is being used
EXPECT_EQ(133, getVoteMin(m, 10, t0 + 86ns));
// No votes active
EXPECT_EQ(0, getVoteMin(m, 10, t0 + 91ns));
}
TEST(SessionTaskMapTest, votesEdgeCaseNoOverlap) {
SessionTaskMap m;
// Sess 2: 30
EXPECT_TRUE(m.add(2, makeSession(2000), {20}));
const auto t0 = std::chrono::steady_clock::now();
const int voteMax = 1000;
// Session Vote UClamp [Time start----------------Time End] Delta
// 2 1 211 [30-55] 25
// 2 2 222 [100-135] 35
// 2 3 233 [140-180] 40
m.addVote(2, 1, 211, voteMax, t0 + 30ns, 25ns);
m.addVote(2, 2, 222, voteMax, t0 + 100ns, 35ns);
m.addVote(2, 3, 233, voteMax, t0 + 140ns, 40ns);
// No votes active yet
EXPECT_EQ(0, getVoteMin(m, 20, t0 + 0ns));
// First vote active
EXPECT_EQ(211, getVoteMin(m, 20, t0 + 30ns));
// Second vote active
EXPECT_EQ(222, getVoteMin(m, 20, t0 + 100ns));
// Third vote active
EXPECT_EQ(233, getVoteMin(m, 20, t0 + 140ns));
// No votes active
EXPECT_EQ(0, getVoteMin(m, 20, t0 + 181ns));
}
TEST(SessionTaskMapTest, TwoSessionsOneInactive) {
const auto tNow = std::chrono::steady_clock::now();
SessionTaskMap m;
{
SessionValueEntry sv;
sv.isActive = true;
sv.isAppSession = true;
sv.lastUpdatedTime = tNow;
sv.votes = std::make_shared<Votes>();
sv.votes->add(11, VoteRange::makeMinRange(111, tNow, 400ms));
EXPECT_TRUE(m.add(1001, sv, {10, 20, 30}));
}
{
SessionValueEntry sv;
sv.isActive = true;
sv.isAppSession = true;
sv.lastUpdatedTime = tNow;
sv.votes = std::make_shared<Votes>();
sv.votes->add(22, VoteRange::makeMinRange(222, tNow, 400ms));
EXPECT_TRUE(m.add(2001, sv, {10, 20, 30}));
}
UclampRange uclampRange;
m.getTaskVoteRange(10, tNow + 10ns, &uclampRange.uclampMin, &uclampRange.uclampMax);
EXPECT_EQ(222, uclampRange.uclampMin);
auto sessItr = m.findSession(2001);
EXPECT_NE(nullptr, sessItr);
sessItr->isActive = false;
uclampRange.uclampMin = 0;
uclampRange.uclampMax = 1024;
m.getTaskVoteRange(10, tNow + 10ns, &uclampRange.uclampMin, &uclampRange.uclampMax);
EXPECT_EQ(111, uclampRange.uclampMin);
}
} // namespace pixel
} // namespace impl
} // namespace power
} // namespace hardware
} // namespace google
} // namespace aidl