diff --git a/power-libperfmgr/Android.bp b/power-libperfmgr/Android.bp index 6cb0fa4..4809f4a 100644 --- a/power-libperfmgr/Android.bp +++ b/power-libperfmgr/Android.bp @@ -21,7 +21,6 @@ cc_binary { vendor: true, shared_libs: [ "android.hardware.power-V2-ndk_platform", - "libadpf-pixel", "libbase", "libcutils", "liblog", @@ -36,5 +35,7 @@ cc_binary { "Power.cpp", "InteractionHandler.cpp", "PowerExt.cpp", + "PowerHintSession.cpp", + "PowerSessionManager.cpp", ], } diff --git a/power-libperfmgr/Power.cpp b/power-libperfmgr/Power.cpp index ade5689..3495d7a 100644 --- a/power-libperfmgr/Power.cpp +++ b/power-libperfmgr/Power.cpp @@ -31,7 +31,8 @@ #include #include -#include "adpf/PowerHintSession.h" +#include "PowerHintSession.h" +#include "PowerSessionManager.h" #define TAP_TO_WAKE_NODE "/sys/class/sensors/dt-gesture/enable" @@ -42,7 +43,7 @@ namespace power { namespace impl { namespace pixel { -using ::aidl::google::hardware::power::impl::pixel::adpf::PowerHintSession; +using ::aidl::google::hardware::power::impl::pixel::PowerHintSession; constexpr char kPowerHalStateProp[] = "vendor.powerhal.state"; constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio"; @@ -86,6 +87,7 @@ Power::Power(std::shared_ptr 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); switch (type) { #ifdef TAP_TO_WAKE_NODE case Mode::DOUBLE_TAP_TO_WAKE: diff --git a/power-libperfmgr/Power.h b/power-libperfmgr/Power.h index 9dff2da..6f4a938 100644 --- a/power-libperfmgr/Power.h +++ b/power-libperfmgr/Power.h @@ -56,7 +56,6 @@ class Power : public ::aidl::android::hardware::power::BnPower { std::unique_ptr mInteractionHandler; std::atomic mSustainedPerfModeOn; const int64_t mAdpfRate; - // TODO(jimmyshiu@): hold weak_ptr of PowerHintSession }; } // namespace pixel diff --git a/power-libperfmgr/PowerExt.cpp b/power-libperfmgr/PowerExt.cpp index 84136b2..3d170fb 100644 --- a/power-libperfmgr/PowerExt.cpp +++ b/power-libperfmgr/PowerExt.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "android.hardware.power-service.realme_sm6375.ext-libperfmgr" #include "PowerExt.h" +#include "PowerSessionManager.h" #include @@ -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(); } diff --git a/power-libperfmgr/PowerHintSession.cpp b/power-libperfmgr/PowerHintSession.cpp new file mode 100644 index 0000000..908983f --- /dev/null +++ b/power-libperfmgr/PowerHintSession.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +#include + +#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(::android::base::GetIntProperty( + kPowerHalAdpfPidInitialIntegral, 100) / + sPidI); +static const int64_t sPidIClamp = + (sPidI == 0) ? 0 + : std::abs(static_cast(::android::base::GetIntProperty( + kPowerHalAdpfPidIClamp, 512) / + sPidI)); +static const int sUclampCap = + static_cast(getDoubleProperty(kPowerHalAdpfUclampCapRatio, 0.5) * 1024); +static const uint32_t sUclampGranularity = + ::android::base::GetUintProperty(kPowerHalAdpfUclampGranularity, 5); +static const int64_t sStaleTimeoutMs = + ::android::base::GetIntProperty(kPowerHalAdpfStaleTimeout, 3000); +static const size_t sSamplingWindow = + ::android::base::GetUintProperty(kPowerHalAdpfSamplingWindow, 1); + +} // namespace + +PowerHintSession::PowerHintSession(int32_t tgid, int32_t uid, const std::vector &threadIds, + int64_t durationNanos) { + mDescriptor = new AppHintDesc(tgid, uid, threadIds, sUclampCap); + mDescriptor->duration = std::chrono::nanoseconds(durationNanos); + mStaleHandler = sp(new StaleHandler(this, sStaleTimeoutMs)); + mPowerManagerHandler = sp(&PowerSessionManager::getInstance()); + + if (ATRACE_ENABLED()) { + std::string sz = + StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-target", mDescriptor->tgid, + mDescriptor->uid, reinterpret_cast(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(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(this) & 0xffff); + ATRACE_INT(sz.c_str(), 0); + sz = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-actl_last", mDescriptor->tgid, + mDescriptor->uid, reinterpret_cast(this) & 0xffff); + ATRACE_INT(sz.c_str(), 0); + sz = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-active", mDescriptor->tgid, + mDescriptor->uid, reinterpret_cast(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 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(this) & 0xffff); + ATRACE_INT(sz.c_str(), min); + sz = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-max", mDescriptor->tgid, + mDescriptor->uid, reinterpret_cast(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(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(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(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(this) & 0xffff); + ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count()); + } + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PowerHintSession::reportActualWorkDuration( + const std::vector &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(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(this) & 0xffff); + ATRACE_INT(sz.c_str(), actualDurationNanos); + sz = StringPrintf("adpf.%" PRId32 "-%" PRId32 "-%" PRIxPTR "-target", mDescriptor->tgid, + mDescriptor->uid, reinterpret_cast(this) & 0xffff); + ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count()); + } + // PID control algorithm + error = ns_to_100us(actualDurationNanos - targetDurationNanos) + + static_cast(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(sPidP * error); + int64_t iOut = static_cast(sPidI * mDescriptor->integral_error); + int64_t dOut = static_cast(sPidD * derivative); + + int64_t output = pOut + iOut + dOut; + TRACE_ADPF_PID(reinterpret_cast(this) & 0xffff, mDescriptor->uid, mDescriptor->tgid, + mDescriptor->update_count, error, mDescriptor->integral_error, derivative, pOut, + iOut, dOut, static_cast(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(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(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(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 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(next - now).count(), this, NULL); + mIsMonitoringStale.store(true); + } + } +} + +time_point PowerHintSession::StaleHandler::getStaleTime() { + return mLastUpdatedTime.load() + kStaleTimeout; +} + +void PowerHintSession::StaleHandler::handleMessage(const Message &) { + std::lock_guard 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(when - now).count(), this, NULL); +} + +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/power-libperfmgr/PowerHintSession.h b/power-libperfmgr/PowerHintSession.h new file mode 100644 index 0000000..4a2e817 --- /dev/null +++ b/power-libperfmgr/PowerHintSession.h @@ -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 +#include +#include +#include + +#include +#include + +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 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 threadIds; + nanoseconds duration; + int current_min; + // status + std::atomic 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 &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 &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 getStaleTime(); + + private: + const milliseconds kStaleTimeout; + PowerHintSession *mSession; + std::atomic mIsMonitoringStale; + std::atomic> mLastUpdatedTime; + std::mutex mStaleLock; + }; + + private: + void setStale(); + void updateUniveralBoostMode(); + int setUclamp(int32_t max, int32_t min); + AppHintDesc *mDescriptor = nullptr; + sp mStaleHandler; + sp mPowerManagerHandler; + std::mutex mLock; +}; + +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/power-libperfmgr/PowerSessionManager.cpp b/power-libperfmgr/PowerSessionManager.cpp new file mode 100644 index 0000000..f3cb29d --- /dev/null +++ b/power-libperfmgr/PowerSessionManager.cpp @@ -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 +#include + +#include "PowerSessionManager.h" + +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { + +void PowerSessionManager::setHintManager(std::shared_ptr 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 guard(mLock); + mSessions.insert(session); +} + +void PowerSessionManager::removePowerSession(PowerHintSession *session) { + std::lock_guard guard(mLock); + mSessions.erase(session); +} + +bool PowerSessionManager::isAnySessionActive() { + std::lock_guard 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 diff --git a/power-libperfmgr/PowerSessionManager.h b/power-libperfmgr/PowerSessionManager.h new file mode 100644 index 0000000..992e876 --- /dev/null +++ b/power-libperfmgr/PowerSessionManager.h @@ -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 +#include +#include + +#include +#include + +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 const &hint_manager); + + // Singleton + static PowerSessionManager &getInstance() { + static PowerSessionManager instance; + return instance; + } + + private: + void disableSystemTopAppBoost(); + void enableSystemTopAppBoost(); + const std::string kDisableBoostHintName; + std::shared_ptr mHintManager; + std::unordered_set 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 diff --git a/power-libperfmgr/service.cpp b/power-libperfmgr/service.cpp index a52c956..55fcc09 100644 --- a/power-libperfmgr/service.cpp +++ b/power-libperfmgr/service.cpp @@ -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) << "Power HAL AIDL Service for moto_sm6375 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();