forked from donjohanliebert/hardware_xiaomi
ADPF: use PID algorithm to control cpu resource
The patch includes: 1. Move from folder adpf to aidl. 2. Add PowerSessionManager class to maintain hint status. And PowerHintMointor looper thread for monitoring or updating PowerHintSession status. 3. Use PID algorithm to replace the step-wise alogrithm for cpu resource control. Test: build, boot to home, trace analysis Bug: 177493042 Change-Id: Ib7d3f414225b18954350341ca22b7be87a6202e7
This commit is contained in:
parent
9fd3926d5f
commit
8a20bda9e4
@ -25,7 +25,6 @@ LOCAL_MODULE_RELATIVE_PATH := hw
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
android.hardware.power-V2-ndk_platform \
|
||||
libadpf-pixel \
|
||||
libbase \
|
||||
libbinder_ndk \
|
||||
libcutils \
|
||||
@ -39,7 +38,9 @@ LOCAL_SRC_FILES := \
|
||||
service.cpp \
|
||||
InteractionHandler.cpp \
|
||||
Power.cpp \
|
||||
PowerExt.cpp
|
||||
PowerExt.cpp \
|
||||
PowerHintSession.cpp \
|
||||
PowerSessionManager.cpp
|
||||
|
||||
LOCAL_CFLAGS := -Wno-unused-parameter -Wno-unused-variable
|
||||
|
||||
|
@ -31,7 +31,8 @@
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include "adpf/PowerHintSession.h"
|
||||
#include "PowerHintSession.h"
|
||||
#include "PowerSessionManager.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace google {
|
||||
@ -40,7 +41,7 @@ namespace power {
|
||||
namespace impl {
|
||||
namespace pixel {
|
||||
|
||||
using ::aidl::google::hardware::power::impl::pixel::adpf::PowerHintSession;
|
||||
using ::aidl::google::hardware::power::impl::pixel::PowerHintSession;
|
||||
|
||||
#ifdef MODE_EXT
|
||||
extern bool isDeviceSpecificModeSupported(Mode type, bool* _aidl_return);
|
||||
@ -89,6 +90,7 @@ Power::Power(std::shared_ptr<HintManager> hm)
|
||||
ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) {
|
||||
LOG(DEBUG) << "Power setMode: " << toString(type) << " to: " << enabled;
|
||||
ATRACE_INT(toString(type).c_str(), enabled);
|
||||
PowerSessionManager::getInstance().updateHintMode(toString(type), enabled);
|
||||
#ifdef MODE_EXT
|
||||
if (setDeviceSpecificMode(type, enabled)) {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
|
@ -56,7 +56,6 @@ class Power : public ::aidl::android::hardware::power::BnPower {
|
||||
std::unique_ptr<InteractionHandler> mInteractionHandler;
|
||||
std::atomic<bool> mSustainedPerfModeOn;
|
||||
const int64_t mAdpfRate;
|
||||
// TODO(jimmyshiu@): hold weak_ptr of PowerHintSession
|
||||
};
|
||||
|
||||
} // namespace pixel
|
||||
|
@ -18,6 +18,7 @@
|
||||
#define LOG_TAG "android.hardware.power-service.xiaomi.ext-libperfmgr"
|
||||
|
||||
#include "PowerExt.h"
|
||||
#include "PowerSessionManager.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
@ -46,6 +47,7 @@ ndk::ScopedAStatus PowerExt::setMode(const std::string &mode, bool enabled) {
|
||||
} else {
|
||||
mHintManager->EndHint(mode);
|
||||
}
|
||||
PowerSessionManager::getInstance().updateHintMode(mode, enabled);
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
444
aidl/power-libperfmgr/PowerHintSession.cpp
Normal file
444
aidl/power-libperfmgr/PowerHintSession.cpp
Normal file
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "powerhal-libperfmgr"
|
||||
#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/parsedouble.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <log/log.h>
|
||||
#include <time.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "PowerHintSession.h"
|
||||
#include "PowerSessionManager.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace google {
|
||||
namespace hardware {
|
||||
namespace power {
|
||||
namespace impl {
|
||||
namespace pixel {
|
||||
|
||||
using ::android::base::StringPrintf;
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::nanoseconds;
|
||||
using std::literals::chrono_literals::operator""s;
|
||||
|
||||
constexpr char kPowerHalAdpfPidOffset[] = "vendor.powerhal.adpf.pid.offset";
|
||||
constexpr char kPowerHalAdpfPidP[] = "vendor.powerhal.adpf.pid.p";
|
||||
constexpr char kPowerHalAdpfPidI[] = "vendor.powerhal.adpf.pid.i";
|
||||
constexpr char kPowerHalAdpfPidIClamp[] = "vendor.powerhal.adpf.pid.i_clamp";
|
||||
constexpr char kPowerHalAdpfPidD[] = "vendor.powerhal.adpf.pid.d";
|
||||
constexpr char kPowerHalAdpfPidInitialIntegral[] = "vendor.powerhal.adpf.pid.i_init";
|
||||
constexpr char kPowerHalAdpfUclampEnable[] = "vendor.powerhal.adpf.uclamp";
|
||||
constexpr char kPowerHalAdpfUclampCapRatio[] = "vendor.powerhal.adpf.uclamp.cap_ratio";
|
||||
constexpr char kPowerHalAdpfUclampGranularity[] = "vendor.powerhal.adpf.uclamp.granularity";
|
||||
constexpr char kPowerHalAdpfStaleTimeout[] = "vendor.powerhal.adpf.stale_timeout_ms";
|
||||
constexpr char kPowerHalAdpfSamplingWindow[] = "vendor.powerhal.adpf.sampling_window";
|
||||
|
||||
namespace {
|
||||
/* there is no glibc or bionic wrapper */
|
||||
struct sched_attr {
|
||||
__u32 size;
|
||||
__u32 sched_policy;
|
||||
__u64 sched_flags;
|
||||
__s32 sched_nice;
|
||||
__u32 sched_priority;
|
||||
__u64 sched_runtime;
|
||||
__u64 sched_deadline;
|
||||
__u64 sched_period;
|
||||
__u32 sched_util_min;
|
||||
__u32 sched_util_max;
|
||||
};
|
||||
|
||||
static int sched_setattr(int pid, struct sched_attr *attr, unsigned int flags) {
|
||||
static const bool kPowerHalAdpfUclamp =
|
||||
::android::base::GetBoolProperty(kPowerHalAdpfUclampEnable, true);
|
||||
if (!kPowerHalAdpfUclamp) {
|
||||
ALOGV("PowerHintSession:%s: skip", __func__);
|
||||
return 0;
|
||||
}
|
||||
return syscall(__NR_sched_setattr, pid, attr, flags);
|
||||
}
|
||||
|
||||
static inline void TRACE_ADPF_PID(uintptr_t session_id, int32_t uid, int32_t tgid, uint64_t count,
|
||||
int64_t err, int64_t integral, int64_t previous, int64_t p,
|
||||
int64_t i, int64_t d, int32_t output) {
|
||||
if (ATRACE_ENABLED()) {
|
||||
std::string idstr = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR, tgid, uid,
|
||||
session_id & 0xffff);
|
||||
std::string sz = StringPrintf("%s-pid.count", idstr.c_str());
|
||||
ATRACE_INT(sz.c_str(), count);
|
||||
sz = StringPrintf("%s-pid.err", idstr.c_str());
|
||||
ATRACE_INT(sz.c_str(), err);
|
||||
sz = StringPrintf("%s-pid.accu", idstr.c_str());
|
||||
ATRACE_INT(sz.c_str(), integral);
|
||||
sz = StringPrintf("%s-pid.prev", idstr.c_str());
|
||||
ATRACE_INT(sz.c_str(), previous);
|
||||
sz = StringPrintf("%s-pid.pOut", idstr.c_str());
|
||||
ATRACE_INT(sz.c_str(), p);
|
||||
sz = StringPrintf("%s-pid.iOut", idstr.c_str());
|
||||
ATRACE_INT(sz.c_str(), i);
|
||||
sz = StringPrintf("%s-pid.dOut", idstr.c_str());
|
||||
ATRACE_INT(sz.c_str(), d);
|
||||
sz = StringPrintf("%s-pid.output", idstr.c_str());
|
||||
ATRACE_INT(sz.c_str(), output);
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t ns_to_100us(int64_t ns) {
|
||||
return ns / 100000;
|
||||
}
|
||||
|
||||
double getDoubleProperty(const char *prop, double value) {
|
||||
std::string result = ::android::base::GetProperty(prop, std::to_string(value).c_str());
|
||||
if (!::android::base::ParseDouble(result.c_str(), &value)) {
|
||||
ALOGE("PowerHintSession : failed to parse double in %s", prop);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static double sPidOffset = getDoubleProperty(kPowerHalAdpfPidOffset, 0.0);
|
||||
static double sPidP = getDoubleProperty(kPowerHalAdpfPidP, 2.0);
|
||||
static double sPidI = getDoubleProperty(kPowerHalAdpfPidI, 0.001);
|
||||
static double sPidD = getDoubleProperty(kPowerHalAdpfPidD, 100.0);
|
||||
static const int64_t sPidIInit =
|
||||
(sPidI == 0) ? 0
|
||||
: static_cast<int64_t>(::android::base::GetIntProperty<int64_t>(
|
||||
kPowerHalAdpfPidInitialIntegral, 100) /
|
||||
sPidI);
|
||||
static const int64_t sPidIClamp =
|
||||
(sPidI == 0) ? 0
|
||||
: std::abs(static_cast<int64_t>(::android::base::GetIntProperty<int64_t>(
|
||||
kPowerHalAdpfPidIClamp, 512) /
|
||||
sPidI));
|
||||
static const int sUclampCap =
|
||||
static_cast<int>(getDoubleProperty(kPowerHalAdpfUclampCapRatio, 0.5) * 1024);
|
||||
static const uint32_t sUclampGranularity =
|
||||
::android::base::GetUintProperty<uint32_t>(kPowerHalAdpfUclampGranularity, 5);
|
||||
static const int64_t sStaleTimeoutMs =
|
||||
::android::base::GetIntProperty<int64_t>(kPowerHalAdpfStaleTimeout, 3000);
|
||||
static const size_t sSamplingWindow =
|
||||
::android::base::GetUintProperty<size_t>(kPowerHalAdpfSamplingWindow, 1);
|
||||
|
||||
} // namespace
|
||||
|
||||
PowerHintSession::PowerHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t> &threadIds,
|
||||
int64_t durationNanos) {
|
||||
mDescriptor = new AppHintDesc(tgid, uid, threadIds, sUclampCap);
|
||||
mDescriptor->duration = std::chrono::nanoseconds(durationNanos);
|
||||
mStaleHandler = sp<StaleHandler>(new StaleHandler(this, sStaleTimeoutMs));
|
||||
mPowerManagerHandler = sp<MessageHandler>(&PowerSessionManager::getInstance());
|
||||
|
||||
if (ATRACE_ENABLED()) {
|
||||
std::string sz =
|
||||
StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-target", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count());
|
||||
sz = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-active", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), mDescriptor->is_active.load());
|
||||
}
|
||||
PowerSessionManager::getInstance().addPowerSession(this);
|
||||
ALOGD("PowerHintSession created: %s", mDescriptor->toString().c_str());
|
||||
}
|
||||
|
||||
PowerHintSession::~PowerHintSession() {
|
||||
close();
|
||||
ALOGD("PowerHintSession deleted: %s", mDescriptor->toString().c_str());
|
||||
if (ATRACE_ENABLED()) {
|
||||
std::string sz =
|
||||
StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-target", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), 0);
|
||||
sz = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-actl_last", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), 0);
|
||||
sz = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-active", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), 0);
|
||||
}
|
||||
delete mDescriptor;
|
||||
}
|
||||
|
||||
void PowerHintSession::updateUniveralBoostMode() {
|
||||
PowerHintMonitor::getInstance().getLooper()->sendMessage(mPowerManagerHandler, NULL);
|
||||
}
|
||||
|
||||
int PowerHintSession::setUclamp(int32_t min, int32_t max) {
|
||||
std::lock_guard<std::mutex> guard(mLock);
|
||||
min = std::max(0, min);
|
||||
min = std::min(min, max);
|
||||
max = std::max(0, max);
|
||||
max = std::max(min, max);
|
||||
if (ATRACE_ENABLED()) {
|
||||
std::string sz =
|
||||
StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-min", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), min);
|
||||
sz = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-max", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), max);
|
||||
}
|
||||
for (const auto tid : mDescriptor->threadIds) {
|
||||
sched_attr attr = {};
|
||||
attr.size = sizeof(attr);
|
||||
|
||||
attr.sched_flags = (SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP);
|
||||
attr.sched_util_min = min;
|
||||
attr.sched_util_max = max;
|
||||
|
||||
int ret = sched_setattr(tid, &attr, 0);
|
||||
if (ret) {
|
||||
ALOGW("sched_setattr failed for thread %d, err=%d", tid, errno);
|
||||
}
|
||||
ALOGV("PowerHintSession tid: %d, uclamp(%d, %d)", tid, min, max);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus PowerHintSession::pause() {
|
||||
if (!mDescriptor->is_active.load())
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
// Reset to default uclamp value.
|
||||
setUclamp(0, 1024);
|
||||
mDescriptor->is_active.store(false);
|
||||
if (ATRACE_ENABLED()) {
|
||||
std::string sz =
|
||||
StringPrintf("%" PRId32 "-%" PRId32 "-%" PRIxPTR "-active", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), mDescriptor->is_active.load());
|
||||
}
|
||||
updateUniveralBoostMode();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus PowerHintSession::resume() {
|
||||
if (mDescriptor->is_active.load())
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
mDescriptor->is_active.store(true);
|
||||
mDescriptor->integral_error = std::max(sPidIInit, mDescriptor->integral_error);
|
||||
if (ATRACE_ENABLED()) {
|
||||
std::string sz =
|
||||
StringPrintf("%" PRId32 "-%" PRId32 "-%" PRIxPTR "-active", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), mDescriptor->is_active.load());
|
||||
}
|
||||
updateUniveralBoostMode();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus PowerHintSession::close() {
|
||||
PowerHintMonitor::getInstance().getLooper()->removeMessages(mStaleHandler);
|
||||
// Reset to (0, 1024) uclamp value -- instead of threads' original setting.
|
||||
setUclamp(0, 1024);
|
||||
PowerSessionManager::getInstance().removePowerSession(this);
|
||||
updateUniveralBoostMode();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus PowerHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
|
||||
if (targetDurationNanos <= 0) {
|
||||
ALOGE("Error: targetDurationNanos(%" PRId64 ") should bigger than 0", targetDurationNanos);
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
ALOGV("update target duration: %" PRId64 " ns", targetDurationNanos);
|
||||
double ratio =
|
||||
targetDurationNanos == 0 ? 1.0 : mDescriptor->duration.count() / targetDurationNanos;
|
||||
mDescriptor->integral_error =
|
||||
std::max(sPidIInit, static_cast<int64_t>(mDescriptor->integral_error * ratio));
|
||||
|
||||
mDescriptor->duration = std::chrono::nanoseconds(targetDurationNanos);
|
||||
if (ATRACE_ENABLED()) {
|
||||
std::string sz =
|
||||
StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-target", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count());
|
||||
}
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus PowerHintSession::reportActualWorkDuration(
|
||||
const std::vector<WorkDuration> &actualDurations) {
|
||||
if (mDescriptor->duration.count() == 0LL) {
|
||||
ALOGE("Expect to call updateTargetWorkDuration() first.");
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
if (actualDurations.size() == 0) {
|
||||
ALOGE("Error: duration.size() shouldn't be %zu.", actualDurations.size());
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
if (!mDescriptor->is_active.load()) {
|
||||
ALOGE("Error: shouldn't report duration during pause state.");
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
if (PowerHintMonitor::getInstance().isRunning() && isStale()) {
|
||||
if (ATRACE_ENABLED()) {
|
||||
std::string sz = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-stale",
|
||||
mDescriptor->tgid, mDescriptor->uid,
|
||||
reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), 0);
|
||||
}
|
||||
mDescriptor->integral_error = std::max(sPidIInit, mDescriptor->integral_error);
|
||||
}
|
||||
int64_t targetDurationNanos = (int64_t)mDescriptor->duration.count();
|
||||
size_t length = actualDurations.size();
|
||||
size_t start = sSamplingWindow == 0 || sSamplingWindow > length ? 0 : length - sSamplingWindow;
|
||||
int64_t actualDurationNanos = 0;
|
||||
int64_t dt = ns_to_100us(targetDurationNanos);
|
||||
int64_t error = 0;
|
||||
int64_t derivative = 0;
|
||||
for (size_t i = start; i < length; i++) {
|
||||
actualDurationNanos = actualDurations[i].durationNanos;
|
||||
if (std::abs(actualDurationNanos) > targetDurationNanos * 20) {
|
||||
ALOGW("The actual duration is way far from the target (%" PRId64 " >> %" PRId64 ")",
|
||||
actualDurationNanos, targetDurationNanos);
|
||||
}
|
||||
if (ATRACE_ENABLED()) {
|
||||
std::string sz = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-actl_last",
|
||||
mDescriptor->tgid, mDescriptor->uid,
|
||||
reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), actualDurationNanos);
|
||||
sz = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-target", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count());
|
||||
}
|
||||
// PID control algorithm
|
||||
error = ns_to_100us(actualDurationNanos - targetDurationNanos) +
|
||||
static_cast<int64_t>(sPidOffset);
|
||||
mDescriptor->integral_error = mDescriptor->integral_error + error * dt;
|
||||
mDescriptor->integral_error = std::min(sPidIClamp, mDescriptor->integral_error);
|
||||
mDescriptor->integral_error = std::max(-sPidIClamp, mDescriptor->integral_error);
|
||||
derivative = (error - mDescriptor->previous_error) / dt;
|
||||
mDescriptor->previous_error = error;
|
||||
}
|
||||
int64_t pOut = static_cast<int64_t>(sPidP * error);
|
||||
int64_t iOut = static_cast<int64_t>(sPidI * mDescriptor->integral_error);
|
||||
int64_t dOut = static_cast<int64_t>(sPidD * derivative);
|
||||
|
||||
int64_t output = pOut + iOut + dOut;
|
||||
TRACE_ADPF_PID(reinterpret_cast<uintptr_t>(this) & 0xffff, mDescriptor->uid, mDescriptor->tgid,
|
||||
mDescriptor->update_count, error, mDescriptor->integral_error, derivative, pOut,
|
||||
iOut, dOut, static_cast<int>(output));
|
||||
mDescriptor->update_count++;
|
||||
|
||||
mStaleHandler->updateStaleTimer();
|
||||
|
||||
/* apply to all the threads in the group */
|
||||
if (output != 0) {
|
||||
int next_min = std::min(sUclampCap, mDescriptor->current_min + static_cast<int>(output));
|
||||
next_min = std::max(0, next_min);
|
||||
if (std::abs(mDescriptor->current_min - next_min) > sUclampGranularity) {
|
||||
setUclamp(next_min, 1024);
|
||||
mDescriptor->current_min = next_min;
|
||||
}
|
||||
}
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
std::string AppHintDesc::toString() const {
|
||||
std::string out =
|
||||
StringPrintf("session %" PRIxPTR "\n", reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
const int64_t durationNanos = duration.count();
|
||||
out.append(StringPrintf(" duration: %" PRId64 " ns\n", durationNanos));
|
||||
out.append(StringPrintf(" uclamp.min: %d \n", current_min));
|
||||
out.append(StringPrintf(" uid: %d, tgid: %d\n", uid, tgid));
|
||||
|
||||
out.append(" threadIds: [");
|
||||
bool first = true;
|
||||
for (int tid : threadIds) {
|
||||
if (!first) {
|
||||
out.append(", ");
|
||||
}
|
||||
out.append(std::to_string(tid));
|
||||
first = false;
|
||||
}
|
||||
out.append("]\n");
|
||||
return out;
|
||||
}
|
||||
|
||||
bool PowerHintSession::isActive() {
|
||||
return mDescriptor->is_active.load();
|
||||
}
|
||||
|
||||
bool PowerHintSession::isStale() {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
return now >= mStaleHandler->getStaleTime();
|
||||
}
|
||||
|
||||
void PowerHintSession::setStale() {
|
||||
if (ATRACE_ENABLED()) {
|
||||
std::string sz =
|
||||
StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-stale", mDescriptor->tgid,
|
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
|
||||
ATRACE_INT(sz.c_str(), 1);
|
||||
}
|
||||
// Reset to default uclamp value.
|
||||
setUclamp(0, 1024);
|
||||
// Deliver a task to check if all sessions are inactive.
|
||||
updateUniveralBoostMode();
|
||||
}
|
||||
|
||||
void PowerHintSession::StaleHandler::updateStaleTimer() {
|
||||
std::lock_guard<std::mutex> guard(mStaleLock);
|
||||
if (PowerHintMonitor::getInstance().isRunning()) {
|
||||
auto when = getStaleTime();
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
mLastUpdatedTime.store(now);
|
||||
if (now > when) {
|
||||
mSession->updateUniveralBoostMode();
|
||||
}
|
||||
if (!mIsMonitoringStale.load()) {
|
||||
auto next = getStaleTime();
|
||||
PowerHintMonitor::getInstance().getLooper()->sendMessageDelayed(
|
||||
duration_cast<nanoseconds>(next - now).count(), this, NULL);
|
||||
mIsMonitoringStale.store(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
time_point<steady_clock> PowerHintSession::StaleHandler::getStaleTime() {
|
||||
return mLastUpdatedTime.load() + kStaleTimeout;
|
||||
}
|
||||
|
||||
void PowerHintSession::StaleHandler::handleMessage(const Message &) {
|
||||
std::lock_guard<std::mutex> guard(mStaleLock);
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto when = getStaleTime();
|
||||
// Check if the session is stale based on the last_updated_time.
|
||||
if (now > when) {
|
||||
mSession->setStale();
|
||||
mIsMonitoringStale.store(false);
|
||||
return;
|
||||
}
|
||||
// Schedule for the next checking time.
|
||||
PowerHintMonitor::getInstance().getLooper()->sendMessageDelayed(
|
||||
duration_cast<nanoseconds>(when - now).count(), this, NULL);
|
||||
}
|
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
118
aidl/power-libperfmgr/PowerHintSession.h
Normal file
118
aidl/power-libperfmgr/PowerHintSession.h
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/power/BnPowerHintSession.h>
|
||||
#include <aidl/android/hardware/power/WorkDuration.h>
|
||||
#include <utils/Looper.h>
|
||||
#include <utils/Thread.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace aidl {
|
||||
namespace google {
|
||||
namespace hardware {
|
||||
namespace power {
|
||||
namespace impl {
|
||||
namespace pixel {
|
||||
|
||||
using aidl::android::hardware::power::BnPowerHintSession;
|
||||
using aidl::android::hardware::power::WorkDuration;
|
||||
using ::android::Message;
|
||||
using ::android::MessageHandler;
|
||||
using ::android::sp;
|
||||
using std::chrono::milliseconds;
|
||||
using std::chrono::nanoseconds;
|
||||
using std::chrono::steady_clock;
|
||||
using std::chrono::time_point;
|
||||
|
||||
struct AppHintDesc {
|
||||
AppHintDesc(int32_t tgid, int32_t uid, std::vector<int> threadIds, int uclamp_min)
|
||||
: tgid(tgid),
|
||||
uid(uid),
|
||||
threadIds(std::move(threadIds)),
|
||||
duration(0LL),
|
||||
current_min(uclamp_min),
|
||||
is_active(true),
|
||||
update_count(0),
|
||||
integral_error(0),
|
||||
previous_error(0) {}
|
||||
std::string toString() const;
|
||||
const int32_t tgid;
|
||||
const int32_t uid;
|
||||
const std::vector<int> threadIds;
|
||||
nanoseconds duration;
|
||||
int current_min;
|
||||
// status
|
||||
std::atomic<bool> is_active;
|
||||
// pid
|
||||
uint64_t update_count;
|
||||
int64_t integral_error;
|
||||
int64_t previous_error;
|
||||
};
|
||||
|
||||
class PowerHintSession : public BnPowerHintSession {
|
||||
public:
|
||||
PowerHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t> &threadIds,
|
||||
int64_t durationNanos);
|
||||
~PowerHintSession();
|
||||
ndk::ScopedAStatus close() override;
|
||||
ndk::ScopedAStatus pause() override;
|
||||
ndk::ScopedAStatus resume() override;
|
||||
ndk::ScopedAStatus updateTargetWorkDuration(int64_t targetDurationNanos) override;
|
||||
ndk::ScopedAStatus reportActualWorkDuration(
|
||||
const std::vector<WorkDuration> &actualDurations) override;
|
||||
bool isActive();
|
||||
bool isStale();
|
||||
|
||||
private:
|
||||
class StaleHandler : public MessageHandler {
|
||||
public:
|
||||
StaleHandler(PowerHintSession *session, int64_t timeout_ms)
|
||||
: kStaleTimeout(timeout_ms),
|
||||
mSession(session),
|
||||
mIsMonitoringStale(false),
|
||||
mLastUpdatedTime(steady_clock::now()) {}
|
||||
void handleMessage(const Message &message) override;
|
||||
void updateStaleTimer();
|
||||
time_point<steady_clock> getStaleTime();
|
||||
|
||||
private:
|
||||
const milliseconds kStaleTimeout;
|
||||
PowerHintSession *mSession;
|
||||
std::atomic<bool> mIsMonitoringStale;
|
||||
std::atomic<time_point<steady_clock>> mLastUpdatedTime;
|
||||
std::mutex mStaleLock;
|
||||
};
|
||||
|
||||
private:
|
||||
void setStale();
|
||||
void updateUniveralBoostMode();
|
||||
int setUclamp(int32_t max, int32_t min);
|
||||
AppHintDesc *mDescriptor = nullptr;
|
||||
sp<StaleHandler> mStaleHandler;
|
||||
sp<MessageHandler> mPowerManagerHandler;
|
||||
std::mutex mLock;
|
||||
};
|
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
128
aidl/power-libperfmgr/PowerSessionManager.cpp
Normal file
128
aidl/power-libperfmgr/PowerSessionManager.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "powerhal-libperfmgr"
|
||||
#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
|
||||
|
||||
#include <log/log.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include "PowerSessionManager.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace google {
|
||||
namespace hardware {
|
||||
namespace power {
|
||||
namespace impl {
|
||||
namespace pixel {
|
||||
|
||||
void PowerSessionManager::setHintManager(std::shared_ptr<HintManager> const &hint_manager) {
|
||||
// Only initialize hintmanager instance if hint is supported.
|
||||
if (hint_manager->IsHintSupported(kDisableBoostHintName)) {
|
||||
mHintManager = hint_manager;
|
||||
}
|
||||
}
|
||||
|
||||
void PowerSessionManager::updateHintMode(const std::string &mode, bool enabled) {
|
||||
ALOGD("PowerSessionManager::updateHintMode: mode: %s, enabled: %d", mode.c_str(), enabled);
|
||||
if (enabled && mode.compare(0, 8, "REFRESH_") == 0) {
|
||||
if (mode.compare("REFRESH_120FPS") == 0) {
|
||||
mDisplayRefreshRate = 120;
|
||||
} else if (mode.compare("REFRESH_90FPS") == 0) {
|
||||
mDisplayRefreshRate = 90;
|
||||
} else if (mode.compare("REFRESH_60FPS") == 0) {
|
||||
mDisplayRefreshRate = 60;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PowerSessionManager::getDisplayRefreshRate() {
|
||||
return mDisplayRefreshRate;
|
||||
}
|
||||
|
||||
void PowerSessionManager::addPowerSession(PowerHintSession *session) {
|
||||
std::lock_guard<std::mutex> guard(mLock);
|
||||
mSessions.insert(session);
|
||||
}
|
||||
|
||||
void PowerSessionManager::removePowerSession(PowerHintSession *session) {
|
||||
std::lock_guard<std::mutex> guard(mLock);
|
||||
mSessions.erase(session);
|
||||
}
|
||||
|
||||
bool PowerSessionManager::isAnySessionActive() {
|
||||
std::lock_guard<std::mutex> guard(mLock);
|
||||
for (PowerHintSession *s : mSessions) {
|
||||
// session active and not stale is actually active.
|
||||
if (s->isActive() && !s->isStale()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PowerSessionManager::handleMessage(const Message &) {
|
||||
if (isAnySessionActive()) {
|
||||
disableSystemTopAppBoost();
|
||||
} else {
|
||||
enableSystemTopAppBoost();
|
||||
}
|
||||
}
|
||||
|
||||
void PowerSessionManager::enableSystemTopAppBoost() {
|
||||
if (mHintManager) {
|
||||
ALOGD("PowerSessionManager::enableSystemTopAppBoost!!");
|
||||
if (ATRACE_ENABLED()) {
|
||||
ATRACE_INT(kDisableBoostHintName.c_str(), 0);
|
||||
}
|
||||
mHintManager->EndHint(kDisableBoostHintName);
|
||||
}
|
||||
}
|
||||
|
||||
void PowerSessionManager::disableSystemTopAppBoost() {
|
||||
if (mHintManager) {
|
||||
ALOGD("PowerSessionManager::disableSystemTopAppBoost!!");
|
||||
if (ATRACE_ENABLED()) {
|
||||
ATRACE_INT(kDisableBoostHintName.c_str(), 1);
|
||||
}
|
||||
mHintManager->DoHint(kDisableBoostHintName);
|
||||
}
|
||||
}
|
||||
|
||||
// =========== PowerHintMonitor implementation start from here ===========
|
||||
void PowerHintMonitor::start() {
|
||||
if (!isRunning()) {
|
||||
run("PowerHintMonitor", ::android::PRIORITY_HIGHEST);
|
||||
}
|
||||
}
|
||||
|
||||
bool PowerHintMonitor::threadLoop() {
|
||||
while (true) {
|
||||
mLooper->pollOnce(-1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Looper *PowerHintMonitor::getLooper() {
|
||||
return mLooper;
|
||||
}
|
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
103
aidl/power-libperfmgr/PowerSessionManager.h
Normal file
103
aidl/power-libperfmgr/PowerSessionManager.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PowerHintSession.h"
|
||||
|
||||
#include <android-base/properties.h>
|
||||
#include <perfmgr/HintManager.h>
|
||||
#include <utils/Looper.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace aidl {
|
||||
namespace google {
|
||||
namespace hardware {
|
||||
namespace power {
|
||||
namespace impl {
|
||||
namespace pixel {
|
||||
|
||||
using ::android::Looper;
|
||||
using ::android::Message;
|
||||
using ::android::MessageHandler;
|
||||
using ::android::Thread;
|
||||
using ::android::perfmgr::HintManager;
|
||||
|
||||
constexpr char kPowerHalAdpfDisableTopAppBoost[] = "vendor.powerhal.adpf.disable.hint";
|
||||
|
||||
class PowerSessionManager : public MessageHandler {
|
||||
public:
|
||||
// current hint info
|
||||
void updateHintMode(const std::string &mode, bool enabled);
|
||||
int getDisplayRefreshRate();
|
||||
// monitoring session status
|
||||
void addPowerSession(PowerHintSession *session);
|
||||
void removePowerSession(PowerHintSession *session);
|
||||
bool isAnySessionActive();
|
||||
void handleMessage(const Message &message) override;
|
||||
void setHintManager(std::shared_ptr<HintManager> const &hint_manager);
|
||||
|
||||
// Singleton
|
||||
static PowerSessionManager &getInstance() {
|
||||
static PowerSessionManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
private:
|
||||
void disableSystemTopAppBoost();
|
||||
void enableSystemTopAppBoost();
|
||||
const std::string kDisableBoostHintName;
|
||||
std::shared_ptr<HintManager> mHintManager;
|
||||
std::unordered_set<PowerHintSession *> mSessions;
|
||||
std::mutex mLock;
|
||||
int mDisplayRefreshRate;
|
||||
// Singleton
|
||||
PowerSessionManager()
|
||||
: kDisableBoostHintName(::android::base::GetProperty(kPowerHalAdpfDisableTopAppBoost,
|
||||
"ADPF_DISABLE_TA_BOOST")),
|
||||
mHintManager(nullptr),
|
||||
mDisplayRefreshRate(60) {}
|
||||
PowerSessionManager(PowerSessionManager const &) = delete;
|
||||
void operator=(PowerSessionManager const &) = delete;
|
||||
};
|
||||
|
||||
class PowerHintMonitor : public Thread {
|
||||
public:
|
||||
void start();
|
||||
bool threadLoop() override;
|
||||
Looper *getLooper();
|
||||
// Singleton
|
||||
static PowerHintMonitor &getInstance() {
|
||||
static PowerHintMonitor instance;
|
||||
return instance;
|
||||
}
|
||||
PowerHintMonitor(PowerHintMonitor const &) = delete;
|
||||
void operator=(PowerHintMonitor const &) = delete;
|
||||
|
||||
private:
|
||||
Looper *mLooper;
|
||||
// Singleton
|
||||
PowerHintMonitor() : Thread(false), mLooper(new Looper(true)) {}
|
||||
};
|
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
@ -25,9 +25,12 @@
|
||||
|
||||
#include "Power.h"
|
||||
#include "PowerExt.h"
|
||||
#include "PowerSessionManager.h"
|
||||
|
||||
using aidl::google::hardware::power::impl::pixel::Power;
|
||||
using aidl::google::hardware::power::impl::pixel::PowerExt;
|
||||
using aidl::google::hardware::power::impl::pixel::PowerHintMonitor;
|
||||
using aidl::google::hardware::power::impl::pixel::PowerSessionManager;
|
||||
using ::android::perfmgr::HintManager;
|
||||
|
||||
constexpr std::string_view kPowerHalInitProp("vendor.powerhal.init");
|
||||
@ -65,6 +68,11 @@ int main() {
|
||||
CHECK(status == STATUS_OK);
|
||||
LOG(INFO) << "Xiaomi Power HAL AIDL Service with Extension is started.";
|
||||
|
||||
if (::android::base::GetIntProperty("vendor.powerhal.adpf.rate", -1) != -1) {
|
||||
PowerHintMonitor::getInstance().start();
|
||||
PowerSessionManager::getInstance().setHintManager(hm);
|
||||
}
|
||||
|
||||
std::thread initThread([&]() {
|
||||
::android::base::WaitForProperty(kPowerHalInitProp.data(), "1");
|
||||
hm->Start();
|
||||
|
Loading…
Reference in New Issue
Block a user