blob: 98178bc40c0e6a7ec34f92921a9f64ce4c4d391c [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
17
18#include <string>
19
20#include "atomic_integer.h"
21#include "common_test.h"
22#include "thread_pool.h"
23
24namespace art {
25
Mathieu Chartier02b6a782012-10-26 13:51:26 -070026class CountTask : public Task {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070027 public:
Brian Carlstrom93ba8932013-07-17 21:31:49 -070028 explicit CountTask(AtomicInteger* count) : count_(count), verbose_(false) {}
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070029
Ian Rogersd914eb22013-04-18 16:11:15 -070030 void Run(Thread* self) {
31 if (verbose_) {
32 LOG(INFO) << "Running: " << *self;
33 }
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070034 // Simulate doing some work.
35 usleep(100);
36 // Increment the counter which keeps track of work completed.
37 ++*count_;
Mathieu Chartier02b6a782012-10-26 13:51:26 -070038 }
39
40 void Finalize() {
Ian Rogersd914eb22013-04-18 16:11:15 -070041 if (verbose_) {
42 LOG(INFO) << "Finalizing: " << *Thread::Current();
43 }
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070044 delete this;
45 }
46
47 private:
48 AtomicInteger* const count_;
Ian Rogersd914eb22013-04-18 16:11:15 -070049 const bool verbose_;
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070050};
51
52class ThreadPoolTest : public CommonTest {
53 public:
54 static int32_t num_threads;
55};
56
57int32_t ThreadPoolTest::num_threads = 4;
58
59// Check that the thread pool actually runs tasks that you assign it.
60TEST_F(ThreadPoolTest, CheckRun) {
61 Thread* self = Thread::Current();
62 ThreadPool thread_pool(num_threads);
Brian Carlstrom93ba8932013-07-17 21:31:49 -070063 AtomicInteger count(0);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070064 static const int32_t num_tasks = num_threads * 4;
65 for (int32_t i = 0; i < num_tasks; ++i) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -070066 thread_pool.AddTask(self, new CountTask(&count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070067 }
68 thread_pool.StartWorkers(self);
69 // Wait for tasks to complete.
Ian Rogers1d54e732013-05-02 21:10:01 -070070 thread_pool.Wait(self, true, false);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070071 // Make sure that we finished all the work.
72 EXPECT_EQ(num_tasks, count);
73}
74
75TEST_F(ThreadPoolTest, StopStart) {
76 Thread* self = Thread::Current();
77 ThreadPool thread_pool(num_threads);
Brian Carlstrom93ba8932013-07-17 21:31:49 -070078 AtomicInteger count(0);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070079 static const int32_t num_tasks = num_threads * 4;
80 for (int32_t i = 0; i < num_tasks; ++i) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -070081 thread_pool.AddTask(self, new CountTask(&count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070082 }
83 usleep(200);
84 // Check that no threads started prematurely.
85 EXPECT_EQ(0, count);
86 // Signal the threads to start processing tasks.
87 thread_pool.StartWorkers(self);
88 usleep(200);
89 thread_pool.StopWorkers(self);
Brian Carlstrom93ba8932013-07-17 21:31:49 -070090 AtomicInteger bad_count(0);
Mathieu Chartier02b6a782012-10-26 13:51:26 -070091 thread_pool.AddTask(self, new CountTask(&bad_count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070092 usleep(200);
93 // Ensure that the task added after the workers were stopped doesn't get run.
94 EXPECT_EQ(0, bad_count);
Ian Rogersd914eb22013-04-18 16:11:15 -070095 // Allow tasks to finish up and delete themselves.
96 thread_pool.StartWorkers(self);
97 while (count.get() != num_tasks && bad_count.get() != 1) {
98 usleep(200);
99 }
100 thread_pool.StopWorkers(self);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700101}
102
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700103class TreeTask : public Task {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700104 public:
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700105 TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth)
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700106 : thread_pool_(thread_pool),
107 count_(count),
Brian Carlstrom0cd7ec22013-07-17 23:40:20 -0700108 depth_(depth) {}
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700109
110 void Run(Thread* self) {
111 if (depth_ > 1) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700112 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1));
113 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700114 }
115 // Increment the counter which keeps track of work completed.
116 ++*count_;
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700117 }
118
119 void Finalize() {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700120 delete this;
121 }
122
123 private:
124 ThreadPool* const thread_pool_;
125 AtomicInteger* const count_;
126 const int depth_;
127};
128
129// Test that adding new tasks from within a task works.
130TEST_F(ThreadPoolTest, RecursiveTest) {
131 Thread* self = Thread::Current();
132 ThreadPool thread_pool(num_threads);
Brian Carlstrom93ba8932013-07-17 21:31:49 -0700133 AtomicInteger count(0);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700134 static const int depth = 8;
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700135 thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700136 thread_pool.StartWorkers(self);
Ian Rogers1d54e732013-05-02 21:10:01 -0700137 thread_pool.Wait(self, true, false);
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700138 EXPECT_EQ((1 << depth) - 1, count);
139}
140
141} // namespace art