Merge "Remove old TaskManager system"
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
#include <renderthread/CanvasContext.h>
|
||||
#include <TreeInfo.h>
|
||||
#include <hwui/Paint.h>
|
||||
#include <utils/TraceUtils.h>
|
||||
|
||||
#include "core_jni_helpers.h"
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ cc_defaults {
|
||||
"surfacetexture/EGLConsumer.cpp",
|
||||
"surfacetexture/ImageConsumer.cpp",
|
||||
"surfacetexture/SurfaceTexture.cpp",
|
||||
"thread/TaskManager.cpp",
|
||||
"thread/CommonPool.cpp",
|
||||
"utils/Blur.cpp",
|
||||
"utils/Color.cpp",
|
||||
"utils/GLUtils.cpp",
|
||||
@@ -308,6 +308,7 @@ cc_test {
|
||||
"tests/unit/main.cpp",
|
||||
"tests/unit/CacheManagerTests.cpp",
|
||||
"tests/unit/CanvasContextTests.cpp",
|
||||
"tests/unit/CommonPoolTests.cpp",
|
||||
"tests/unit/DamageAccumulatorTests.cpp",
|
||||
"tests/unit/DeferredLayerUpdaterTests.cpp",
|
||||
"tests/unit/FatVectorTests.cpp",
|
||||
@@ -381,7 +382,6 @@ cc_benchmark {
|
||||
"tests/microbench/LinearAllocatorBench.cpp",
|
||||
"tests/microbench/PathParserBench.cpp",
|
||||
"tests/microbench/RenderNodeBench.cpp",
|
||||
"tests/microbench/TaskManagerBench.cpp",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "hwui/Bitmap.h"
|
||||
#include "utils/Color.h"
|
||||
#include "utils/MathUtils.h"
|
||||
#include "utils/TraceUtils.h"
|
||||
|
||||
using namespace android::uirenderer::renderthread;
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <SkPictureRecorder.h>
|
||||
#include "TreeInfo.h"
|
||||
#include "VectorDrawable.h"
|
||||
#include "thread/CommonPool.h"
|
||||
#include "utils/TraceUtils.h"
|
||||
|
||||
#include <unistd.h>
|
||||
@@ -49,10 +50,6 @@ SkiaPipeline::~SkiaPipeline() {
|
||||
unpinImages();
|
||||
}
|
||||
|
||||
TaskManager* SkiaPipeline::getTaskManager() {
|
||||
return mRenderThread.cacheManager().getTaskManager();
|
||||
}
|
||||
|
||||
void SkiaPipeline::onDestroyHardwareResources() {
|
||||
unpinImages();
|
||||
mRenderThread.cacheManager().trimStaleResources();
|
||||
@@ -225,42 +222,21 @@ void SkiaPipeline::renderVectorDrawableCache() {
|
||||
}
|
||||
}
|
||||
|
||||
class SkiaPipeline::SavePictureProcessor : public TaskProcessor<bool> {
|
||||
public:
|
||||
explicit SavePictureProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {}
|
||||
|
||||
struct SavePictureTask : public Task<bool> {
|
||||
sk_sp<SkData> data;
|
||||
std::string filename;
|
||||
};
|
||||
|
||||
void savePicture(const sk_sp<SkData>& data, const std::string& filename) {
|
||||
sp<SavePictureTask> task(new SavePictureTask());
|
||||
task->data = data;
|
||||
task->filename = filename;
|
||||
TaskProcessor<bool>::add(task);
|
||||
}
|
||||
|
||||
virtual void onProcess(const sp<Task<bool>>& task) override {
|
||||
ATRACE_NAME("SavePictureTask");
|
||||
SavePictureTask* t = static_cast<SavePictureTask*>(task.get());
|
||||
|
||||
if (0 == access(t->filename.c_str(), F_OK)) {
|
||||
task->setResult(false);
|
||||
static void savePictureAsync(const sk_sp<SkData>& data, const std::string& filename) {
|
||||
CommonPool::post([data, filename] {
|
||||
if (0 == access(filename.c_str(), F_OK)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkFILEWStream stream(t->filename.c_str());
|
||||
SkFILEWStream stream(filename.c_str());
|
||||
if (stream.isValid()) {
|
||||
stream.write(t->data->data(), t->data->size());
|
||||
stream.write(data->data(), data->size());
|
||||
stream.flush();
|
||||
SkDebugf("SKP Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(),
|
||||
t->filename.c_str());
|
||||
filename.c_str());
|
||||
}
|
||||
|
||||
task->setResult(true);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
|
||||
if (CC_UNLIKELY(Properties::skpCaptureEnabled)) {
|
||||
@@ -297,16 +273,10 @@ void SkiaPipeline::endCapture(SkSurface* surface) {
|
||||
ATRACE_END();
|
||||
|
||||
// offload saving to file in a different thread
|
||||
if (!mSavePictureProcessor.get()) {
|
||||
TaskManager* taskManager = getTaskManager();
|
||||
mSavePictureProcessor = new SavePictureProcessor(
|
||||
taskManager->canRunTasks() ? taskManager : nullptr);
|
||||
}
|
||||
if (1 == mCaptureSequence) {
|
||||
mSavePictureProcessor->savePicture(data, mCapturedFile);
|
||||
savePictureAsync(data, mCapturedFile);
|
||||
} else {
|
||||
mSavePictureProcessor->savePicture(
|
||||
data,
|
||||
savePictureAsync(data,
|
||||
mCapturedFile + "_" + std::to_string(mCaptureSequence));
|
||||
}
|
||||
mCaptureSequence--;
|
||||
|
||||
@@ -33,8 +33,6 @@ public:
|
||||
explicit SkiaPipeline(renderthread::RenderThread& thread);
|
||||
virtual ~SkiaPipeline();
|
||||
|
||||
TaskManager* getTaskManager() override;
|
||||
|
||||
void onDestroyHardwareResources() override;
|
||||
|
||||
bool pinImages(std::vector<SkImage*>& mutableImages) override;
|
||||
@@ -157,11 +155,7 @@ private:
|
||||
* mCaptureSequence counts how many frames are left to take in the sequence.
|
||||
*/
|
||||
int mCaptureSequence = 0;
|
||||
/**
|
||||
* mSavePictureProcessor is used to run the file saving code in a separate thread.
|
||||
*/
|
||||
class SavePictureProcessor;
|
||||
sp<SavePictureProcessor> mSavePictureProcessor;
|
||||
|
||||
/**
|
||||
* mRecorder holds the current picture recorder. We could store it on the stack to support
|
||||
* parallel tryCapture calls (not really needed).
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "pipeline/skia/SkiaMemoryTracer.h"
|
||||
#include "Properties.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "thread/CommonPool.h"
|
||||
|
||||
#include <GrContextOptions.h>
|
||||
#include <SkExecutor.h>
|
||||
@@ -76,29 +77,15 @@ void CacheManager::updateContextCacheSizes() {
|
||||
mGrContext->setResourceCacheLimits(mMaxResources, mMaxResourceBytes);
|
||||
}
|
||||
|
||||
class CacheManager::SkiaTaskProcessor : public TaskProcessor<bool>, public SkExecutor {
|
||||
class CommonPoolExecutor : public SkExecutor {
|
||||
public:
|
||||
explicit SkiaTaskProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {}
|
||||
|
||||
// This is really a Task<void> but that doesn't really work when Future<>
|
||||
// expects to be able to get/set a value
|
||||
struct SkiaTask : public Task<bool> {
|
||||
std::function<void()> func;
|
||||
};
|
||||
|
||||
virtual void add(std::function<void(void)> func) override {
|
||||
sp<SkiaTask> task(new SkiaTask());
|
||||
task->func = func;
|
||||
TaskProcessor<bool>::add(task);
|
||||
}
|
||||
|
||||
virtual void onProcess(const sp<Task<bool> >& task) override {
|
||||
SkiaTask* t = static_cast<SkiaTask*>(task.get());
|
||||
t->func();
|
||||
task->setResult(true);
|
||||
CommonPool::post(std::move(func));
|
||||
}
|
||||
};
|
||||
|
||||
static CommonPoolExecutor sDefaultExecutor;
|
||||
|
||||
void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, ssize_t size) {
|
||||
contextOptions->fAllowPathMaskCaching = true;
|
||||
|
||||
@@ -107,12 +94,7 @@ void CacheManager::configureContext(GrContextOptions* contextOptions, const void
|
||||
// provided to Skia.
|
||||
contextOptions->fGlyphCacheTextureMaximumBytes = GrNextSizePow2(mMaxSurfaceArea);
|
||||
|
||||
if (mTaskManager.canRunTasks()) {
|
||||
if (!mTaskProcessor.get()) {
|
||||
mTaskProcessor = new SkiaTaskProcessor(&mTaskManager);
|
||||
}
|
||||
contextOptions->fExecutor = mTaskProcessor.get();
|
||||
}
|
||||
contextOptions->fExecutor = &sDefaultExecutor;
|
||||
|
||||
auto& cache = skiapipeline::ShaderCache::get();
|
||||
cache.initShaderDiskCache(identity, size);
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "pipeline/skia/VectorDrawableAtlas.h"
|
||||
#include "thread/TaskManager.h"
|
||||
#include "thread/TaskProcessor.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
@@ -54,8 +52,6 @@ public:
|
||||
size_t getCacheSize() const { return mMaxResourceBytes; }
|
||||
size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; }
|
||||
|
||||
TaskManager* getTaskManager() { return &mTaskManager; }
|
||||
|
||||
private:
|
||||
friend class RenderThread;
|
||||
|
||||
@@ -78,10 +74,6 @@ private:
|
||||
};
|
||||
|
||||
sp<skiapipeline::VectorDrawableAtlas> mVectorDrawableAtlas;
|
||||
|
||||
class SkiaTaskProcessor;
|
||||
sp<SkiaTaskProcessor> mTaskProcessor;
|
||||
TaskManager mTaskManager;
|
||||
};
|
||||
|
||||
} /* namespace renderthread */
|
||||
|
||||
@@ -27,8 +27,10 @@
|
||||
#include "pipeline/skia/SkiaOpenGLPipeline.h"
|
||||
#include "pipeline/skia/SkiaPipeline.h"
|
||||
#include "pipeline/skia/SkiaVulkanPipeline.h"
|
||||
#include "thread/CommonPool.h"
|
||||
#include "utils/GLUtils.h"
|
||||
#include "utils/TimeUtils.h"
|
||||
#include "utils/TraceUtils.h"
|
||||
#include "../Properties.h"
|
||||
|
||||
#include <cutils/properties.h>
|
||||
@@ -603,31 +605,14 @@ void CanvasContext::waitOnFences() {
|
||||
if (mFrameFences.size()) {
|
||||
ATRACE_CALL();
|
||||
for (auto& fence : mFrameFences) {
|
||||
fence->getResult();
|
||||
fence.get();
|
||||
}
|
||||
mFrameFences.clear();
|
||||
}
|
||||
}
|
||||
|
||||
class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> {
|
||||
public:
|
||||
explicit FuncTaskProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {}
|
||||
|
||||
virtual void onProcess(const sp<Task<bool> >& task) override {
|
||||
FuncTask* t = static_cast<FuncTask*>(task.get());
|
||||
t->func();
|
||||
task->setResult(true);
|
||||
}
|
||||
};
|
||||
|
||||
void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
|
||||
if (!mFrameWorkProcessor.get()) {
|
||||
mFrameWorkProcessor = new FuncTaskProcessor(mRenderPipeline->getTaskManager());
|
||||
}
|
||||
sp<FuncTask> task(new FuncTask());
|
||||
task->func = func;
|
||||
mFrameFences.push_back(task);
|
||||
mFrameWorkProcessor->add(task);
|
||||
mFrameFences.push_back(CommonPool::async(std::move(func)));
|
||||
}
|
||||
|
||||
int64_t CanvasContext::getFrameNumber() {
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
#include "ReliableSurface.h"
|
||||
#include "renderthread/RenderTask.h"
|
||||
#include "renderthread/RenderThread.h"
|
||||
#include "thread/Task.h"
|
||||
#include "thread/TaskProcessor.h"
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <SkBitmap.h>
|
||||
@@ -42,6 +40,7 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <future>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
@@ -274,15 +273,7 @@ private:
|
||||
// Stores the bounds of the main content.
|
||||
Rect mContentDrawBounds;
|
||||
|
||||
// TODO: This is really a Task<void> but that doesn't really work
|
||||
// when Future<> expects to be able to get/set a value
|
||||
struct FuncTask : public Task<bool> {
|
||||
std::function<void()> func;
|
||||
};
|
||||
class FuncTaskProcessor;
|
||||
|
||||
std::vector<sp<FuncTask>> mFrameFences;
|
||||
sp<TaskProcessor<bool>> mFrameWorkProcessor;
|
||||
std::vector<std::future<void>> mFrameFences;
|
||||
std::unique_ptr<IRenderPipeline> mRenderPipeline;
|
||||
|
||||
std::vector<std::function<void(int64_t)>> mFrameCompleteCallbacks;
|
||||
|
||||
@@ -75,7 +75,6 @@ public:
|
||||
virtual void renderLayers(const LightGeometry& lightGeometry,
|
||||
LayerUpdateQueue* layerUpdateQueue, bool opaque,
|
||||
const LightInfo& lightInfo) = 0;
|
||||
virtual TaskManager* getTaskManager() = 0;
|
||||
virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
|
||||
ErrorHandler* errorHandler) = 0;
|
||||
virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "renderthread/RenderThread.h"
|
||||
#include "utils/Macros.h"
|
||||
#include "utils/TimeUtils.h"
|
||||
#include "utils/TraceUtils.h"
|
||||
|
||||
#include <ui/GraphicBuffer.h>
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "utils/FatVector.h"
|
||||
#include "utils/TimeUtils.h"
|
||||
#include "utils/TraceUtils.h"
|
||||
|
||||
#ifdef HWUI_GLES_WRAP_ENABLED
|
||||
#include "debug/GlesDriver.h"
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "RenderThread.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "utils/FatVector.h"
|
||||
#include "utils/TraceUtils.h"
|
||||
|
||||
#include <GrBackendSemaphore.h>
|
||||
#include <GrBackendSurface.h>
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "tests/common/TestContext.h"
|
||||
#include "tests/common/TestScene.h"
|
||||
#include "tests/common/scenes/TestSceneBase.h"
|
||||
#include "utils/TraceUtils.h"
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <gui/Surface.h>
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 <benchmark/benchmark.h>
|
||||
|
||||
#include "thread/Task.h"
|
||||
#include "thread/TaskManager.h"
|
||||
#include "thread/TaskProcessor.h"
|
||||
#include "thread/ThreadBase.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
using namespace android;
|
||||
using namespace android::uirenderer;
|
||||
|
||||
class TrivialTask : public Task<char> {};
|
||||
|
||||
class TrivialProcessor : public TaskProcessor<char> {
|
||||
public:
|
||||
explicit TrivialProcessor(TaskManager* manager) : TaskProcessor(manager) {}
|
||||
virtual ~TrivialProcessor() {}
|
||||
virtual void onProcess(const sp<Task<char>>& task) override {
|
||||
TrivialTask* t = static_cast<TrivialTask*>(task.get());
|
||||
t->setResult(reinterpret_cast<intptr_t>(t) % 16 == 0 ? 'a' : 'b');
|
||||
}
|
||||
};
|
||||
|
||||
class TestThread : public ThreadBase, public virtual RefBase {};
|
||||
|
||||
void BM_TaskManager_allocateTask(benchmark::State& state) {
|
||||
std::vector<sp<TrivialTask>> tasks;
|
||||
tasks.reserve(state.max_iterations);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
tasks.emplace_back(new TrivialTask);
|
||||
benchmark::DoNotOptimize(tasks.back());
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_TaskManager_allocateTask);
|
||||
|
||||
void BM_TaskManager_enqueueTask(benchmark::State& state) {
|
||||
TaskManager taskManager;
|
||||
sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
|
||||
std::vector<sp<TrivialTask>> tasks;
|
||||
tasks.reserve(state.max_iterations);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
tasks.emplace_back(new TrivialTask);
|
||||
benchmark::DoNotOptimize(tasks.back());
|
||||
processor->add(tasks.back());
|
||||
}
|
||||
|
||||
for (sp<TrivialTask>& task : tasks) {
|
||||
task->getResult();
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_TaskManager_enqueueTask);
|
||||
|
||||
void BM_TaskManager_enqueueRunDeleteTask(benchmark::State& state) {
|
||||
TaskManager taskManager;
|
||||
sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
|
||||
std::vector<sp<TrivialTask>> tasks;
|
||||
tasks.reserve(state.max_iterations);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
tasks.emplace_back(new TrivialTask);
|
||||
benchmark::DoNotOptimize(tasks.back());
|
||||
processor->add(tasks.back());
|
||||
}
|
||||
state.ResumeTiming();
|
||||
for (sp<TrivialTask>& task : tasks) {
|
||||
benchmark::DoNotOptimize(task->getResult());
|
||||
}
|
||||
tasks.clear();
|
||||
state.PauseTiming();
|
||||
}
|
||||
BENCHMARK(BM_TaskManager_enqueueRunDeleteTask);
|
||||
|
||||
void BM_Thread_enqueueTask(benchmark::State& state) {
|
||||
sp<TestThread> thread{new TestThread};
|
||||
thread->start();
|
||||
|
||||
atomic_int counter(0);
|
||||
int expected = 0;
|
||||
while (state.KeepRunning()) {
|
||||
expected++;
|
||||
thread->queue().post([&counter]() { counter++; });
|
||||
}
|
||||
thread->queue().runSync([]() {});
|
||||
|
||||
thread->requestExit();
|
||||
thread->join();
|
||||
if (counter != expected) {
|
||||
printf("Ran %d lambads, should have been %d\n", counter.load(), expected);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Thread_enqueueTask);
|
||||
|
||||
void BM_Thread_enqueueRunDeleteTask(benchmark::State& state) {
|
||||
sp<TestThread> thread{new TestThread};
|
||||
thread->start();
|
||||
std::vector<std::future<int>> tasks;
|
||||
tasks.reserve(state.max_iterations);
|
||||
|
||||
int expected = 0;
|
||||
while (state.KeepRunning()) {
|
||||
tasks.emplace_back(thread->queue().async([expected]() -> int { return expected + 1; }));
|
||||
expected++;
|
||||
}
|
||||
state.ResumeTiming();
|
||||
expected = 0;
|
||||
for (auto& future : tasks) {
|
||||
if (future.get() != ++expected) {
|
||||
printf("Mismatch expected %d vs. observed %d\n", expected, future.get());
|
||||
}
|
||||
}
|
||||
tasks.clear();
|
||||
state.PauseTiming();
|
||||
}
|
||||
BENCHMARK(BM_Thread_enqueueRunDeleteTask);
|
||||
138
libs/hwui/tests/unit/CommonPoolTests.cpp
Normal file
138
libs/hwui/tests/unit/CommonPoolTests.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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 <gtest/gtest.h>
|
||||
|
||||
#include "thread/CommonPool.h"
|
||||
|
||||
#include <array>
|
||||
#include <condition_variable>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
#include "unistd.h"
|
||||
|
||||
using namespace android;
|
||||
using namespace android::uirenderer;
|
||||
|
||||
TEST(CommonPool, post) {
|
||||
std::atomic_bool ran(false);
|
||||
CommonPool::post([&ran] { ran = true; });
|
||||
for (int i = 0; !ran && i < 1000; i++) {
|
||||
usleep(1);
|
||||
}
|
||||
EXPECT_TRUE(ran) << "Failed to flip atomic after 1 second";
|
||||
}
|
||||
|
||||
TEST(CommonPool, threadCount) {
|
||||
std::set<pid_t> threads;
|
||||
std::array<std::future<pid_t>, 64> futures;
|
||||
for (int i = 0; i < futures.size(); i++) {
|
||||
futures[i] = CommonPool::async([] {
|
||||
usleep(10);
|
||||
return gettid();
|
||||
});
|
||||
}
|
||||
for (auto& f : futures) {
|
||||
threads.insert(f.get());
|
||||
}
|
||||
EXPECT_EQ(threads.size(), CommonPool::THREAD_COUNT);
|
||||
EXPECT_EQ(0, threads.count(gettid()));
|
||||
}
|
||||
|
||||
TEST(CommonPool, singleThread) {
|
||||
std::mutex mutex;
|
||||
std::condition_variable fence;
|
||||
bool isProcessing = false;
|
||||
bool queuedSecond = false;
|
||||
|
||||
auto f1 = CommonPool::async([&] {
|
||||
{
|
||||
std::unique_lock lock{mutex};
|
||||
isProcessing = true;
|
||||
fence.notify_all();
|
||||
while (!queuedSecond) {
|
||||
fence.wait(lock);
|
||||
}
|
||||
}
|
||||
return gettid();
|
||||
});
|
||||
|
||||
{
|
||||
std::unique_lock lock{mutex};
|
||||
while (!isProcessing) {
|
||||
fence.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
auto f2 = CommonPool::async([] {
|
||||
return gettid();
|
||||
});
|
||||
|
||||
{
|
||||
std::unique_lock lock{mutex};
|
||||
queuedSecond = true;
|
||||
fence.notify_all();
|
||||
}
|
||||
|
||||
auto tid1 = f1.get();
|
||||
auto tid2 = f2.get();
|
||||
EXPECT_EQ(tid1, tid2);
|
||||
EXPECT_NE(gettid(), tid1);
|
||||
}
|
||||
|
||||
TEST(CommonPool, fullQueue) {
|
||||
std::mutex lock;
|
||||
std::condition_variable fence;
|
||||
bool signaled = false;
|
||||
static constexpr auto QUEUE_COUNT = CommonPool::THREAD_COUNT + CommonPool::QUEUE_SIZE + 10;
|
||||
std::atomic_int queuedCount{0};
|
||||
std::array<std::future<void>, QUEUE_COUNT> futures;
|
||||
|
||||
std::thread queueThread{[&] {
|
||||
for (int i = 0; i < QUEUE_COUNT; i++) {
|
||||
futures[i] = CommonPool::async([&] {
|
||||
std::unique_lock _lock{lock};
|
||||
while (!signaled) {
|
||||
fence.wait(_lock);
|
||||
}
|
||||
});
|
||||
queuedCount++;
|
||||
}
|
||||
}};
|
||||
|
||||
int previous;
|
||||
do {
|
||||
previous = queuedCount.load();
|
||||
usleep(10000);
|
||||
} while (previous != queuedCount.load());
|
||||
|
||||
EXPECT_GT(queuedCount.load(), CommonPool::QUEUE_SIZE);
|
||||
EXPECT_LT(queuedCount.load(), QUEUE_COUNT);
|
||||
|
||||
{
|
||||
std::unique_lock _lock{lock};
|
||||
signaled = true;
|
||||
fence.notify_all();
|
||||
}
|
||||
|
||||
queueThread.join();
|
||||
EXPECT_EQ(queuedCount.load(), QUEUE_COUNT);
|
||||
|
||||
// Ensure all our tasks are finished before return as they have references to the stack
|
||||
for (auto& f : futures) {
|
||||
f.get();
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,6 @@
|
||||
#include "debug/NullGlesDriver.h"
|
||||
#include "hwui/Typeface.h"
|
||||
#include "tests/common/LeakChecker.h"
|
||||
#include "thread/Task.h"
|
||||
#include "thread/TaskManager.h"
|
||||
#include "thread/TaskProcessor.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 ANDROID_HWUI_BARRIER_H
|
||||
#define ANDROID_HWUI_BARRIER_H
|
||||
|
||||
#include <utils/Condition.h>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class Barrier {
|
||||
public:
|
||||
explicit Barrier(Condition::WakeUpType type = Condition::WAKE_UP_ALL)
|
||||
: mType(type), mOpened(false) {}
|
||||
~Barrier() {}
|
||||
|
||||
void open() {
|
||||
Mutex::Autolock l(mLock);
|
||||
mOpened = true;
|
||||
mCondition.signal(mType);
|
||||
}
|
||||
|
||||
void wait() const {
|
||||
Mutex::Autolock l(mLock);
|
||||
while (!mOpened) {
|
||||
mCondition.wait(mLock);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Condition::WakeUpType mType;
|
||||
volatile bool mOpened;
|
||||
mutable Mutex mLock;
|
||||
mutable Condition mCondition;
|
||||
};
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_BARRIER_H
|
||||
90
libs/hwui/thread/CommonPool.cpp
Normal file
90
libs/hwui/thread/CommonPool.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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;
|
||||
// Create 2 workers
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
std::thread worker([pool, i] {
|
||||
{
|
||||
std::array<char, 20> name{"hwuiTask"};
|
||||
snprintf(name.data(), name.size(), "hwuiTask%d", i);
|
||||
auto self = pthread_self();
|
||||
pthread_setname_np(self, name.data());
|
||||
setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND);
|
||||
auto startHook = renderthread::RenderThread::getOnStartHook();
|
||||
if (startHook) {
|
||||
startHook(name.data());
|
||||
}
|
||||
}
|
||||
pool->workerLoop();
|
||||
});
|
||||
worker.detach();
|
||||
}
|
||||
}
|
||||
|
||||
void CommonPool::post(Task&& task) {
|
||||
static CommonPool pool;
|
||||
pool.enqueue(std::move(task));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
115
libs/hwui/thread/CommonPool.h
Normal file
115
libs/hwui/thread/CommonPool.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FRAMEWORKS_BASE_COMMONPOOL_H
|
||||
#define FRAMEWORKS_BASE_COMMONPOOL_H
|
||||
|
||||
#include "utils/Macros.h"
|
||||
|
||||
#include <log/log.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
template <class T, int SIZE>
|
||||
class ArrayQueue {
|
||||
PREVENT_COPY_AND_ASSIGN(ArrayQueue);
|
||||
static_assert(SIZE > 0, "Size must be positive");
|
||||
|
||||
public:
|
||||
ArrayQueue() = default;
|
||||
~ArrayQueue() = default;
|
||||
|
||||
constexpr size_t capacity() const { return SIZE; }
|
||||
constexpr bool hasWork() const { return mHead != mTail; }
|
||||
constexpr bool hasSpace() const { return ((mHead + 1) % SIZE) != mTail; }
|
||||
constexpr int size() const {
|
||||
if (mHead > mTail) {
|
||||
return mHead - mTail;
|
||||
} else {
|
||||
return mTail - mHead + SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void push(T&& t) {
|
||||
int newHead = (mHead + 1) % SIZE;
|
||||
LOG_ALWAYS_FATAL_IF(newHead == mTail, "no space");
|
||||
|
||||
mBuffer[mHead] = std::move(t);
|
||||
mHead = newHead;
|
||||
}
|
||||
|
||||
constexpr T&& pop() {
|
||||
LOG_ALWAYS_FATAL_IF(mTail == mHead, "empty");
|
||||
int index = mTail;
|
||||
mTail = (mTail + 1) % SIZE;
|
||||
return std::move(mBuffer[index]);
|
||||
}
|
||||
|
||||
private:
|
||||
T mBuffer[SIZE];
|
||||
int mHead = 0;
|
||||
int mTail = 0;
|
||||
};
|
||||
|
||||
class CommonPool {
|
||||
PREVENT_COPY_AND_ASSIGN(CommonPool);
|
||||
|
||||
public:
|
||||
using Task = std::function<void()>;
|
||||
static constexpr auto THREAD_COUNT = 2;
|
||||
static constexpr auto QUEUE_SIZE = 128;
|
||||
|
||||
static void post(Task&& func);
|
||||
|
||||
template <class F>
|
||||
static auto async(F&& func) -> std::future<decltype(func())> {
|
||||
typedef std::packaged_task<decltype(func())()> task_t;
|
||||
auto task = std::make_shared<task_t>(std::forward<F>(func));
|
||||
post([task]() { std::invoke(*task); });
|
||||
return task->get_future();
|
||||
}
|
||||
|
||||
template <class F>
|
||||
static auto runSync(F&& func) -> decltype(func()) {
|
||||
std::packaged_task<decltype(func())()> task{std::forward<F>(func)};
|
||||
post([&task]() { std::invoke(task); });
|
||||
return task.get_future().get();
|
||||
};
|
||||
|
||||
private:
|
||||
CommonPool();
|
||||
~CommonPool() {}
|
||||
|
||||
void enqueue(Task&&);
|
||||
|
||||
void workerLoop();
|
||||
|
||||
std::mutex mLock;
|
||||
std::condition_variable mCondition;
|
||||
int mWaitingThreads = 0;
|
||||
ArrayQueue<Task, QUEUE_SIZE> mWorkQueue;
|
||||
};
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
#endif // FRAMEWORKS_BASE_COMMONPOOL_H
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 ANDROID_HWUI_FUTURE_H
|
||||
#define ANDROID_HWUI_FUTURE_H
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
#include "Barrier.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
template <typename T>
|
||||
class Future : public LightRefBase<Future<T> > {
|
||||
public:
|
||||
explicit Future(Condition::WakeUpType type = Condition::WAKE_UP_ONE)
|
||||
: mBarrier(type), mResult() {}
|
||||
~Future() {}
|
||||
|
||||
/**
|
||||
* Returns the result of this future, blocking if
|
||||
* the result is not available yet.
|
||||
*/
|
||||
T get() const {
|
||||
mBarrier.wait();
|
||||
return mResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method must be called only once.
|
||||
*/
|
||||
void produce(T result) {
|
||||
mResult = result;
|
||||
mBarrier.open();
|
||||
}
|
||||
|
||||
private:
|
||||
Barrier mBarrier;
|
||||
T mResult;
|
||||
};
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_FUTURE_H
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 ANDROID_HWUI_SIGNAL_H
|
||||
#define ANDROID_HWUI_SIGNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class Signal {
|
||||
public:
|
||||
explicit Signal(Condition::WakeUpType type = Condition::WAKE_UP_ALL)
|
||||
: mType(type), mSignaled(false) {}
|
||||
~Signal() {}
|
||||
|
||||
void signal() {
|
||||
{
|
||||
Mutex::Autolock l(mLock);
|
||||
mSignaled = true;
|
||||
}
|
||||
mCondition.signal(mType);
|
||||
}
|
||||
|
||||
void wait() {
|
||||
Mutex::Autolock l(mLock);
|
||||
while (!mSignaled) {
|
||||
mCondition.wait(mLock);
|
||||
}
|
||||
mSignaled = false;
|
||||
}
|
||||
|
||||
private:
|
||||
Condition::WakeUpType mType;
|
||||
volatile bool mSignaled;
|
||||
mutable Mutex mLock;
|
||||
mutable Condition mCondition;
|
||||
};
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_SIGNAL_H
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 ANDROID_HWUI_TASK_H
|
||||
#define ANDROID_HWUI_TASK_H
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include "Future.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class TaskBase : public RefBase {
|
||||
public:
|
||||
TaskBase() {}
|
||||
virtual ~TaskBase() {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Task : public TaskBase {
|
||||
public:
|
||||
Task() : mFuture(new Future<T>()) {}
|
||||
virtual ~Task() {}
|
||||
|
||||
T getResult() const { return mFuture->get(); }
|
||||
|
||||
void setResult(T result) { mFuture->produce(result); }
|
||||
|
||||
protected:
|
||||
const sp<Future<T> >& future() const { return mFuture; }
|
||||
|
||||
private:
|
||||
sp<Future<T> > mFuture;
|
||||
};
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_TASK_H
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 <sys/resource.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#include "Task.h"
|
||||
#include "TaskManager.h"
|
||||
#include "TaskProcessor.h"
|
||||
#include "utils/MathUtils.h"
|
||||
#include "renderthread/RenderThread.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Manager
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TaskManager::TaskManager() {
|
||||
// Get the number of available CPUs. This value does not change over time.
|
||||
int cpuCount = sysconf(_SC_NPROCESSORS_CONF);
|
||||
|
||||
// Really no point in making more than 2 of these worker threads, but
|
||||
// we do want to limit ourselves to 1 worker thread on dual-core devices.
|
||||
int workerCount = cpuCount > 2 ? 2 : 1;
|
||||
for (int i = 0; i < workerCount; i++) {
|
||||
String8 name;
|
||||
name.appendFormat("hwuiTask%d", i + 1);
|
||||
mThreads.push_back(new WorkerThread(name));
|
||||
}
|
||||
}
|
||||
|
||||
TaskManager::~TaskManager() {
|
||||
for (size_t i = 0; i < mThreads.size(); i++) {
|
||||
mThreads[i]->exit();
|
||||
}
|
||||
}
|
||||
|
||||
bool TaskManager::canRunTasks() const {
|
||||
return mThreads.size() > 0;
|
||||
}
|
||||
|
||||
void TaskManager::stop() {
|
||||
for (size_t i = 0; i < mThreads.size(); i++) {
|
||||
mThreads[i]->exit();
|
||||
}
|
||||
}
|
||||
|
||||
bool TaskManager::addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor) {
|
||||
if (mThreads.size() > 0) {
|
||||
TaskWrapper wrapper(task, processor);
|
||||
|
||||
size_t minQueueSize = INT_MAX;
|
||||
sp<WorkerThread> thread;
|
||||
|
||||
for (size_t i = 0; i < mThreads.size(); i++) {
|
||||
if (mThreads[i]->getTaskCount() < minQueueSize) {
|
||||
thread = mThreads[i];
|
||||
minQueueSize = mThreads[i]->getTaskCount();
|
||||
}
|
||||
}
|
||||
|
||||
return thread->addTask(wrapper);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Thread
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
status_t TaskManager::WorkerThread::readyToRun() {
|
||||
setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND);
|
||||
auto onStartHook = renderthread::RenderThread::getOnStartHook();
|
||||
if (onStartHook) {
|
||||
onStartHook(mName.c_str());
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool TaskManager::WorkerThread::threadLoop() {
|
||||
mSignal.wait();
|
||||
std::vector<TaskWrapper> tasks;
|
||||
{
|
||||
Mutex::Autolock l(mLock);
|
||||
tasks.swap(mTasks);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < tasks.size(); i++) {
|
||||
const TaskWrapper& task = tasks[i];
|
||||
task.mProcessor->process(task.mTask);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TaskManager::WorkerThread::addTask(const TaskWrapper& task) {
|
||||
if (!isRunning()) {
|
||||
run(mName.string(), PRIORITY_DEFAULT);
|
||||
} else if (exitPending()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Autolock l(mLock);
|
||||
mTasks.push_back(task);
|
||||
}
|
||||
mSignal.signal();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t TaskManager::WorkerThread::getTaskCount() const {
|
||||
Mutex::Autolock l(mLock);
|
||||
return mTasks.size();
|
||||
}
|
||||
|
||||
void TaskManager::WorkerThread::exit() {
|
||||
requestExit();
|
||||
mSignal.signal();
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 ANDROID_HWUI_TASK_MANAGER_H
|
||||
#define ANDROID_HWUI_TASK_MANAGER_H
|
||||
|
||||
#include <utils/Mutex.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/Thread.h>
|
||||
|
||||
#include "Signal.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
template <typename T>
|
||||
class Task;
|
||||
class TaskBase;
|
||||
|
||||
template <typename T>
|
||||
class TaskProcessor;
|
||||
class TaskProcessorBase;
|
||||
|
||||
class TaskManager {
|
||||
public:
|
||||
TaskManager();
|
||||
~TaskManager();
|
||||
|
||||
/**
|
||||
* Returns true if this task manager can run tasks,
|
||||
* false otherwise. This method will typically return
|
||||
* false on a single CPU core device.
|
||||
*/
|
||||
bool canRunTasks() const;
|
||||
|
||||
/**
|
||||
* Stops all allocated threads. Adding tasks will start
|
||||
* the threads again as necessary.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
friend class TaskProcessor;
|
||||
|
||||
template <typename T>
|
||||
bool addTask(const sp<Task<T> >& task, const sp<TaskProcessor<T> >& processor) {
|
||||
return addTaskBase(sp<TaskBase>(task), sp<TaskProcessorBase>(processor));
|
||||
}
|
||||
|
||||
bool addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor);
|
||||
|
||||
struct TaskWrapper {
|
||||
TaskWrapper() : mTask(), mProcessor() {}
|
||||
|
||||
TaskWrapper(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor)
|
||||
: mTask(task), mProcessor(processor) {}
|
||||
|
||||
sp<TaskBase> mTask;
|
||||
sp<TaskProcessorBase> mProcessor;
|
||||
};
|
||||
|
||||
class WorkerThread : public Thread {
|
||||
public:
|
||||
explicit WorkerThread(const String8& name)
|
||||
: Thread(false), mSignal(Condition::WAKE_UP_ONE), mName(name) {}
|
||||
|
||||
bool addTask(const TaskWrapper& task);
|
||||
size_t getTaskCount() const;
|
||||
void exit();
|
||||
|
||||
private:
|
||||
virtual status_t readyToRun() override;
|
||||
virtual bool threadLoop() override;
|
||||
|
||||
// Lock for the list of tasks
|
||||
mutable Mutex mLock;
|
||||
std::vector<TaskWrapper> mTasks;
|
||||
|
||||
// Signal used to wake up the thread when a new
|
||||
// task is available in the list
|
||||
mutable Signal mSignal;
|
||||
|
||||
const String8 mName;
|
||||
};
|
||||
|
||||
std::vector<sp<WorkerThread> > mThreads;
|
||||
};
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_TASK_MANAGER_H
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 ANDROID_HWUI_TASK_PROCESSOR_H
|
||||
#define ANDROID_HWUI_TASK_PROCESSOR_H
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
#include "Task.h"
|
||||
#include "TaskManager.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class TaskProcessorBase : public RefBase {
|
||||
public:
|
||||
TaskProcessorBase() {}
|
||||
virtual ~TaskProcessorBase(){};
|
||||
|
||||
virtual void process(const sp<TaskBase>& task) = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TaskProcessor : public TaskProcessorBase {
|
||||
public:
|
||||
explicit TaskProcessor(TaskManager* manager) : mManager(manager) {}
|
||||
virtual ~TaskProcessor() {}
|
||||
|
||||
void add(const sp<Task<T> >& task) {
|
||||
if (!addImpl(task)) {
|
||||
// fall back to immediate execution
|
||||
process(task);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void onProcess(const sp<Task<T> >& task) = 0;
|
||||
|
||||
private:
|
||||
bool addImpl(const sp<Task<T> >& task);
|
||||
|
||||
virtual void process(const sp<TaskBase>& task) override {
|
||||
sp<Task<T> > realTask = static_cast<Task<T>*>(task.get());
|
||||
// This is the right way to do it but sp<> doesn't play nice
|
||||
// sp<Task<T> > realTask = static_cast<sp<Task<T> > >(task);
|
||||
onProcess(realTask);
|
||||
}
|
||||
|
||||
TaskManager* mManager;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool TaskProcessor<T>::addImpl(const sp<Task<T> >& task) {
|
||||
if (mManager) {
|
||||
sp<TaskProcessor<T> > self(this);
|
||||
return mManager->addTask(task, self);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_TASK_PROCESSOR_H
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace android::uirenderer {
|
||||
|
||||
Reference in New Issue
Block a user