blob: bffdeca4db54996d9f9d730e0d79e56d75d6f655 [file] [log] [blame]
John Reck322b8ab2019-03-14 13:15:28 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gtest/gtest.h>
18
19#include "thread/CommonPool.h"
20
21#include <array>
22#include <condition_variable>
23#include <set>
24#include <thread>
25#include "unistd.h"
26
27using namespace android;
28using namespace android::uirenderer;
29
30TEST(CommonPool, post) {
31 std::atomic_bool ran(false);
32 CommonPool::post([&ran] { ran = true; });
33 for (int i = 0; !ran && i < 1000; i++) {
34 usleep(1);
35 }
36 EXPECT_TRUE(ran) << "Failed to flip atomic after 1 second";
37}
38
John Reckc24e8e62019-04-23 09:23:52 -070039// test currently relies on timings, which
40// makes it flaky. Disable for now
41TEST(DISABLED_CommonPool, threadCount) {
John Reck322b8ab2019-03-14 13:15:28 -070042 std::set<pid_t> threads;
43 std::array<std::future<pid_t>, 64> futures;
44 for (int i = 0; i < futures.size(); i++) {
45 futures[i] = CommonPool::async([] {
46 usleep(10);
47 return gettid();
48 });
49 }
50 for (auto& f : futures) {
51 threads.insert(f.get());
52 }
53 EXPECT_EQ(threads.size(), CommonPool::THREAD_COUNT);
54 EXPECT_EQ(0, threads.count(gettid()));
55}
56
John Reck68526062020-11-24 15:27:54 -050057// Disabled since this is flaky. This isn't a necessarily useful functional test, so being
58// disabled isn't that significant. However it may be good to resurrect this somehow.
59TEST(CommonPool, DISABLED_singleThread) {
John Reck322b8ab2019-03-14 13:15:28 -070060 std::mutex mutex;
61 std::condition_variable fence;
62 bool isProcessing = false;
63 bool queuedSecond = false;
64
65 auto f1 = CommonPool::async([&] {
66 {
67 std::unique_lock lock{mutex};
68 isProcessing = true;
69 fence.notify_all();
70 while (!queuedSecond) {
71 fence.wait(lock);
72 }
73 }
74 return gettid();
75 });
76
77 {
78 std::unique_lock lock{mutex};
79 while (!isProcessing) {
80 fence.wait(lock);
81 }
82 }
83
84 auto f2 = CommonPool::async([] {
85 return gettid();
86 });
87
88 {
89 std::unique_lock lock{mutex};
90 queuedSecond = true;
91 fence.notify_all();
92 }
93
94 auto tid1 = f1.get();
95 auto tid2 = f2.get();
96 EXPECT_EQ(tid1, tid2);
97 EXPECT_NE(gettid(), tid1);
98}
99
John Reckc24e8e62019-04-23 09:23:52 -0700100// Test currently relies on timings
101// which makes it flaky, disable for now
102TEST(DISABLED_CommonPool, fullQueue) {
John Reck322b8ab2019-03-14 13:15:28 -0700103 std::mutex lock;
104 std::condition_variable fence;
105 bool signaled = false;
106 static constexpr auto QUEUE_COUNT = CommonPool::THREAD_COUNT + CommonPool::QUEUE_SIZE + 10;
107 std::atomic_int queuedCount{0};
108 std::array<std::future<void>, QUEUE_COUNT> futures;
109
110 std::thread queueThread{[&] {
111 for (int i = 0; i < QUEUE_COUNT; i++) {
112 futures[i] = CommonPool::async([&] {
113 std::unique_lock _lock{lock};
114 while (!signaled) {
115 fence.wait(_lock);
116 }
117 });
118 queuedCount++;
119 }
120 }};
121
122 int previous;
123 do {
124 previous = queuedCount.load();
125 usleep(10000);
126 } while (previous != queuedCount.load());
127
128 EXPECT_GT(queuedCount.load(), CommonPool::QUEUE_SIZE);
129 EXPECT_LT(queuedCount.load(), QUEUE_COUNT);
130
131 {
132 std::unique_lock _lock{lock};
133 signaled = true;
134 fence.notify_all();
135 }
136
137 queueThread.join();
138 EXPECT_EQ(queuedCount.load(), QUEUE_COUNT);
139
140 // Ensure all our tasks are finished before return as they have references to the stack
141 for (auto& f : futures) {
142 f.get();
143 }
John Reckcfd929d2019-04-08 11:28:15 -0700144}
145
146class ObjectTracker {
147 static std::atomic_int sGlobalCount;
148
149public:
150 ObjectTracker() {
151 sGlobalCount++;
152 }
153 ObjectTracker(const ObjectTracker&) {
154 sGlobalCount++;
155 }
156 ObjectTracker(ObjectTracker&&) {
157 sGlobalCount++;
158 }
159 ~ObjectTracker() {
160 sGlobalCount--;
161 }
162
163 static int count() { return sGlobalCount.load(); }
164};
165
166std::atomic_int ObjectTracker::sGlobalCount{0};
167
168TEST(CommonPool, asyncLifecycleCheck) {
169 ASSERT_EQ(0, ObjectTracker::count());
170 {
171 ObjectTracker obj;
172 ASSERT_EQ(1, ObjectTracker::count());
173 EXPECT_LT(1, CommonPool::async([obj] { return ObjectTracker::count(); }).get());
174 }
175 CommonPool::waitForIdle();
176 ASSERT_EQ(0, ObjectTracker::count());
177}
178
179TEST(CommonPool, syncLifecycleCheck) {
180 ASSERT_EQ(0, ObjectTracker::count());
181 {
182 ObjectTracker obj;
183 ASSERT_EQ(1, ObjectTracker::count());
184 EXPECT_LT(1, CommonPool::runSync([obj] { return ObjectTracker::count(); }));
185 }
186 CommonPool::waitForIdle();
187 ASSERT_EQ(0, ObjectTracker::count());
John Reckc24e8e62019-04-23 09:23:52 -0700188}