Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(308)

Side by Side Diff: runtime/vm/thread_pool_test.cc

Issue 9581039: Implement ThreadPool. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "vm/os.h"
6 #include "vm/thread.h"
7 #include "vm/thread_pool.h"
8 #include "vm/unit_test.h"
9
10 namespace dart {
11
12 DECLARE_FLAG(int, worker_timeout_millis);
13
14
15 class ThreadPoolTestPeer {
16 public:
17 // When the pool has an exit monitor, workers notify a monitor just
18 // before they exit. This is only used in tests to make sure that
19 // Shutdown works.
20 static void SetExitMonitor(Monitor* exit_monitor, int* exit_count) {
21 ThreadPool::exit_monitor_ = exit_monitor;
22 ThreadPool::exit_count_ = exit_count;
23 }
24 };
25
26
27 UNIT_TEST_CASE(ThreadPool_Create) {
28 ThreadPool thread_pool;
29 }
30
31
32 class TestTask : public ThreadPool::Task {
33 public:
34 TestTask(Monitor* sync, bool* done)
35 : sync_(sync), done_(done) {
36 }
37
38 void Run() {
39 MonitorLocker ml(sync_);
40 *done_ = true;
41 ml.Notify();
42 }
43
44 private:
45 Monitor* sync_;
46 bool* done_;
47 };
48
49
50 UNIT_TEST_CASE(ThreadPool_RunOne) {
51 ThreadPool thread_pool;
52 Monitor sync;
53 bool done = false;
54 thread_pool.Run(new TestTask(&sync, &done));
55 {
56 MonitorLocker ml(&sync);
57 while (!done) {
58 ml.Wait();
59 }
60 }
61 EXPECT(done);
62
63 // Do a sanity test on the worker stats.
64 EXPECT_EQ(1, thread_pool.workers_started());
65 EXPECT_EQ(0, thread_pool.workers_stopped());
66 EXPECT_EQ(1, thread_pool.workers_idle());
67 EXPECT_EQ(0, thread_pool.workers_running());
68 }
69
70
71 UNIT_TEST_CASE(ThreadPool_RunMany) {
72 const int kTaskCount = 100;
73 ThreadPool thread_pool;
74 Monitor sync[kTaskCount];
75 bool done[kTaskCount];
76
77 for (int i = 0; i < kTaskCount; i++) {
78 done[i] = false;
79 thread_pool.Run(new TestTask(&sync[i], &done[i]));
80 }
81 for (int i = 0; i < kTaskCount; i++) {
82 MonitorLocker ml(&sync[i]);
83 while (!done[i]) {
84 ml.Wait();
85 }
86 EXPECT(done[i]);
87 }
88 }
89
90
91 class SleepTask : public ThreadPool::Task {
92 public:
93 explicit SleepTask(int millis)
94 : millis_(millis) {
95 }
96
97 void Run() {
98 OS::Sleep(millis_);
99 }
100
101 private:
102 int millis_;
103 };
104
105
106 UNIT_TEST_CASE(ThreadPool_WorkerShutdown) {
107 Monitor exit_sync;
108 int exit_count = 0;
109 MonitorLocker ml(&exit_sync);
110
111 // Set up the ThreadPool so that workers notify before they exit.
112 ThreadPool* thread_pool = new ThreadPool();
113 ThreadPoolTestPeer::SetExitMonitor(&exit_sync, &exit_count);
114
115 // Run a single task.
116 thread_pool->Run(new SleepTask(2));
117
118 // Kill the thread pool.
119 delete thread_pool;
120 thread_pool = NULL;
121
122 // Wait for the workers to terminate.
123 while (exit_count == 0) {
124 ml.Wait();
125 }
126 EXPECT_EQ(1, exit_count);
127 }
128
129
130 UNIT_TEST_CASE(ThreadPool_WorkerTimeout) {
131 // Adjust the worker timeout so that we timeout quickly.
132 int saved_timeout = FLAG_worker_timeout_millis;
133 FLAG_worker_timeout_millis = 1;
134
135 ThreadPool thread_pool;
136 EXPECT_EQ(0, thread_pool.workers_started());
137 EXPECT_EQ(0, thread_pool.workers_stopped());
138
139 // Run a worker.
140 Monitor sync;
141 bool done = false;
142 thread_pool.Run(new TestTask(&sync, &done));
143 EXPECT_EQ(1, thread_pool.workers_started());
144 EXPECT_EQ(0, thread_pool.workers_stopped());
145 {
146 MonitorLocker ml(&sync);
147 while (!done) {
148 ml.Wait();
149 }
150 }
151 EXPECT(done);
152
153 // Wait up to 5 seconds to see if a worker times out.
154 const int kMaxWait = 5000;
155 int waited = 0;
156 while (thread_pool.workers_stopped() == 0 && waited < kMaxWait) {
157 OS::Sleep(1);
158 waited += 1;
159 }
160 EXPECT_EQ(1, thread_pool.workers_stopped());
161 FLAG_worker_timeout_millis = saved_timeout;
162 }
163
164
165 class SpawnTask : public ThreadPool::Task {
166 public:
167 SpawnTask(ThreadPool* pool, Monitor* sync, int todo, int total, int* done)
168 : pool_(pool), sync_(sync), todo_(todo), total_(total), done_(done) {
169 }
170
171 void Run() {
172 todo_--; // Subtract one for current task.
173 int child_todo = todo_ / 2;
174
175 // Spawn 0-2 children.
176 if (todo_ > 0) {
177 pool_->Run(
178 new SpawnTask(pool_, sync_, todo_ - child_todo, total_, done_));
179 }
180 if (todo_ > 1) {
181 pool_->Run(
182 new SpawnTask(pool_, sync_, child_todo, total_, done_));
183 }
184
185 {
186 MonitorLocker ml(sync_);
187 (*done_)++;
188 if (*done_ >= total_) {
189 ml.Notify();
190 }
191 }
192 }
193
194 private:
195 ThreadPool* pool_;
196 Monitor* sync_;
197 int todo_;
198 int total_;
199 int* done_;
200 };
201
202
203 UNIT_TEST_CASE(ThreadPool_RecursiveSpawn) {
204 ThreadPool thread_pool;
205 Monitor sync;
206 const int kTotalTasks = 500;
207 int done = 0;
208 thread_pool.Run(
209 new SpawnTask(&thread_pool, &sync, kTotalTasks, kTotalTasks, &done));
210 {
211 MonitorLocker ml(&sync);
212 while (done < kTotalTasks) {
213 ml.Wait();
214 }
215 }
216 EXPECT_EQ(kTotalTasks, done);
217 }
218
219
220 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698