blob: d7842002ee23b5b61a37867f8f4def9ff195f3c0 [file] [log] [blame]
Mathieu Chartier0e4627e2012-10-23 16:13:36 -07001/*
2 * Copyright (C) 2012 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
Brian Carlstroma1ce1fe2014-02-24 23:23:58 -080017#include "thread_pool.h"
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070018
19#include <string>
20
David Sehrc431b9d2018-03-02 12:01:51 -080021#include "base/atomic.h"
Brian Carlstroma1ce1fe2014-02-24 23:23:58 -080022#include "common_runtime_test.h"
Andreas Gampeb15de0c2017-01-24 13:12:19 -080023#include "scoped_thread_state_change-inl.h"
Ian Rogerse63db272014-07-15 15:36:11 -070024#include "thread-inl.h"
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070025
26namespace art {
27
Mathieu Chartier02b6a782012-10-26 13:51:26 -070028class CountTask : public Task {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070029 public:
Brian Carlstrom93ba8932013-07-17 21:31:49 -070030 explicit CountTask(AtomicInteger* count) : count_(count), verbose_(false) {}
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070031
Ian Rogersd914eb22013-04-18 16:11:15 -070032 void Run(Thread* self) {
33 if (verbose_) {
34 LOG(INFO) << "Running: " << *self;
35 }
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070036 // Simulate doing some work.
37 usleep(100);
38 // Increment the counter which keeps track of work completed.
39 ++*count_;
Mathieu Chartier02b6a782012-10-26 13:51:26 -070040 }
41
42 void Finalize() {
Ian Rogersd914eb22013-04-18 16:11:15 -070043 if (verbose_) {
44 LOG(INFO) << "Finalizing: " << *Thread::Current();
45 }
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070046 delete this;
47 }
48
49 private:
50 AtomicInteger* const count_;
Ian Rogersd914eb22013-04-18 16:11:15 -070051 const bool verbose_;
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070052};
53
Brian Carlstroma1ce1fe2014-02-24 23:23:58 -080054class ThreadPoolTest : public CommonRuntimeTest {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070055 public:
56 static int32_t num_threads;
57};
58
59int32_t ThreadPoolTest::num_threads = 4;
60
61// Check that the thread pool actually runs tasks that you assign it.
62TEST_F(ThreadPoolTest, CheckRun) {
63 Thread* self = Thread::Current();
Mathieu Chartierbcd5e9d2013-11-13 14:33:28 -080064 ThreadPool thread_pool("Thread pool test thread pool", num_threads);
Brian Carlstrom93ba8932013-07-17 21:31:49 -070065 AtomicInteger count(0);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070066 static const int32_t num_tasks = num_threads * 4;
67 for (int32_t i = 0; i < num_tasks; ++i) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -070068 thread_pool.AddTask(self, new CountTask(&count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070069 }
70 thread_pool.StartWorkers(self);
71 // Wait for tasks to complete.
Ian Rogers1d54e732013-05-02 21:10:01 -070072 thread_pool.Wait(self, true, false);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070073 // Make sure that we finished all the work.
Orion Hodson88591fe2018-03-06 13:35:43 +000074 EXPECT_EQ(num_tasks, count.load(std::memory_order_seq_cst));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070075}
76
77TEST_F(ThreadPoolTest, StopStart) {
78 Thread* self = Thread::Current();
Mathieu Chartierbcd5e9d2013-11-13 14:33:28 -080079 ThreadPool thread_pool("Thread pool test thread pool", num_threads);
Brian Carlstrom93ba8932013-07-17 21:31:49 -070080 AtomicInteger count(0);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070081 static const int32_t num_tasks = num_threads * 4;
82 for (int32_t i = 0; i < num_tasks; ++i) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -070083 thread_pool.AddTask(self, new CountTask(&count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070084 }
85 usleep(200);
86 // Check that no threads started prematurely.
Orion Hodson88591fe2018-03-06 13:35:43 +000087 EXPECT_EQ(0, count.load(std::memory_order_seq_cst));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070088 // Signal the threads to start processing tasks.
89 thread_pool.StartWorkers(self);
90 usleep(200);
91 thread_pool.StopWorkers(self);
Brian Carlstrom93ba8932013-07-17 21:31:49 -070092 AtomicInteger bad_count(0);
Mathieu Chartier02b6a782012-10-26 13:51:26 -070093 thread_pool.AddTask(self, new CountTask(&bad_count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070094 usleep(200);
95 // Ensure that the task added after the workers were stopped doesn't get run.
Orion Hodson88591fe2018-03-06 13:35:43 +000096 EXPECT_EQ(0, bad_count.load(std::memory_order_seq_cst));
Ian Rogersd914eb22013-04-18 16:11:15 -070097 // Allow tasks to finish up and delete themselves.
98 thread_pool.StartWorkers(self);
Mathieu Chartier7947b542014-11-09 12:30:50 -080099 thread_pool.Wait(self, false, false);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700100}
101
Andreas Gampe6f3a70f2016-11-16 13:58:05 -0800102TEST_F(ThreadPoolTest, StopWait) {
103 Thread* self = Thread::Current();
104 ThreadPool thread_pool("Thread pool test thread pool", num_threads);
105
106 AtomicInteger count(0);
107 static const int32_t num_tasks = num_threads * 100;
108 for (int32_t i = 0; i < num_tasks; ++i) {
109 thread_pool.AddTask(self, new CountTask(&count));
110 }
111
112 // Signal the threads to start processing tasks.
113 thread_pool.StartWorkers(self);
114 usleep(200);
115 thread_pool.StopWorkers(self);
116
117 thread_pool.Wait(self, false, false); // We should not deadlock here.
Andreas Gampe1013bde2016-11-18 15:06:21 -0800118
119 // Drain the task list. Note: we have to restart here, as no tasks will be finished when
120 // the pool is stopped.
121 thread_pool.StartWorkers(self);
122 thread_pool.Wait(self, /* do_work */ true, false);
Andreas Gampe6f3a70f2016-11-16 13:58:05 -0800123}
124
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700125class TreeTask : public Task {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700126 public:
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700127 TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth)
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700128 : thread_pool_(thread_pool),
129 count_(count),
Brian Carlstrom0cd7ec22013-07-17 23:40:20 -0700130 depth_(depth) {}
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700131
132 void Run(Thread* self) {
133 if (depth_ > 1) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700134 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1));
135 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700136 }
137 // Increment the counter which keeps track of work completed.
138 ++*count_;
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700139 }
140
141 void Finalize() {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700142 delete this;
143 }
144
145 private:
146 ThreadPool* const thread_pool_;
147 AtomicInteger* const count_;
148 const int depth_;
149};
150
151// Test that adding new tasks from within a task works.
152TEST_F(ThreadPoolTest, RecursiveTest) {
153 Thread* self = Thread::Current();
Mathieu Chartierbcd5e9d2013-11-13 14:33:28 -0800154 ThreadPool thread_pool("Thread pool test thread pool", num_threads);
Brian Carlstrom93ba8932013-07-17 21:31:49 -0700155 AtomicInteger count(0);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700156 static const int depth = 8;
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700157 thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700158 thread_pool.StartWorkers(self);
Ian Rogers1d54e732013-05-02 21:10:01 -0700159 thread_pool.Wait(self, true, false);
Orion Hodson88591fe2018-03-06 13:35:43 +0000160 EXPECT_EQ((1 << depth) - 1, count.load(std::memory_order_seq_cst));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700161}
162
Andreas Gampeb15de0c2017-01-24 13:12:19 -0800163class PeerTask : public Task {
164 public:
165 PeerTask() {}
166
167 void Run(Thread* self) {
168 ScopedObjectAccess soa(self);
169 CHECK(self->GetPeer() != nullptr);
170 }
171
172 void Finalize() {
173 delete this;
174 }
175};
176
177class NoPeerTask : public Task {
178 public:
179 NoPeerTask() {}
180
181 void Run(Thread* self) {
182 ScopedObjectAccess soa(self);
183 CHECK(self->GetPeer() == nullptr);
184 }
185
186 void Finalize() {
187 delete this;
188 }
189};
190
191// Tests for create_peer functionality.
192TEST_F(ThreadPoolTest, PeerTest) {
193 Thread* self = Thread::Current();
194 {
195 ThreadPool thread_pool("Thread pool test thread pool", 1);
196 thread_pool.AddTask(self, new NoPeerTask());
197 thread_pool.StartWorkers(self);
198 thread_pool.Wait(self, false, false);
199 }
200
201 {
202 // To create peers, the runtime needs to be started.
203 self->TransitionFromSuspendedToRunnable();
204 bool started = runtime_->Start();
205 ASSERT_TRUE(started);
206
207 ThreadPool thread_pool("Thread pool test thread pool", 1, true);
208 thread_pool.AddTask(self, new PeerTask());
209 thread_pool.StartWorkers(self);
210 thread_pool.Wait(self, false, false);
211 }
212}
213
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700214} // namespace art