Bo Liu 027b218847 Integrate HWUI with PerformanceHintManager
PerformanceHintManager.Session is in java, so add JNI and a HintSessionWrapper
class in HardwareRenderer. Then pass the two calls as two std::functions
into DrawFrameTask.

Note Session is created per HardwareRenderer, not global (per
RenderThread).

Session includes UI thread, render thread, and the thread pool.
Desired duration is from the intended start duration to the frame
deadline. Add an actual frame start time to compute

Add system properties:
debug.hwui.use_hint_manager to enable PerformanceHintManager
debug.hwui.target_cpu_time_percent to control percentage of frame time
  to be used for target cpu duration.

Test: Manual test that there are no crashes and values make sense.
Bug: 158791282
Change-Id: I83f25433c10daa20033803fb7c4ae45eab34f1d3
2021-04-10 10:21:17 -07:00

130 lines
3.5 KiB
C++

/*
* Copyright (C) 2019 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.
*/
#include "CommonPool.h"
#include <sys/resource.h>
#include <utils/Trace.h>
#include "renderthread/RenderThread.h"
#include <array>
namespace android {
namespace uirenderer {
CommonPool::CommonPool() {
ATRACE_CALL();
CommonPool* pool = this;
std::mutex mLock;
std::vector<int> tids(THREAD_COUNT);
std::vector<std::condition_variable> tidConditionVars(THREAD_COUNT);
// Create 2 workers
for (int i = 0; i < THREAD_COUNT; i++) {
std::thread worker([pool, i, &mLock, &tids, &tidConditionVars] {
{
std::array<char, 20> name{"hwuiTask"};
snprintf(name.data(), name.size(), "hwuiTask%d", i);
auto self = pthread_self();
pthread_setname_np(self, name.data());
{
std::unique_lock lock(mLock);
tids[i] = pthread_gettid_np(self);
tidConditionVars[i].notify_one();
}
setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND);
auto startHook = renderthread::RenderThread::getOnStartHook();
if (startHook) {
startHook(name.data());
}
}
pool->workerLoop();
});
worker.detach();
}
{
std::unique_lock lock(mLock);
for (int i = 0; i < THREAD_COUNT; i++) {
while (!tids[i]) {
tidConditionVars[i].wait(lock);
}
}
}
mWorkerThreadIds = std::move(tids);
}
CommonPool& CommonPool::instance() {
static CommonPool pool;
return pool;
}
void CommonPool::post(Task&& task) {
instance().enqueue(std::move(task));
}
std::vector<int> CommonPool::getThreadIds() {
return instance().mWorkerThreadIds;
}
void CommonPool::enqueue(Task&& task) {
std::unique_lock lock(mLock);
while (!mWorkQueue.hasSpace()) {
lock.unlock();
usleep(100);
lock.lock();
}
mWorkQueue.push(std::move(task));
if (mWaitingThreads == THREAD_COUNT || (mWaitingThreads > 0 && mWorkQueue.size() > 1)) {
mCondition.notify_one();
}
}
void CommonPool::workerLoop() {
std::unique_lock lock(mLock);
while (true) {
if (!mWorkQueue.hasWork()) {
mWaitingThreads++;
mCondition.wait(lock);
mWaitingThreads--;
}
// Need to double-check that work is still available now that we have the lock
// It may have already been grabbed by a different thread
while (mWorkQueue.hasWork()) {
auto work = mWorkQueue.pop();
lock.unlock();
work();
lock.lock();
}
}
}
void CommonPool::waitForIdle() {
instance().doWaitForIdle();
}
void CommonPool::doWaitForIdle() {
std::unique_lock lock(mLock);
while (mWaitingThreads != THREAD_COUNT) {
lock.unlock();
usleep(100);
lock.lock();
}
}
} // namespace uirenderer
} // namespace android