Merge "power: remove interaction lock when idle" into oc-dr1-dev

This commit is contained in:
TreeHugger Robot
2017-06-22 01:37:42 +00:00
committed by Android (Google) Code Review
13 changed files with 402 additions and 66 deletions

View File

@@ -188,6 +188,7 @@ on post-fs
chmod 0664 /sys/devices/virtual/graphics/fb0/idle_time
chown system graphics /sys/devices/virtual/graphics/fb0/idle_time
write /sys/devices/virtual/graphics/fb0/idle_time 100
# Wait qseecomd started
wait_for_prop sys.listeners.registered true

View File

@@ -23,7 +23,16 @@ LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := android.hardware.power@1.1-service.wahoo
LOCAL_INIT_RC := android.hardware.power@1.1-service.wahoo.rc
LOCAL_SRC_FILES := service.cpp Power.cpp power-helper.c metadata-parser.c utils.c list.c hint-data.c powerhintparser.c
LOCAL_SRC_FILES := service.cpp \
Power.cpp \
InteractionHandler.cpp \
power-helper.c \
metadata-parser.c \
utils.c \
list.c \
hint-data.c \
powerhintparser.c
LOCAL_C_INCLUDES := external/libxml2/include \
external/icu/icu4c/source/common
@@ -32,7 +41,7 @@ LOCAL_SRC_FILES += power-8998.c
# Enable interaction boost all the time
LOCAL_CFLAGS += -DINTERACTION_BOOST
LOCAL_CFLAGS += -DINTERACTION_BOOST -Werror
LOCAL_SHARED_LIBRARIES := \
liblog \

View File

@@ -0,0 +1,258 @@
/*
* 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 specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "PowerInteractionHandler"
#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
#include <fcntl.h>
#include <poll.h>
#include <sys/eventfd.h>
#include <time.h>
#include <unistd.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include "InteractionHandler.h"
#include "power-common.h"
#include "power-helper.h"
#include "powerhintparser.h"
#include "hint-data.h"
#include "utils.h"
#define FB_IDLE_PATH "/sys/class/graphics/fb0/idle_state"
#define MAX_LENGTH 64
#define MSINSEC 1000L
#define USINMS 1000000L
InteractionHandler::InteractionHandler()
: mState(INTERACTION_STATE_UNINITIALIZED),
mWaitMs(100),
mMinDurationMs(1400),
mMaxDurationMs(5650),
mDurationMs(0) {
}
InteractionHandler::~InteractionHandler() {
Exit();
}
bool InteractionHandler::Init() {
std::lock_guard<std::mutex> lk(mLock);
if (mState != INTERACTION_STATE_UNINITIALIZED)
return true;
mIdleFd = open(FB_IDLE_PATH, O_RDONLY);
if (mIdleFd < 0) {
ALOGE("Unable to open idle state path (%d)", errno);
return false;
}
mEventFd = eventfd(0, EFD_NONBLOCK);
if (mEventFd < 0) {
ALOGE("Unable to create event fd (%d)", errno);
close(mIdleFd);
return false;
}
mState = INTERACTION_STATE_IDLE;
mThread = std::unique_ptr<std::thread>(
new std::thread(&InteractionHandler::Routine, this));
return true;
}
void InteractionHandler::Exit() {
std::unique_lock<std::mutex> lk(mLock);
if (mState == INTERACTION_STATE_UNINITIALIZED)
return;
AbortWaitLocked();
mState = INTERACTION_STATE_UNINITIALIZED;
lk.unlock();
mCond.notify_all();
mThread->join();
close(mEventFd);
close(mIdleFd);
}
void InteractionHandler::PerfLock() {
int *resource_values;
int num_resources;
resource_values = getPowerhint(INTERACTION_HINT_ID, &num_resources);
if (resource_values != NULL) {
ALOGV("%s: acquiring perf lock", __func__);
perform_hint_action(INTERACTION_HINT_ID,
resource_values, num_resources);
ATRACE_INT("interaction_lock", 1);
}
}
void InteractionHandler::PerfRel() {
ALOGV("%s: releasing perf lock", __func__);
undo_hint_action(INTERACTION_HINT_ID);
ATRACE_INT("interaction_lock", 0);
}
long long InteractionHandler::CalcTimespecDiffMs(struct timespec start,
struct timespec end) {
long long diff_in_us = 0;
diff_in_us += (end.tv_sec - start.tv_sec) * MSINSEC;
diff_in_us += (end.tv_nsec - start.tv_nsec) / USINMS;
return diff_in_us;
}
void InteractionHandler::Acquire(int32_t duration) {
if (is_perf_hint_active(SUSTAINED_PERF_HINT_ID) ||
is_perf_hint_active(VR_MODE_HINT_ID)) {
ALOGV("%s: ignoring due to other active perf hints", __func__);
return;
}
ATRACE_CALL();
std::lock_guard<std::mutex> lk(mLock);
if (mState == INTERACTION_STATE_UNINITIALIZED) {
ALOGW("%s: called while uninitialized", __func__);
return;
}
int inputDuration = duration + 650;
int finalDuration;
if (inputDuration > mMaxDurationMs)
finalDuration = mMaxDurationMs;
else if (inputDuration > mMinDurationMs)
finalDuration = inputDuration;
else
finalDuration = mMinDurationMs;
struct timespec cur_timespec;
clock_gettime(CLOCK_MONOTONIC, &cur_timespec);
if (finalDuration <= mDurationMs) {
long long elapsed_time = CalcTimespecDiffMs(mLastTimespec, cur_timespec);
// don't hint if previous hint's duration covers this hint's duration
if (elapsed_time <= (mDurationMs - finalDuration)) {
ALOGV("%s: Previous duration (%d) cover this (%d) elapsed: %lld",
__func__, mDurationMs, finalDuration, elapsed_time);
return;
}
}
mLastTimespec = cur_timespec;
mDurationMs = finalDuration;
ALOGV("%s: input: %d final duration: %d", __func__,
duration, finalDuration);
if (mState == INTERACTION_STATE_WAITING)
AbortWaitLocked();
else if (mState == INTERACTION_STATE_IDLE)
PerfLock();
mState = INTERACTION_STATE_INTERACTION;
mCond.notify_one();
}
void InteractionHandler::Release() {
std::lock_guard<std::mutex> lk(mLock);
if (mState == INTERACTION_STATE_WAITING) {
ATRACE_CALL();
PerfRel();
mState = INTERACTION_STATE_IDLE;
} else {
// clear any wait aborts pending in event fd
uint64_t val;
ssize_t ret = read(mEventFd, &val, sizeof(val));
ALOGW_IF(ret < 0, "%s: failed to clear eventfd (%zd, %d)",
__func__, ret, errno);
}
}
// should be called while locked
void InteractionHandler::AbortWaitLocked() {
uint64_t val = 1;
ssize_t ret = write(mEventFd, &val, sizeof(val));
if (ret != sizeof(val))
ALOGW("Unable to write to event fd (%zd)", ret);
}
void InteractionHandler::WaitForIdle(int32_t wait_ms, int32_t timeout_ms) {
char data[MAX_LENGTH];
ssize_t ret;
struct pollfd pfd[2];
ATRACE_CALL();
ALOGV("%s: wait:%d timeout:%d", __func__, wait_ms, timeout_ms);
pfd[0].fd = mEventFd;
pfd[0].events = POLLIN;
pfd[1].fd = mIdleFd;
pfd[1].events = POLLPRI | POLLERR;
ret = poll(pfd, 1, wait_ms);
if (ret > 0) {
ALOGV("%s: wait aborted", __func__);
return;
} else if (ret < 0) {
ALOGE("%s: error in poll while waiting", __func__);
return;
}
ret = pread(mIdleFd, data, sizeof(data), 0);
if (!ret) {
ALOGE("%s: Unexpected EOF!", __func__);
return;
}
if (!strncmp(data, "idle", 4)) {
ALOGV("%s: already idle", __func__);
return;
}
ret = poll(pfd, 2, timeout_ms);
if (ret < 0)
ALOGE("%s: Error on waiting for idle (%zd)", __func__, ret);
else if (ret == 0)
ALOGV("%s: timed out waiting for idle", __func__);
else if (pfd[0].revents)
ALOGV("%s: wait for idle aborted", __func__);
else if (pfd[1].revents)
ALOGV("%s: idle detected", __func__);
}
void InteractionHandler::Routine() {
std::unique_lock<std::mutex> lk(mLock, std::defer_lock);
while (true) {
lk.lock();
mCond.wait(lk, [&] { return mState != INTERACTION_STATE_IDLE; });
if (mState == INTERACTION_STATE_UNINITIALIZED)
return;
mState = INTERACTION_STATE_WAITING;
lk.unlock();
WaitForIdle(mWaitMs, mDurationMs);
Release();
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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 specific language governing permissions and
* limitations under the License.
*/
#ifndef INTERACTIONHANDLER_H
#define INTERACTIONHANDLER_H
#include <condition_variable>
#include <mutex>
#include <thread>
enum interaction_state {
INTERACTION_STATE_UNINITIALIZED,
INTERACTION_STATE_IDLE,
INTERACTION_STATE_INTERACTION,
INTERACTION_STATE_WAITING,
};
struct InteractionHandler {
InteractionHandler();
~InteractionHandler();
bool Init();
void Exit();
void Acquire(int32_t duration);
private:
void Release();
void WaitForIdle(int32_t wait_ms, int32_t timeout_ms);
void AbortWaitLocked();
void Routine();
void PerfLock();
void PerfRel();
long long CalcTimespecDiffMs(struct timespec start, struct timespec end);
enum interaction_state mState;
int mIdleFd;
int mEventFd;
int32_t mWaitMs;
int32_t mMinDurationMs;
int32_t mMaxDurationMs;
int32_t mDurationMs;
struct timespec mLastTimespec;
std::unique_ptr<std::thread> mThread;
std::mutex mLock;
std::condition_variable mCond;
};
#endif //INTERACTIONHANDLER_H

View File

@@ -44,6 +44,7 @@ using ::android::hardware::Void;
Power::Power() {
power_init();
mInteractionHandler.Init();
}
// Methods from ::android::hardware::power::V1_0::IPower follow.
@@ -53,9 +54,12 @@ Return<void> Power::setInteractive(bool interactive) {
}
Return<void> Power::powerHint(PowerHint hint, int32_t data) {
power_hint(static_cast<power_hint_t>(hint), data ? (&data) : NULL);
power_hint_t h = static_cast<power_hint_t>(hint);
if (h == POWER_HINT_INTERACTION) {
mInteractionHandler.Acquire(data);
return Void();
}
power_hint(h, data ? &data : NULL);
return Void();
}
@@ -90,7 +94,7 @@ Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_c
state->supportedOnlyInSuspend = false;
state->voters.resize(XO_VOTERS);
for(size_t i = 0; i < XO_VOTERS; i++) {
int voter = i + XO_VOTERS_START;
int voter = static_cast<int>(i + XO_VOTERS_START);
state->voters[i].name = rpm_stat_map[voter].label;
values = stats + (voter * MAX_RPM_PARAMS);
state->voters[i].totalTimeInMsecVotedForSinceBoot = values[0] / RPM_CLK;

View File

@@ -22,6 +22,8 @@
#include <hidl/Status.h>
#include <hardware/power.h>
#include "InteractionHandler.h"
namespace android {
namespace hardware {
namespace power {
@@ -33,6 +35,7 @@ using ::android::hardware::power::V1_0::PowerHint;
using ::android::hardware::power::V1_1::IPower;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::InteractionHandler;
struct Power : public IPower {
// Methods from ::android::hardware::power::V1_0::IPower follow.
@@ -49,6 +52,8 @@ struct Power : public IPower {
// Methods from ::android::hidl::base::V1_0::IBase follow.
private:
InteractionHandler mInteractionHandler;
};
} // namespace implementation

View File

@@ -48,9 +48,6 @@
#include "power-common.h"
#include "powerhintparser.h"
#define USINSEC 1000000L
#define NSINUS 1000L
static int sustained_mode_handle = 0;
static int vr_mode_handle = 0;
static int launch_handle = 0;
@@ -59,10 +56,18 @@ static int vr_mode = 0;
static int launch_mode = 0;
#define CHECK_HANDLE(x) (((x)>0) && ((x)!=-1))
static struct timespec s_previous_boost_timespec;
static int s_previous_duration;
void interaction(int duration, int num_args, int opt_list[]);
int is_perf_hint_active(int hint)
{
switch (hint) {
case SUSTAINED_PERF_HINT_ID:
return sustained_performance_mode != 0;
case VR_MODE_HINT_ID:
return vr_mode != 0;
case VR_MODE_SUSTAINED_PERF_HINT_ID:
return vr_mode != 0 && sustained_performance_mode != 0;
}
return 0;
}
static int process_sustained_perf_hint(void *data)
{
@@ -272,50 +277,6 @@ static int process_activity_launch_hint(void *data)
return HINT_NONE;
}
static long long calc_timespan_us(struct timespec start, struct timespec end) {
long long diff_in_us = 0;
diff_in_us += (end.tv_sec - start.tv_sec) * USINSEC;
diff_in_us += (end.tv_nsec - start.tv_nsec) / NSINUS;
return diff_in_us;
}
static int interaction_hint(void *data)
{
if (sustained_performance_mode || vr_mode) {
ALOGW("%s: already handled?", __FUNCTION__);
return HINT_HANDLED;
}
int duration = 1500; // 1.5s by default
if (data) {
int input_duration = *((int*)data) + 750;
if (input_duration > duration) {
duration = (input_duration > 5750) ? 5750 : input_duration;
}
}
struct timespec cur_boost_timespec;
clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
long long elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
// don't hint if previous hint's duration covers this hint's duration
if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
return HINT_HANDLED;
}
s_previous_boost_timespec = cur_boost_timespec;
s_previous_duration = duration;
int *resource_values;
int num_resources;
/* extract perflock resources */
resource_values = getPowerhint(INTERACTION_HINT_ID, &num_resources);
if (resource_values != NULL)
interaction(duration, num_resources, resource_values);
return HINT_HANDLED;
}
int power_hint_override(power_hint_t hint, void *data)
{
int ret_val = HINT_NONE;
@@ -329,9 +290,6 @@ int power_hint_override(power_hint_t hint, void *data)
case POWER_HINT_VR_MODE:
ret_val = process_vr_mode_hint(data);
break;
case POWER_HINT_INTERACTION:
ret_val = interaction_hint(data);
break;
case POWER_HINT_LAUNCH:
ret_val = process_activity_launch_hint(data);
break;

View File

@@ -255,6 +255,11 @@ void power_hint(power_hint_t hint, void *data)
}
}
int __attribute__ ((weak)) is_perf_hint_active(int UNUSED(hint))
{
return 0;
}
int __attribute__ ((weak)) set_interactive_override(int UNUSED(on))
{
return HINT_NONE;

View File

@@ -100,6 +100,7 @@ void power_set_interactive(int on);
int extract_platform_stats(uint64_t *list);
int extract_wlan_stats(uint64_t *list);
int is_perf_hint_active(int hint);
#ifdef __cplusplus
}

View File

@@ -43,6 +43,15 @@ typedef struct perflock_param_t {
static perflock_param_t powerhint[MAX_HINT];
int parsePowerhintXML();
int *getPowerhint(int, int*);
#ifdef __cplusplus
extern "C" {
#endif
int *getPowerhint(int, int *);
#ifdef __cplusplus
}
#endif
#endif /* __POWERHINTPARSER__ */

View File

@@ -239,7 +239,7 @@ void perform_hint_action(int hint_id, int resource_values[], int num_resources)
num_resources);
if (lock_handle == -1) {
ALOGE("Failed to acquire lock.");
ALOGE("%s: Failed to acquire lock.", __func__);
} else {
/* Add this handle to our internal hint-list. */
struct hint_data *new_hint =

View File

@@ -27,20 +27,36 @@
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UTILS_H
#define UTILS_H
#include <cutils/properties.h>
#ifdef __cplusplus
extern "C" {
#endif
int sysfs_read(char *path, char *s, int num_bytes);
int sysfs_write(char *path, char *s);
int get_scaling_governor(char governor[], int size);
int get_scaling_governor_check_cores(char governor[], int size,int core_num);
int is_interactive_governor(char*);
int get_scaling_governor_check_cores(char governor[], int size, int core_num);
int is_interactive_governor(char *);
void vote_ondemand_io_busy_off();
void unvote_ondemand_io_busy_off();
void vote_ondemand_sdf_low();
void unvote_ondemand_sdf_low();
void perform_hint_action(int hint_id, int resource_values[],
int num_resources);
int num_resources);
void undo_hint_action(int hint_id);
void release_request(int lock_handle);
int interaction_with_handle(int lock_handle, int duration, int num_args, int opt_list[]);
int interaction_with_handle(int lock_handle,
int duration,
int num_args,
int opt_list[]);
#ifdef __cplusplus
}
#endif
#endif //UTILS_H

View File

@@ -1,6 +1,9 @@
allow hal_power_default perfd:unix_stream_socket connectto;
allow hal_power_default perfd_socket:sock_file write;
allow hal_power_default sysfs_graphics:dir search;
allow hal_power_default sysfs_graphics:file r_file_perms;
userdebug_or_eng(`
# debugfs entries are only needed in user-debug or eng builds
allow hal_power_default debugfs_rpm:file r_file_perms;