blob: fc06317a2165608a1edccf9a61e4f9c21717a2b3 [file] [log] [blame]
/*
* Copyright 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 "SessionTaskMap.h"
#include <algorithm>
#include <sstream>
namespace aidl {
namespace google {
namespace hardware {
namespace power {
namespace impl {
namespace pixel {
bool SessionTaskMap::add(int64_t sessionId, const SessionValueEntry &sv,
const std::vector<pid_t> &taskIds) {
if (mSessions.find(sessionId) != mSessions.end()) {
return false;
}
auto sessValPtr = std::make_shared<SessionValueEntry>();
(*sessValPtr) = sv;
sessValPtr->sessionId = sessionId;
auto &sessEntry = mSessions[sessionId];
sessEntry.val = sessValPtr;
sessEntry.linkedTasks = taskIds;
for (auto taskId : taskIds) {
mTasks[taskId].push_back(sessValPtr);
}
return true;
}
void SessionTaskMap::addVote(int64_t sessionId, int voteId, int uclampMin, int uclampMax,
std::chrono::steady_clock::time_point startTime,
std::chrono::nanoseconds durationNs) {
auto sessItr = mSessions.find(sessionId);
if (sessItr == mSessions.end()) {
return;
}
sessItr->second.val->votes->add(voteId,
CpuVote(true, startTime, durationNs, uclampMin, uclampMax));
}
std::shared_ptr<SessionValueEntry> SessionTaskMap::findSession(int64_t sessionId) {
auto sessItr = mSessions.find(sessionId);
if (sessItr == mSessions.end()) {
return nullptr;
}
return sessItr->second.val;
}
void SessionTaskMap::getTaskVoteRange(pid_t taskId, std::chrono::steady_clock::time_point timeNow,
int *uclampMin, int *uclampMax) const {
UclampRange uclampRange;
auto taskItr = mTasks.find(taskId);
if (taskItr == mTasks.end()) {
return;
}
for (const auto &sessInTask : taskItr->second) {
if (!sessInTask->isActive) {
continue;
}
sessInTask->votes->getUclampRange(&uclampRange, timeNow);
}
*uclampMin = uclampRange.uclampMin;
*uclampMax = uclampRange.uclampMax;
}
std::vector<int64_t> SessionTaskMap::getSessionIds(pid_t taskId) const {
auto itr = mTasks.find(taskId);
if (itr == mTasks.end()) {
static const std::vector<int64_t> emptySessionIdVec;
return emptySessionIdVec;
}
std::vector<int64_t> res;
res.reserve(itr->second.size());
for (const auto &i : itr->second) {
res.push_back(i->sessionId);
}
return res;
}
std::vector<pid_t> &SessionTaskMap::getTaskIds(int64_t sessionId) {
auto taskItr = mSessions.find(sessionId);
if (taskItr == mSessions.end()) {
static std::vector<pid_t> emptyTaskIdVec;
return emptyTaskIdVec;
}
return taskItr->second.linkedTasks;
}
bool SessionTaskMap::isAnyAppSessionActive(std::chrono::steady_clock::time_point timePoint) const {
for (auto &sessionVal : mSessions) {
if (!sessionVal.second.val->isAppSession) {
continue;
}
if (!sessionVal.second.val->isActive) {
continue;
}
if (!sessionVal.second.val->votes->allTimedOut(timePoint)) {
return true;
}
}
return false;
}
bool SessionTaskMap::remove(int64_t sessionId) {
auto sessItr = mSessions.find(sessionId);
if (sessItr == mSessions.end()) {
return false;
}
// For each task id in linked tasks need to remove the corresponding
// task to session mapping in the task map
for (const auto taskId : sessItr->second.linkedTasks) {
// Used linked task ids to cleanup
auto taskItr = mTasks.find(taskId);
if (taskItr == mTasks.end()) {
// Inconsisent state
continue;
}
// Now lookup session id in task's set
auto taskSessItr =
std::find(taskItr->second.begin(), taskItr->second.end(), sessItr->second.val);
if (taskSessItr == taskItr->second.end()) {
// Should not happen
continue;
}
// Remove session id from task map
taskItr->second.erase(taskSessItr);
if (taskItr->second.empty()) {
mTasks.erase(taskItr);
}
}
// Now we can safely remove session entirely since there are no more
// mappings in task to session id
mSessions.erase(sessItr);
return true;
}
bool SessionTaskMap::removeDeadTaskSessionMap(int64_t sessionId, pid_t taskId) {
auto sessItr = mSessions.find(sessionId);
if (sessItr == mSessions.end()) {
return false;
}
auto taskItr = mTasks.find(taskId);
if (taskItr == mTasks.end()) {
// Inconsisent state
return false;
}
// Now lookup session id in task's set
auto taskSessItr =
std::find(taskItr->second.begin(), taskItr->second.end(), sessItr->second.val);
if (taskSessItr == taskItr->second.end()) {
// Should not happen
return false;
}
// Remove session id from task map
taskItr->second.erase(taskSessItr);
if (taskItr->second.empty()) {
mTasks.erase(taskItr);
}
return true;
}
bool SessionTaskMap::replace(int64_t sessionId, const std::vector<pid_t> &taskIds,
std::vector<pid_t> *addedThreads, std::vector<pid_t> *removedThreads) {
auto itr = mSessions.find(sessionId);
if (itr == mSessions.end()) {
return false;
}
// Make copies of val and threads
auto svTmp = itr->second.val;
const auto previousTaskIds = itr->second.linkedTasks;
// Determine newly added threads
if (addedThreads) {
for (auto tid : taskIds) {
auto taskSessItr = mTasks.find(tid);
if (taskSessItr == mTasks.end()) {
addedThreads->push_back(tid);
}
}
}
// Remove session from mappings
remove(sessionId);
// Add session value and task mappings
add(sessionId, *svTmp, taskIds);
// Determine completely removed threads
if (removedThreads) {
for (auto tid : previousTaskIds) {
auto taskSessItr = mTasks.find(tid);
if (taskSessItr == mTasks.end()) {
removedThreads->push_back(tid);
}
}
}
return true;
}
size_t SessionTaskMap::sizeSessions() const {
return mSessions.size();
}
size_t SessionTaskMap::sizeTasks() const {
return mTasks.size();
}
const std::string &SessionTaskMap::idString(int64_t sessionId) const {
auto sessItr = mSessions.find(sessionId);
if (sessItr == mSessions.end()) {
static const std::string emptyString;
return emptyString;
}
return sessItr->second.val->idString;
}
bool SessionTaskMap::isAppSession(int64_t sessionId) const {
auto sessItr = mSessions.find(sessionId);
if (sessItr == mSessions.end()) {
return false;
}
return sessItr->second.val->isAppSession;
}
} // namespace pixel
} // namespace impl
} // namespace power
} // namespace hardware
} // namespace google
} // namespace aidl