diff options
27 files changed, 375 insertions, 800 deletions
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 9f9fbf9eb26d..c4c16ee0ef9b 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -31,6 +31,7 @@ #include <renderthread/CanvasContext.h> #include <TreeInfo.h> #include <hwui/Paint.h> +#include <utils/TraceUtils.h> #include "core_jni_helpers.h" diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 4f1b2a4fcbf8..ebba4cb79dfb 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -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", ], } diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp index fe633e96b9d7..fb60a966c48f 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/Readback.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; diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index a00a36f93501..721a115c1381 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -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--; diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 7381e0417a2d..41d864653b67 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -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). diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 6c04232ab7f5..8b02c11911ca 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -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); diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h index 66f04f1ba266..b0286e8cde25 100644 --- a/libs/hwui/renderthread/CacheManager.h +++ b/libs/hwui/renderthread/CacheManager.h @@ -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 */ diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index f5b4d9359ee9..baa41c1ec698 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -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() { diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 4da0eac85bb0..abca34225f98 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -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; diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index 2cfc8df38297..0502eb88b6a5 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -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; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 34f76d9b3579..1bcb819509af 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -31,6 +31,7 @@ #include "renderthread/RenderThread.h" #include "utils/Macros.h" #include "utils/TimeUtils.h" +#include "utils/TraceUtils.h" #include <ui/GraphicBuffer.h> diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index c784d64f820c..def805adeeea 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -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" diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 6dacc7a0ea07..9916da5d9f10 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -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> diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp index 0e61899ed58b..b45dbc8b832b 100644 --- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp +++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp @@ -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> diff --git a/libs/hwui/tests/microbench/TaskManagerBench.cpp b/libs/hwui/tests/microbench/TaskManagerBench.cpp deleted file mode 100644 index 4153baec22b5..000000000000 --- a/libs/hwui/tests/microbench/TaskManagerBench.cpp +++ /dev/null @@ -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);
\ No newline at end of file diff --git a/libs/hwui/tests/unit/CommonPoolTests.cpp b/libs/hwui/tests/unit/CommonPoolTests.cpp new file mode 100644 index 000000000000..c564ed632786 --- /dev/null +++ b/libs/hwui/tests/unit/CommonPoolTests.cpp @@ -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(); + } +}
\ No newline at end of file diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp index 63d15403b607..83d888c310f0 100644 --- a/libs/hwui/tests/unit/main.cpp +++ b/libs/hwui/tests/unit/main.cpp @@ -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> diff --git a/libs/hwui/thread/Barrier.h b/libs/hwui/thread/Barrier.h deleted file mode 100644 index bb750ca0fa88..000000000000 --- a/libs/hwui/thread/Barrier.h +++ /dev/null @@ -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 diff --git a/libs/hwui/thread/CommonPool.cpp b/libs/hwui/thread/CommonPool.cpp new file mode 100644 index 000000000000..7f94a152cf8d --- /dev/null +++ b/libs/hwui/thread/CommonPool.cpp @@ -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
\ No newline at end of file diff --git a/libs/hwui/thread/CommonPool.h b/libs/hwui/thread/CommonPool.h new file mode 100644 index 000000000000..aef2990d6343 --- /dev/null +++ b/libs/hwui/thread/CommonPool.h @@ -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 diff --git a/libs/hwui/thread/Future.h b/libs/hwui/thread/Future.h deleted file mode 100644 index df53348e58fb..000000000000 --- a/libs/hwui/thread/Future.h +++ /dev/null @@ -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 diff --git a/libs/hwui/thread/Signal.h b/libs/hwui/thread/Signal.h deleted file mode 100644 index 6d33ac473ac4..000000000000 --- a/libs/hwui/thread/Signal.h +++ /dev/null @@ -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 diff --git a/libs/hwui/thread/Task.h b/libs/hwui/thread/Task.h deleted file mode 100644 index 228ce19a2fd5..000000000000 --- a/libs/hwui/thread/Task.h +++ /dev/null @@ -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 diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp deleted file mode 100644 index de10ff1824ee..000000000000 --- a/libs/hwui/thread/TaskManager.cpp +++ /dev/null @@ -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 diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h deleted file mode 100644 index 6c67222a12d7..000000000000 --- a/libs/hwui/thread/TaskManager.h +++ /dev/null @@ -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 diff --git a/libs/hwui/thread/TaskProcessor.h b/libs/hwui/thread/TaskProcessor.h deleted file mode 100644 index 8117ae6409c4..000000000000 --- a/libs/hwui/thread/TaskProcessor.h +++ /dev/null @@ -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 diff --git a/libs/hwui/thread/WorkQueue.h b/libs/hwui/thread/WorkQueue.h index 7a6e638e0568..42f8503fd000 100644 --- a/libs/hwui/thread/WorkQueue.h +++ b/libs/hwui/thread/WorkQueue.h @@ -26,7 +26,6 @@ #include <functional> #include <future> #include <mutex> -#include <variant> #include <vector> namespace android::uirenderer { |