blob: 783f786bef67b1f14b74613d3a21ba7361d99601 [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
26class CountClosure : public Closure {
27 public:
28 CountClosure(AtomicInteger* count) : count_(count) {
29
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_;
37 delete this;
38 }
39
40 private:
41 AtomicInteger* const count_;
42};
43
44class ThreadPoolTest : public CommonTest {
45 public:
46 static int32_t num_threads;
47};
48
49int32_t ThreadPoolTest::num_threads = 4;
50
51// Check that the thread pool actually runs tasks that you assign it.
52TEST_F(ThreadPoolTest, CheckRun) {
53 Thread* self = Thread::Current();
54 ThreadPool thread_pool(num_threads);
55 AtomicInteger count = 0;
56 static const int32_t num_tasks = num_threads * 4;
57 for (int32_t i = 0; i < num_tasks; ++i) {
58 thread_pool.AddTask(self, new CountClosure(&count));
59 }
60 thread_pool.StartWorkers(self);
61 // Wait for tasks to complete.
62 thread_pool.Wait(self);
63 // Make sure that we finished all the work.
64 EXPECT_EQ(num_tasks, count);
65}
66
67TEST_F(ThreadPoolTest, StopStart) {
68 Thread* self = Thread::Current();
69 ThreadPool thread_pool(num_threads);
70 AtomicInteger count = 0;
71 static const int32_t num_tasks = num_threads * 4;
72 for (int32_t i = 0; i < num_tasks; ++i) {
73 thread_pool.AddTask(self, new CountClosure(&count));
74 }
75 usleep(200);
76 // Check that no threads started prematurely.
77 EXPECT_EQ(0, count);
78 // Signal the threads to start processing tasks.
79 thread_pool.StartWorkers(self);
80 usleep(200);
81 thread_pool.StopWorkers(self);
82 AtomicInteger bad_count = 0;
83 thread_pool.AddTask(self, new CountClosure(&bad_count));
84 usleep(200);
85 // Ensure that the task added after the workers were stopped doesn't get run.
86 EXPECT_EQ(0, bad_count);
87}
88
89class TreeClosure : public Closure {
90 public:
91 TreeClosure(ThreadPool* const thread_pool, AtomicInteger* count, int depth)
92 : thread_pool_(thread_pool),
93 count_(count),
94 depth_(depth) {
95
96 }
97
98 void Run(Thread* self) {
99 if (depth_ > 1) {
100 thread_pool_->AddTask(self, new TreeClosure(thread_pool_, count_, depth_ - 1));
101 thread_pool_->AddTask(self, new TreeClosure(thread_pool_, count_, depth_ - 1));
102 }
103 // Increment the counter which keeps track of work completed.
104 ++*count_;
105 delete this;
106 }
107
108 private:
109 ThreadPool* const thread_pool_;
110 AtomicInteger* const count_;
111 const int depth_;
112};
113
114// Test that adding new tasks from within a task works.
115TEST_F(ThreadPoolTest, RecursiveTest) {
116 Thread* self = Thread::Current();
117 ThreadPool thread_pool(num_threads);
118 AtomicInteger count = 0;
119 static const int depth = 8;
120 thread_pool.AddTask(self, new TreeClosure(&thread_pool, &count, depth));
121 thread_pool.StartWorkers(self);
122 thread_pool.Wait(self);
123 EXPECT_EQ((1 << depth) - 1, count);
124}
125
126} // namespace art