From 1f851e8b21045f1dccb4710444a364cd45e609c3 Mon Sep 17 00:00:00 2001 From: Jimmy Shiu Date: Mon, 25 Jan 2021 01:20:38 +0800 Subject: power: add PowerHintSession for ADPF implementation Adapted from PoC from ag/13100800 Added more ATRACE for further tuning and debug Test: APPPID=$(adb shell pidof com.prefabulated.touchlatency); watch -n 1 adb shell grep uclamp /proc/${APPPID}/sched Test: atest VtsHalPowerTargetTest Bug: 177492680 Change-Id: I6bfd61b21dc1cde04f6ba9ae8d3533cd263ad814 Signed-off-by: Wei Wang --- power-libperfmgr/Android.bp | 21 +- power-libperfmgr/adpf/PowerHintSession.cpp | 251 +++++++++++++++++++++ power-libperfmgr/adpf/PowerHintSession.h | 81 +++++++ power-libperfmgr/aidl/Power.cpp | 53 ++++- power-libperfmgr/aidl/Power.h | 7 + .../aidl/android.hardware.power-service.pixel.xml | 1 + power-libperfmgr/aidl/service.cpp | 2 +- power-libperfmgr/disp-power/DisplayLowPower.cpp | 2 +- power-libperfmgr/disp-power/InteractionHandler.cpp | 2 +- power-libperfmgr/hidl/DEPRECATED | 0 10 files changed, 407 insertions(+), 13 deletions(-) create mode 100644 power-libperfmgr/adpf/PowerHintSession.cpp create mode 100644 power-libperfmgr/adpf/PowerHintSession.h create mode 100644 power-libperfmgr/hidl/DEPRECATED diff --git a/power-libperfmgr/Android.bp b/power-libperfmgr/Android.bp index 006b359e..57164f3b 100644 --- a/power-libperfmgr/Android.bp +++ b/power-libperfmgr/Android.bp @@ -17,6 +17,24 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +cc_library { + name: "libadpf-pixel", + relative_install_path: "hw", + proprietary: true, + vendor: true, + srcs: [ + "adpf/PowerHintSession.cpp", + ], + shared_libs: [ + "android.hardware.power-V2-ndk_platform", + "libbase", + "libbinder_ndk", + "libcutils", + "liblog", + "libutils", + ], +} + cc_library { name: "libdisppower-pixel", proprietary: true, @@ -48,7 +66,8 @@ cc_binary { vintf_fragments: ["aidl/android.hardware.power-service.pixel.xml"], vendor: true, shared_libs: [ - "android.hardware.power-V1-ndk_platform", + "android.hardware.power-V2-ndk_platform", + "libadpf-pixel", "libbase", "libcutils", "liblog", diff --git a/power-libperfmgr/adpf/PowerHintSession.cpp b/power-libperfmgr/adpf/PowerHintSession.cpp new file mode 100644 index 00000000..fc8846ad --- /dev/null +++ b/power-libperfmgr/adpf/PowerHintSession.cpp @@ -0,0 +1,251 @@ +/* + * 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 "PowerHintSession.h" + +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { +namespace adpf { + +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; +}; + +int sched_setattr(int pid, struct sched_attr *attr, unsigned int flags) { + return syscall(__NR_sched_setattr, pid, attr, flags); +} +} // namespace + +using ::android::base::StringPrintf; + +PowerHintSession::PowerHintSession(int32_t tgid, int32_t uid, const std::vector &threadIds, + int64_t durationNanos) { + ALOGD("PowerHintSession is ready to process hints"); + mDescriptor = new AppHintDesc(tgid, uid, threadIds); + // TODO(jimmyshiu@): use better control algorithms + mDescriptor->dur_scale = 1.0f; + mDescriptor->tolerance = 0.2f; + mDescriptor->duration = std::chrono::nanoseconds(durationNanos); + + if (ATRACE_ENABLED()) { + std::string sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-duration", mDescriptor->tgid, + mDescriptor->uid, this); + ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count()); + sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-active", mDescriptor->tgid, mDescriptor->uid, + this); + ATRACE_INT(sz.c_str(), mDescriptor->is_active); + } + ALOGD("PowerHintSession create: %s", mDescriptor->toString().c_str()); +} + +PowerHintSession::~PowerHintSession() { + ALOGD("PowerHintSession delete: %s", mDescriptor->toString().c_str()); + if (ATRACE_ENABLED()) { + std::string sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-duration", mDescriptor->tgid, + mDescriptor->uid, this); + ATRACE_INT(sz.c_str(), 0); + sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-min", mDescriptor->tgid, mDescriptor->uid, + this); + ATRACE_INT(sz.c_str(), 0); + sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-max", mDescriptor->tgid, mDescriptor->uid, + this); + ATRACE_INT(sz.c_str(), 0); + sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-actual_latest", mDescriptor->tgid, + mDescriptor->uid, this); + ATRACE_INT(sz.c_str(), 0); + } + delete mDescriptor; +} + +int PowerHintSession::setUclamp(int32_t tid, int32_t min, int32_t max) { + struct sched_attr attr; + memset(&attr, 0, sizeof(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, ret); + return EX_ILLEGAL_STATE; + } + ALOGD("PowerHintSession tid: %d, uclamp(%d, %d)", tid, min, max); + return 0; +} + +ndk::ScopedAStatus PowerHintSession::pause() { + if (!mDescriptor->is_active) + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + for (auto tid : mDescriptor->threadIds) { + setUclamp(tid, 0, 1024); + } + mDescriptor->is_active = false; + if (ATRACE_ENABLED()) { + std::string sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-active", mDescriptor->tgid, + mDescriptor->uid, this); + ATRACE_INT(sz.c_str(), mDescriptor->is_active); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PowerHintSession::resume() { + if (mDescriptor->is_active) + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + for (auto tid : mDescriptor->threadIds) { + setUclamp(tid, mDescriptor->current_min, mDescriptor->current_max); + } + mDescriptor->is_active = true; + if (ATRACE_ENABLED()) { + std::string sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-active", mDescriptor->tgid, + mDescriptor->uid, this); + ATRACE_INT(sz.c_str(), mDescriptor->is_active); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PowerHintSession::close() { + for (auto tid : mDescriptor->threadIds) { + setUclamp(tid, 0, 1024); + } + 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); + } + ALOGD("update target duration: %" PRId64 " ~ %" PRId64 " ns", targetDurationNanos, + (int64_t)(targetDurationNanos * (1.0 - mDescriptor->tolerance))); + /* TODO(jimmyshiu@): if we have some good history then we should probably adjust + * the utilization limits based on the difference between the old and + * new desired durations. For now, we just do nothing and it will resettle + * after a few frames. + */ + mDescriptor->duration = std::chrono::nanoseconds(targetDurationNanos); + + if (ATRACE_ENABLED()) { + std::string sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-duration", mDescriptor->tgid, + mDescriptor->uid, this); + 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) { + ALOGE("Error: shouldn't report duration during pause state."); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + int64_t actualDurationNanos = actualDurations.back().durationNanos; + + constexpr int step_size = 4; + float target_duration = + static_cast(mDescriptor->duration.count() * mDescriptor->dur_scale); + float z = static_cast((actualDurationNanos - target_duration) / target_duration); + if (z > 0) { + mDescriptor->current_min = std::min(1024, mDescriptor->current_min + step_size); + mDescriptor->current_max = std::max(mDescriptor->current_min, mDescriptor->current_max); + } else if (z < -mDescriptor->tolerance) { + mDescriptor->current_max = std::max(0, mDescriptor->current_max - step_size); + mDescriptor->current_min = std::min(mDescriptor->current_min, mDescriptor->current_max); + } else { + return ndk::ScopedAStatus::ok(); + } + + if (ATRACE_ENABLED()) { + std::string sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-min", mDescriptor->tgid, + mDescriptor->uid, this); + ATRACE_INT(sz.c_str(), mDescriptor->current_min); + sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-max", mDescriptor->tgid, mDescriptor->uid, + this); + ATRACE_INT(sz.c_str(), mDescriptor->current_max); + sz = StringPrintf("%" PRId32 "-%" PRId32 "-%p-actual_latest", mDescriptor->tgid, + mDescriptor->uid, this); + ATRACE_INT(sz.c_str(), actualDurationNanos); + } + + /* apply to all the threads in the group */ + for (auto tid : mDescriptor->threadIds) { + setUclamp(tid, mDescriptor->current_min, mDescriptor->current_max); + } + return ndk::ScopedAStatus::ok(); +} + +std::string AppHintDesc::toString() const { + std::string out = StringPrintf("session %p\n", this); + const int64_t durationNanos = duration.count(); + out.append(StringPrintf(" duration: %" PRId64 " ~ %" PRId64 " ns\n", durationNanos, + (int64_t)(durationNanos * (1.0 - tolerance)))); + + 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; +} + +} // namespace adpf +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/power-libperfmgr/adpf/PowerHintSession.h b/power-libperfmgr/adpf/PowerHintSession.h new file mode 100644 index 00000000..32a7d2e7 --- /dev/null +++ b/power-libperfmgr/adpf/PowerHintSession.h @@ -0,0 +1,81 @@ +/* + * 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 + +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { +namespace adpf { + +using aidl::android::hardware::power::WorkDuration; +using std::chrono::nanoseconds; + +struct AppHintDesc { + AppHintDesc(int32_t tgid, int32_t uid, std::vector threadIds) + : tgid(tgid), + uid(uid), + threadIds(std::move(threadIds)), + duration(0LL), + current_min(0), + current_max(1024), + is_active(true) {} + std::string toString() const; + const int32_t tgid; + const int32_t uid; + const std::vector threadIds; + nanoseconds duration; + int current_min; + int current_max; + bool apply; + float dur_scale; + float tolerance; + bool is_active; +}; + +class PowerHintSession : public ::aidl::android::hardware::power::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; + + private: + static int setUclamp(int32_t tid, int32_t max, int32_t min); + AppHintDesc *mDescriptor = nullptr; +}; + +} // namespace adpf +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/power-libperfmgr/aidl/Power.cpp b/power-libperfmgr/aidl/Power.cpp index d944cf40..b3d9d92a 100644 --- a/power-libperfmgr/aidl/Power.cpp +++ b/power-libperfmgr/aidl/Power.cpp @@ -15,7 +15,7 @@ */ #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL) -#define LOG_TAG "android.hardware.power-service.pixel-libperfmgr" +#define LOG_TAG "powerhal-libperfmgr" #include "Power.h" @@ -26,10 +26,12 @@ #include #include #include +#include #include #include +#include "adpf/PowerHintSession.h" #include "disp-power/DisplayLowPower.h" namespace aidl { @@ -39,51 +41,56 @@ namespace power { namespace impl { namespace pixel { +using ::aidl::google::hardware::power::impl::pixel::adpf::PowerHintSession; + constexpr char kPowerHalStateProp[] = "vendor.powerhal.state"; constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio"; constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering"; +constexpr char kPowerHalAdpfRateProp[] = "vendor.powerhal.adpf.rate"; +constexpr int64_t kPowerHalAdpfRateDefault = -1; Power::Power(std::shared_ptr hm, std::shared_ptr dlpw) : mHintManager(hm), mDisplayLowPower(dlpw), mInteractionHandler(nullptr), mVRModeOn(false), - mSustainedPerfModeOn(false) { + mSustainedPerfModeOn(false), + mAdpfRate(::android::base::GetIntProperty(kPowerHalAdpfRateProp, kPowerHalAdpfRateDefault)) { mInteractionHandler = std::make_unique(mHintManager); mInteractionHandler->Init(); std::string state = ::android::base::GetProperty(kPowerHalStateProp, ""); if (state == "SUSTAINED_PERFORMANCE") { - ALOGI("Initialize with SUSTAINED_PERFORMANCE on"); + LOG(INFO) << "Initialize with SUSTAINED_PERFORMANCE on"; mHintManager->DoHint("SUSTAINED_PERFORMANCE"); mSustainedPerfModeOn = true; } else if (state == "VR") { - ALOGI("Initialize with VR on"); + LOG(INFO) << "Initialize with VR on"; mHintManager->DoHint(state); mVRModeOn = true; } else if (state == "VR_SUSTAINED_PERFORMANCE") { - ALOGI("Initialize with SUSTAINED_PERFORMANCE and VR on"); + LOG(INFO) << "Initialize with SUSTAINED_PERFORMANCE and VR on"; mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE"); mSustainedPerfModeOn = true; mVRModeOn = true; } else { - ALOGI("Initialize PowerHAL"); + LOG(INFO) << "Initialize PowerHAL"; } state = ::android::base::GetProperty(kPowerHalAudioProp, ""); if (state == "AUDIO_STREAMING_LOW_LATENCY") { - ALOGI("Initialize with AUDIO_LOW_LATENCY on"); + LOG(INFO) << "Initialize with AUDIO_LOW_LATENCY on"; mHintManager->DoHint(state); } state = ::android::base::GetProperty(kPowerHalRenderingProp, ""); if (state == "EXPENSIVE_RENDERING") { - ALOGI("Initialize with EXPENSIVE_RENDERING on"); + LOG(INFO) << "Initialize with EXPENSIVE_RENDERING on"; mHintManager->DoHint("EXPENSIVE_RENDERING"); } // Now start to take powerhint - ALOGI("PowerHAL ready to process hints"); + LOG(INFO) << "PowerHAL ready to take hints, Adpf update rate: " << mAdpfRate; } ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) { @@ -248,6 +255,34 @@ binder_status_t Power::dump(int fd, const char **, uint32_t) { return STATUS_OK; } +ndk::ScopedAStatus Power::createHintSession(int32_t tgid, int32_t uid, + const std::vector &threadIds, + int64_t durationNanos, + std::shared_ptr *_aidl_return) { + if (mAdpfRate == -1) { + *_aidl_return = nullptr; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + if (threadIds.size() == 0) { + LOG(ERROR) << "Error: threadIds.size() shouldn't be " << threadIds.size(); + *_aidl_return = nullptr; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + std::shared_ptr session = + ndk::SharedRefBase::make(tgid, uid, threadIds, durationNanos); + *_aidl_return = session; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Power::getHintSessionPreferredRate(int64_t *outNanoseconds) { + *outNanoseconds = mAdpfRate; + if (mAdpfRate == -1) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + + return ndk::ScopedAStatus::ok(); +} + } // namespace pixel } // namespace impl } // namespace power diff --git a/power-libperfmgr/aidl/Power.h b/power-libperfmgr/aidl/Power.h index a5157ce8..75685894 100644 --- a/power-libperfmgr/aidl/Power.h +++ b/power-libperfmgr/aidl/Power.h @@ -34,6 +34,7 @@ namespace impl { namespace pixel { using ::aidl::android::hardware::power::Boost; +using ::aidl::android::hardware::power::IPowerHintSession; using ::aidl::android::hardware::power::Mode; using ::android::perfmgr::HintManager; @@ -44,6 +45,11 @@ class Power : public ::aidl::android::hardware::power::BnPower { ndk::ScopedAStatus isModeSupported(Mode type, bool *_aidl_return) override; ndk::ScopedAStatus setBoost(Boost type, int32_t durationMs) override; ndk::ScopedAStatus isBoostSupported(Boost type, bool *_aidl_return) override; + ndk::ScopedAStatus createHintSession(int32_t tgid, int32_t uid, + const std::vector &threadIds, + int64_t durationNanos, + std::shared_ptr *_aidl_return) override; + ndk::ScopedAStatus getHintSessionPreferredRate(int64_t *outNanoseconds) override; binder_status_t dump(int fd, const char **args, uint32_t numArgs) override; private: @@ -52,6 +58,7 @@ class Power : public ::aidl::android::hardware::power::BnPower { std::unique_ptr mInteractionHandler; std::atomic mVRModeOn; std::atomic mSustainedPerfModeOn; + const int64_t mAdpfRate; }; } // namespace pixel diff --git a/power-libperfmgr/aidl/android.hardware.power-service.pixel.xml b/power-libperfmgr/aidl/android.hardware.power-service.pixel.xml index caf6ea2d..9f56debd 100644 --- a/power-libperfmgr/aidl/android.hardware.power-service.pixel.xml +++ b/power-libperfmgr/aidl/android.hardware.power-service.pixel.xml @@ -1,6 +1,7 @@ android.hardware.power + 2 IPower/default diff --git a/power-libperfmgr/aidl/service.cpp b/power-libperfmgr/aidl/service.cpp index 388139d8..aa32fc5e 100644 --- a/power-libperfmgr/aidl/service.cpp +++ b/power-libperfmgr/aidl/service.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.power-service.pixel-libperfmgr" +#define LOG_TAG "powerhal-libperfmgr" #include diff --git a/power-libperfmgr/disp-power/DisplayLowPower.cpp b/power-libperfmgr/disp-power/DisplayLowPower.cpp index a78c2781..f2da5746 100644 --- a/power-libperfmgr/disp-power/DisplayLowPower.cpp +++ b/power-libperfmgr/disp-power/DisplayLowPower.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.power@-service.pixel-libperfmgr" +#define LOG_TAG "powerhal-libperfmgr" #include #include diff --git a/power-libperfmgr/disp-power/InteractionHandler.cpp b/power-libperfmgr/disp-power/InteractionHandler.cpp index a2ff9d4b..f6cd0e9a 100644 --- a/power-libperfmgr/disp-power/InteractionHandler.cpp +++ b/power-libperfmgr/disp-power/InteractionHandler.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.power@-service.pixel-libperfmgr" +#define LOG_TAG "powerhal-libperfmgr" #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL) #include diff --git a/power-libperfmgr/hidl/DEPRECATED b/power-libperfmgr/hidl/DEPRECATED new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3