blob: 39ffc2e2a7c12d5d45b52bd51a649f0cdaf4e994 [file] [log] [blame]
/*
* Copyright (C) 2017 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 specic language governing permissions and
* limitations under the License.
*/
#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
#define LOG_TAG "libperfmgr"
#include "perfmgr/NodeLooperThread.h"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <utils/Trace.h>
namespace android {
namespace perfmgr {
bool NodeLooperThread::Request(const std::vector<NodeAction>& actions,
const std::string& hint_type) {
if (::android::Thread::exitPending()) {
LOG(WARNING) << "NodeLooperThread is exiting";
return false;
}
if (!::android::Thread::isRunning()) {
LOG(WARNING) << "NodeLooperThread is not running, request " << hint_type;
}
bool ret = true;
::android::AutoMutex _l(lock_);
for (const auto& a : actions) {
if (a.node_index >= nodes_.size()) {
LOG(ERROR) << "Node index out of bound: " << a.node_index
<< " ,size: " << nodes_.size();
ret = false;
} else {
// End time set to steady time point max
ReqTime end_time = ReqTime::max();
// Timeout is non-zero
if (a.timeout_ms != std::chrono::milliseconds::zero()) {
auto now = std::chrono::steady_clock::now();
// Overflow protection in case timeout_ms is too big to overflow
// time point which is unsigned integer
if (std::chrono::duration_cast<std::chrono::milliseconds>(
ReqTime::max() - now) > a.timeout_ms) {
end_time = now + a.timeout_ms;
}
}
ret = nodes_[a.node_index]->AddRequest(a.value_index, hint_type,
end_time) &&
ret;
}
}
wake_cond_.signal();
return ret;
}
bool NodeLooperThread::Cancel(const std::vector<NodeAction>& actions,
const std::string& hint_type) {
if (::android::Thread::exitPending()) {
LOG(WARNING) << "NodeLooperThread is exiting";
return false;
}
if (!::android::Thread::isRunning()) {
LOG(WARNING) << "NodeLooperThread is not running, cancel " << hint_type;
}
bool ret = true;
::android::AutoMutex _l(lock_);
for (const auto& a : actions) {
if (a.node_index >= nodes_.size()) {
LOG(ERROR) << "Node index out of bound: " << a.node_index
<< " ,size: " << nodes_.size();
ret = false;
} else {
nodes_[a.node_index]->RemoveRequest(hint_type);
}
}
wake_cond_.signal();
return ret;
}
void NodeLooperThread::DumpToFd(int fd) {
::android::AutoMutex _l(lock_);
for (auto& n : nodes_) {
n->DumpToFd(fd);
}
}
bool NodeLooperThread::threadLoop() {
::android::AutoMutex _l(lock_);
std::chrono::milliseconds timeout_ms = kMaxUpdatePeriod;
// Update 2 passes: some node may have dependency in other node
// e.g. update cpufreq min to VAL while cpufreq max still set to
// a value lower than VAL, is expected to fail in first pass
ATRACE_BEGIN("update_nodes");
for (auto& n : nodes_) {
n->Update(false);
}
for (auto& n : nodes_) {
timeout_ms = std::min(n->Update(true), timeout_ms);
}
ATRACE_END();
nsecs_t sleep_timeout_ns = std::numeric_limits<nsecs_t>::max();
if (timeout_ms.count() < sleep_timeout_ns / 1000 / 1000) {
sleep_timeout_ns = timeout_ms.count() * 1000 * 1000;
}
// VERBOSE level won't print by default in user/userdebug build
LOG(VERBOSE) << "NodeLooperThread will wait for " << sleep_timeout_ns
<< "ns";
ATRACE_BEGIN("wait");
wake_cond_.waitRelative(lock_, sleep_timeout_ns);
ATRACE_END();
return true;
}
bool NodeLooperThread::Start() {
auto ret = this->run("NodeLooperThread", PRIORITY_HIGHEST);
if (ret != NO_ERROR) {
LOG(ERROR) << "NodeLooperThread start failed: " << ret;
} else {
LOG(INFO) << "NodeLooperThread started";
}
return ret == NO_ERROR;
}
void NodeLooperThread::Stop() {
if (::android::Thread::isRunning()) {
LOG(INFO) << "NodeLooperThread stopping";
{
::android::AutoMutex _l(lock_);
wake_cond_.signal();
::android::Thread::requestExit();
}
::android::Thread::join();
LOG(INFO) << "NodeLooperThread stopped";
}
}
} // namespace perfmgr
} // namespace android