blob: bac60021c1712f9a31347aeb7a31c47f8689bca7 [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:
Mathieu Chartier02b6a782012-10-26 13:51:26 -070028 CountTask(AtomicInteger* count) : count_(count) {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070029
30 }
31
32 void Run(Thread* /* self */) {
33 // Simulate doing some work.
34 usleep(100);
35 // Increment the counter which keeps track of work completed.
36 ++*count_;
Mathieu Chartier02b6a782012-10-26 13:51:26 -070037 }
38
39 void Finalize() {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070040 delete this;
41 }
42
43 private:
44 AtomicInteger* const count_;
45};
46
47class ThreadPoolTest : public CommonTest {
48 public:
49 static int32_t num_threads;
50};
51
52int32_t ThreadPoolTest::num_threads = 4;
53
54// Check that the thread pool actually runs tasks that you assign it.
55TEST_F(ThreadPoolTest, CheckRun) {
56 Thread* self = Thread::Current();
57 ThreadPool thread_pool(num_threads);
58 AtomicInteger count = 0;
59 static const int32_t num_tasks = num_threads * 4;
60 for (int32_t i = 0; i < num_tasks; ++i) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -070061 thread_pool.AddTask(self, new CountTask(&count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070062 }
63 thread_pool.StartWorkers(self);
64 // Wait for tasks to complete.
65 thread_pool.Wait(self);
66 // Make sure that we finished all the work.
67 EXPECT_EQ(num_tasks, count);
68}
69
70TEST_F(ThreadPoolTest, StopStart) {
71 Thread* self = Thread::Current();
72 ThreadPool thread_pool(num_threads);
73 AtomicInteger count = 0;
74 static const int32_t num_tasks = num_threads * 4;
75 for (int32_t i = 0; i < num_tasks; ++i) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -070076 thread_pool.AddTask(self, new CountTask(&count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070077 }
78 usleep(200);
79 // Check that no threads started prematurely.
80 EXPECT_EQ(0, count);
81 // Signal the threads to start processing tasks.
82 thread_pool.StartWorkers(self);
83 usleep(200);
84 thread_pool.StopWorkers(self);
85 AtomicInteger bad_count = 0;
Mathieu Chartier02b6a782012-10-26 13:51:26 -070086 thread_pool.AddTask(self, new CountTask(&bad_count));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070087 usleep(200);
88 // Ensure that the task added after the workers were stopped doesn't get run.
89 EXPECT_EQ(0, bad_count);
90}
91
Mathieu Chartier02b6a782012-10-26 13:51:26 -070092class TreeTask : public Task {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070093 public:
Mathieu Chartier02b6a782012-10-26 13:51:26 -070094 TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth)
Mathieu Chartier0e4627e2012-10-23 16:13:36 -070095 : thread_pool_(thread_pool),
96 count_(count),
97 depth_(depth) {
98
99 }
100
101 void Run(Thread* self) {
102 if (depth_ > 1) {
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700103 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1));
104 thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700105 }
106 // Increment the counter which keeps track of work completed.
107 ++*count_;
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700108 }
109
110 void Finalize() {
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700111 delete this;
112 }
113
114 private:
115 ThreadPool* const thread_pool_;
116 AtomicInteger* const count_;
117 const int depth_;
118};
119
120// Test that adding new tasks from within a task works.
121TEST_F(ThreadPoolTest, RecursiveTest) {
122 Thread* self = Thread::Current();
123 ThreadPool thread_pool(num_threads);
124 AtomicInteger count = 0;
125 static const int depth = 8;
Mathieu Chartier02b6a782012-10-26 13:51:26 -0700126 thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth));
Mathieu Chartier0e4627e2012-10-23 16:13:36 -0700127 thread_pool.StartWorkers(self);
128 thread_pool.Wait(self);
129 EXPECT_EQ((1 << depth) - 1, count);
130}
131
132} // namespace art