blob: 2ae2ecff4e4de4ef7e64bae894a462b8766ca6a8 [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
Ian Rogersef7d42f2014-01-06 12:55:46 -080021#include "atomic.h"
Brian Carlstroma1ce1fe2014-02-24 23:23:58 -080022#include "common_runtime_test.h"
Ian Rogerse63db272014-07-15 15:36:11 -070023#include "thread-inl.h"
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070024
25namespace art {
26
Mathieu Chartier02b6a782012-10-26 13:51:26 -070027class CountTask : public Task {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070028 public:
Brian Carlstrom93ba8932013-07-17 21:31:49 -070029 explicit CountTask(AtomicInteger* count) : count_(count), verbose_(false) {}
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070030
Ian Rogersd914eb22013-04-18 16:11:15 -070031 void Run(Thread* self) {
32 if (verbose_) {
33 LOG(INFO) << "Running: " << *self;
34 }
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070035 // Simulate doing some work.
36 usleep(100);
37 // Increment the counter which keeps track of work completed.
38 ++*count_;
Mathieu Chartier02b6a782012-10-26 13:51:26 -070039 }
40
41 void Finalize() {
Ian Rogersd914eb22013-04-18 16:11:15 -070042 if (verbose_) {
43 LOG(INFO) << "Finalizing: " << *Thread::Current();
44 }
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070045 delete this;
46 }
47
48 private:
49 AtomicInteger* const count_;
Ian Rogersd914eb22013-04-18 16:11:15 -070050 const bool verbose_;
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070051};
52
Brian Carlstroma1ce1fe2014-02-24 23:23:58 -080053class ThreadPoolTest : public CommonRuntimeTest {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070054 public:
55 static int32_t num_threads;
56};
57
58int32_t ThreadPoolTest::num_threads = 4;
59
60// Check that the thread pool actually runs tasks that you assign it.
61TEST_F(ThreadPoolTest, CheckRun) {
62 Thread* self = Thread::Current();
Mathieu Chartierbcd5e9d2013-11-13 14:33:28 -080063 ThreadPool thread_pool("Thread pool test thread pool", num_threads);
Brian Carlstrom93ba8932013-07-17 21:31:49 -070064 AtomicInteger count(0);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070065 static const int32_t num_tasks = num_threads * 4;
66 for (int32_t i = 0; i < num_tasks; ++i) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -070067 thread_pool.AddTask(self, new CountTask(&count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070068 }
69 thread_pool.StartWorkers(self);
70 // Wait for tasks to complete.
Ian Rogers1d54e732013-05-02 21:10:01 -070071 thread_pool.Wait(self, true, false);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070072 // Make sure that we finished all the work.
Ian Rogers3e5cf302014-05-20 16:40:37 -070073 EXPECT_EQ(num_tasks, count.LoadSequentiallyConsistent());
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070074}
75
76TEST_F(ThreadPoolTest, StopStart) {
77 Thread* self = Thread::Current();
Mathieu Chartierbcd5e9d2013-11-13 14:33:28 -080078 ThreadPool thread_pool("Thread pool test thread pool", num_threads);
Brian Carlstrom93ba8932013-07-17 21:31:49 -070079 AtomicInteger count(0);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070080 static const int32_t num_tasks = num_threads * 4;
81 for (int32_t i = 0; i < num_tasks; ++i) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -070082 thread_pool.AddTask(self, new CountTask(&count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070083 }
84 usleep(200);
85 // Check that no threads started prematurely.
Ian Rogers3e5cf302014-05-20 16:40:37 -070086 EXPECT_EQ(0, count.LoadSequentiallyConsistent());
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070087 // Signal the threads to start processing tasks.
88 thread_pool.StartWorkers(self);
89 usleep(200);
90 thread_pool.StopWorkers(self);
Brian Carlstrom93ba8932013-07-17 21:31:49 -070091 AtomicInteger bad_count(0);
Mathieu Chartier02b6a782012-10-26 13:51:26 -070092 thread_pool.AddTask(self, new CountTask(&bad_count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070093 usleep(200);
94 // Ensure that the task added after the workers were stopped doesn't get run.
Ian Rogers3e5cf302014-05-20 16:40:37 -070095 EXPECT_EQ(0, bad_count.LoadSequentiallyConsistent());
Ian Rogersd914eb22013-04-18 16:11:15 -070096 // Allow tasks to finish up and delete themselves.
97 thread_pool.StartWorkers(self);
Mathieu Chartier7947b542014-11-09 12:30:50 -080098 thread_pool.Wait(self, false, false);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070099}
100
Andreas Gampe6f3a70f2016-11-16 13:58:05 -0800101TEST_F(ThreadPoolTest, StopWait) {
102 Thread* self = Thread::Current();
103 ThreadPool thread_pool("Thread pool test thread pool", num_threads);
104
105 AtomicInteger count(0);
106 static const int32_t num_tasks = num_threads * 100;
107 for (int32_t i = 0; i < num_tasks; ++i) {
108 thread_pool.AddTask(self, new CountTask(&count));
109 }
110
111 // Signal the threads to start processing tasks.
112 thread_pool.StartWorkers(self);
113 usleep(200);
114 thread_pool.StopWorkers(self);
115
116 thread_pool.Wait(self, false, false); // We should not deadlock here.
117}
118
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700119class TreeTask : public Task {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700120 public:
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700121 TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth)
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700122 : thread_pool_(thread_pool),
123 count_(count),
Brian Carlstrom0cd7ec22013-07-17 23:40:20 -0700124 depth_(depth) {}
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700125
126 void Run(Thread* self) {
127 if (depth_ > 1) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700128 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1));
129 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700130 }
131 // Increment the counter which keeps track of work completed.
132 ++*count_;
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700133 }
134
135 void Finalize() {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700136 delete this;
137 }
138
139 private:
140 ThreadPool* const thread_pool_;
141 AtomicInteger* const count_;
142 const int depth_;
143};
144
145// Test that adding new tasks from within a task works.
146TEST_F(ThreadPoolTest, RecursiveTest) {
147 Thread* self = Thread::Current();
Mathieu Chartierbcd5e9d2013-11-13 14:33:28 -0800148 ThreadPool thread_pool("Thread pool test thread pool", num_threads);
Brian Carlstrom93ba8932013-07-17 21:31:49 -0700149 AtomicInteger count(0);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700150 static const int depth = 8;
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700151 thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700152 thread_pool.StartWorkers(self);
Ian Rogers1d54e732013-05-02 21:10:01 -0700153 thread_pool.Wait(self, true, false);
Ian Rogers3e5cf302014-05-20 16:40:37 -0700154 EXPECT_EQ((1 << depth) - 1, count.LoadSequentiallyConsistent());
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700155}
156
157} // namespace art