Remove old TaskManager system
Replace it with a newer, fancier, WorkQueue-inspired
one that's just a global common thread pool.
Test: hwuiunit passes
Change-Id: Ib5d03104a08bbac9a4ec67a1bfc0db2b35d6700f
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 0e61899e..b45dbc8 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 4153bae..0000000
--- 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 0000000..c564ed6
--- /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 63d1540..83d888c 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>