blob: 2d9733763a171989badf4cf1898d4e78903416af [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Mark Slee9f0c6512007-02-28 23:58:26 +000019
Roger Meierba406d32013-07-15 22:41:34 +020020#include <thrift/thrift-config.h>
Roger Meier49ff8b12012-04-13 09:12:31 +000021#include <thrift/concurrency/Thread.h>
22#include <thrift/concurrency/PlatformThreadFactory.h>
23#include <thrift/concurrency/Monitor.h>
24#include <thrift/concurrency/Util.h>
Marc Slemko8a40a762006-07-19 17:46:50 +000025
26#include <assert.h>
27#include <iostream>
28#include <set>
29
T Jake Lucianib5e62212009-01-31 22:36:20 +000030namespace apache { namespace thrift { namespace concurrency { namespace test {
Marc Slemko8a40a762006-07-19 17:46:50 +000031
Mark Slee5ea15f92007-03-05 22:55:59 +000032using boost::shared_ptr;
T Jake Lucianib5e62212009-01-31 22:36:20 +000033using namespace apache::thrift::concurrency;
Marc Slemko8a40a762006-07-19 17:46:50 +000034
Mark Sleef5f2be42006-09-05 21:05:31 +000035/**
Marc Slemko3a3b53b2007-05-22 23:59:54 +000036 * ThreadManagerTests class
Mark Sleef5f2be42006-09-05 21:05:31 +000037 *
Mark Sleef5f2be42006-09-05 21:05:31 +000038 * @version $Id:$
39 */
Marc Slemko8a40a762006-07-19 17:46:50 +000040class ThreadFactoryTests {
41
Marc Slemko6f038a72006-08-03 18:58:09 +000042public:
43
Konrad Grochowski293a40e2014-09-04 17:28:17 +040044 static const double TEST_TOLERANCE;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000045
Marc Slemko6f038a72006-08-03 18:58:09 +000046 class Task: public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +000047
48 public:
49
50 Task() {}
51
52 void run() {
53 std::cout << "\t\t\tHello World" << std::endl;
54 }
55 };
56
Mark Sleef5f2be42006-09-05 21:05:31 +000057 /**
58 * Hello world test
59 */
Marc Slemko8a40a762006-07-19 17:46:50 +000060 bool helloWorldTest() {
61
Roger Meier3faaedf2011-10-02 10:51:45 +000062 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +000063
Marc Slemko6f038a72006-08-03 18:58:09 +000064 shared_ptr<Task> task = shared_ptr<Task>(new ThreadFactoryTests::Task());
Marc Slemko8a40a762006-07-19 17:46:50 +000065
Marc Slemko6f038a72006-08-03 18:58:09 +000066 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemko8a40a762006-07-19 17:46:50 +000067
68 thread->start();
69
70 thread->join();
71
Marc Slemko8a40a762006-07-19 17:46:50 +000072 std::cout << "\t\t\tSuccess!" << std::endl;
73
74 return true;
75 }
76
Mark Sleef5f2be42006-09-05 21:05:31 +000077 /**
78 * Reap N threads
79 */
80 class ReapNTask: public Runnable {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000081
Mark Sleef5f2be42006-09-05 21:05:31 +000082 public:
Marc Slemko3a3b53b2007-05-22 23:59:54 +000083
Mark Sleef5f2be42006-09-05 21:05:31 +000084 ReapNTask(Monitor& monitor, int& activeCount) :
85 _monitor(monitor),
86 _count(activeCount) {}
Marc Slemko3a3b53b2007-05-22 23:59:54 +000087
Marc Slemko8a40a762006-07-19 17:46:50 +000088 void run() {
Mark Sleef5f2be42006-09-05 21:05:31 +000089 Synchronized s(_monitor);
Marc Slemko3a3b53b2007-05-22 23:59:54 +000090
Mark Sleef5f2be42006-09-05 21:05:31 +000091 _count--;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000092
Mark Sleef5f2be42006-09-05 21:05:31 +000093 //std::cout << "\t\t\tthread count: " << _count << std::endl;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000094
Mark Sleef5f2be42006-09-05 21:05:31 +000095 if (_count == 0) {
96 _monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +000097 }
98 }
99
100 Monitor& _monitor;
101
102 int& _count;
103 };
104
Marc Slemko67606e52007-06-04 21:01:19 +0000105 bool reapNThreads(int loop=1, int count=10) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000106
Roger Meier3faaedf2011-10-02 10:51:45 +0000107 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +0000108
Marc Slemko67606e52007-06-04 21:01:19 +0000109 Monitor* monitor = new Monitor();
Marc Slemko8a40a762006-07-19 17:46:50 +0000110
Marc Slemko67606e52007-06-04 21:01:19 +0000111 for(int lix = 0; lix < loop; lix++) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000112
Marc Slemko67606e52007-06-04 21:01:19 +0000113 int* activeCount = new int(count);
Marc Slemko8a40a762006-07-19 17:46:50 +0000114
Marc Slemko67606e52007-06-04 21:01:19 +0000115 std::set<shared_ptr<Thread> > threads;
Marc Slemko8a40a762006-07-19 17:46:50 +0000116
Marc Slemko67606e52007-06-04 21:01:19 +0000117 int tix;
Marc Slemko8a40a762006-07-19 17:46:50 +0000118
Marc Slemko67606e52007-06-04 21:01:19 +0000119 for (tix = 0; tix < count; tix++) {
120 try {
121 threads.insert(threadFactory.newThread(shared_ptr<Runnable>(new ReapNTask(*monitor, *activeCount))));
122 } catch(SystemResourceException& e) {
123 std::cout << "\t\t\tfailed to create " << lix * count + tix << " thread " << e.what() << std::endl;
124 throw e;
125 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000126 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000127
Marc Slemko67606e52007-06-04 21:01:19 +0000128 tix = 0;
129 for (std::set<shared_ptr<Thread> >::const_iterator thread = threads.begin(); thread != threads.end(); tix++, ++thread) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000130
Marc Slemko67606e52007-06-04 21:01:19 +0000131 try {
132 (*thread)->start();
133 } catch(SystemResourceException& e) {
134 std::cout << "\t\t\tfailed to start " << lix * count + tix << " thread " << e.what() << std::endl;
135 throw e;
136 }
137 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000138
Marc Slemko67606e52007-06-04 21:01:19 +0000139 {
140 Synchronized s(*monitor);
141 while (*activeCount > 0) {
142 monitor->wait(1000);
143 }
144 }
Roger Meier3075ffc2011-08-04 22:36:07 +0000145 delete activeCount;
Marc Slemko67606e52007-06-04 21:01:19 +0000146 std::cout << "\t\t\treaped " << lix * count << " threads" << std::endl;
Marc Slemko8a40a762006-07-19 17:46:50 +0000147 }
148
149 std::cout << "\t\t\tSuccess!" << std::endl;
150
151 return true;
152 }
153
Mark Sleef5f2be42006-09-05 21:05:31 +0000154 class SynchStartTask: public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +0000155
Mark Sleef5f2be42006-09-05 21:05:31 +0000156 public:
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000157
Marc Slemko8a40a762006-07-19 17:46:50 +0000158 enum STATE {
Marc Slemko03dedd92006-07-20 00:58:47 +0000159 UNINITIALIZED,
160 STARTING,
161 STARTED,
162 STOPPING,
163 STOPPED
Marc Slemko8a40a762006-07-19 17:46:50 +0000164 };
165
Mark Sleef5f2be42006-09-05 21:05:31 +0000166 SynchStartTask(Monitor& monitor, volatile STATE& state) :
167 _monitor(monitor),
168 _state(state) {}
Marc Slemko8a40a762006-07-19 17:46:50 +0000169
170 void run() {
Mark Sleef5f2be42006-09-05 21:05:31 +0000171 {
172 Synchronized s(_monitor);
David Reiss96d23882007-07-26 21:10:32 +0000173 if (_state == SynchStartTask::STARTING) {
174 _state = SynchStartTask::STARTED;
175 _monitor.notify();
176 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000177 }
178
Mark Sleef5f2be42006-09-05 21:05:31 +0000179 {
180 Synchronized s(_monitor);
181 while (_state == SynchStartTask::STARTED) {
David Reiss96d23882007-07-26 21:10:32 +0000182 _monitor.wait();
183 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000184
David Reiss96d23882007-07-26 21:10:32 +0000185 if (_state == SynchStartTask::STOPPING) {
Mark Sleef5f2be42006-09-05 21:05:31 +0000186 _state = SynchStartTask::STOPPED;
187 _monitor.notifyAll();
David Reiss96d23882007-07-26 21:10:32 +0000188 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000189 }
190 }
191
Mark Sleef5f2be42006-09-05 21:05:31 +0000192 private:
Marc Slemko8a40a762006-07-19 17:46:50 +0000193 Monitor& _monitor;
194 volatile STATE& _state;
195 };
196
197 bool synchStartTest() {
198
199 Monitor monitor;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000200
Marc Slemko8a40a762006-07-19 17:46:50 +0000201 SynchStartTask::STATE state = SynchStartTask::UNINITIALIZED;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000202
Marc Slemko6f038a72006-08-03 18:58:09 +0000203 shared_ptr<SynchStartTask> task = shared_ptr<SynchStartTask>(new SynchStartTask(monitor, state));
Marc Slemko8a40a762006-07-19 17:46:50 +0000204
Roger Meier3faaedf2011-10-02 10:51:45 +0000205 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +0000206
Marc Slemko6f038a72006-08-03 18:58:09 +0000207 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemko8a40a762006-07-19 17:46:50 +0000208
Mark Sleef5f2be42006-09-05 21:05:31 +0000209 if (state == SynchStartTask::UNINITIALIZED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000210
211 state = SynchStartTask::STARTING;
212
213 thread->start();
214 }
215
Mark Sleef5f2be42006-09-05 21:05:31 +0000216 {
217 Synchronized s(monitor);
218 while (state == SynchStartTask::STARTING) {
David Reiss96d23882007-07-26 21:10:32 +0000219 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000220 }
221 }
222
223 assert(state != SynchStartTask::STARTING);
224
Mark Sleef5f2be42006-09-05 21:05:31 +0000225 {
226 Synchronized s(monitor);
Marc Slemko8a40a762006-07-19 17:46:50 +0000227
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000228 try {
229 monitor.wait(100);
230 } catch(TimedOutException& e) {
231 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000232
Mark Sleef5f2be42006-09-05 21:05:31 +0000233 if (state == SynchStartTask::STARTED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000234
David Reiss96d23882007-07-26 21:10:32 +0000235 state = SynchStartTask::STOPPING;
Marc Slemko8a40a762006-07-19 17:46:50 +0000236
David Reiss96d23882007-07-26 21:10:32 +0000237 monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +0000238 }
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000239
Mark Sleef5f2be42006-09-05 21:05:31 +0000240 while (state == SynchStartTask::STOPPING) {
David Reiss96d23882007-07-26 21:10:32 +0000241 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000242 }
243 }
244
245 assert(state == SynchStartTask::STOPPED);
246
Marc Slemkoc7782972006-07-25 02:26:35 +0000247 bool success = true;
248
249 std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "!" << std::endl;
250
Marc Slemko8a40a762006-07-19 17:46:50 +0000251 return true;
252 }
253
Marc Slemkoc7782972006-07-25 02:26:35 +0000254 /** See how accurate monitor timeout is. */
255
Mark Slee9b82d272007-05-23 05:16:07 +0000256 bool monitorTimeoutTest(size_t count=1000, int64_t timeout=10) {
Marc Slemkoc7782972006-07-25 02:26:35 +0000257
258 Monitor monitor;
259
Mark Slee9b82d272007-05-23 05:16:07 +0000260 int64_t startTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000261
Mark Sleef5f2be42006-09-05 21:05:31 +0000262 for (size_t ix = 0; ix < count; ix++) {
263 {
264 Synchronized s(monitor);
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000265 try {
266 monitor.wait(timeout);
267 } catch(TimedOutException& e) {
268 }
Marc Slemkoc7782972006-07-25 02:26:35 +0000269 }
270 }
271
Mark Slee9b82d272007-05-23 05:16:07 +0000272 int64_t endTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000273
274 double error = ((endTime - startTime) - (count * timeout)) / (double)(count * timeout);
275
Mark Sleef5f2be42006-09-05 21:05:31 +0000276 if (error < 0.0) {
Marc Slemkoc7782972006-07-25 02:26:35 +0000277
278 error *= 1.0;
279 }
280
Konrad Grochowski293a40e2014-09-04 17:28:17 +0400281 bool success = error < ThreadFactoryTests::TEST_TOLERANCE;
Marc Slemkoc7782972006-07-25 02:26:35 +0000282
283 std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "! expected time: " << count * timeout << "ms elapsed time: "<< endTime - startTime << "ms error%: " << error * 100.0 << std::endl;
284
285 return success;
286 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000287
288
289 class FloodTask : public Runnable {
290 public:
291
292 FloodTask(const size_t id) :_id(id) {}
293 ~FloodTask(){
294 if(_id % 1000 == 0) {
295 std::cout << "\t\tthread " << _id << " done" << std::endl;
296 }
297 }
298
299 void run(){
300 if(_id % 1000 == 0) {
301 std::cout << "\t\tthread " << _id << " started" << std::endl;
302 }
303
Konrad Grochowski293a40e2014-09-04 17:28:17 +0400304 THRIFT_SLEEP_USEC(1);
Marc Slemkoa6479032007-06-05 22:20:14 +0000305 }
306 const size_t _id;
307 };
308
Roger Meier3faaedf2011-10-02 10:51:45 +0000309 void foo(PlatformThreadFactory *tf) {
Roger Meier3b771a12010-11-17 22:11:26 +0000310 (void) tf;
Marc Slemkoa6479032007-06-05 22:20:14 +0000311 }
312
313 bool floodNTest(size_t loop=1, size_t count=100000) {
314
315 bool success = false;
316
317 for(size_t lix = 0; lix < loop; lix++) {
318
Roger Meier3faaedf2011-10-02 10:51:45 +0000319 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemkoa6479032007-06-05 22:20:14 +0000320 threadFactory.setDetached(true);
321
322 for(size_t tix = 0; tix < count; tix++) {
323
324 try {
325
326 shared_ptr<FloodTask> task(new FloodTask(lix * count + tix ));
327
328 shared_ptr<Thread> thread = threadFactory.newThread(task);
329
330 thread->start();
331
Konrad Grochowski293a40e2014-09-04 17:28:17 +0400332 THRIFT_SLEEP_USEC(1);
Marc Slemkoa6479032007-06-05 22:20:14 +0000333
334 } catch (TException& e) {
335
336 std::cout << "\t\t\tfailed to start " << lix * count + tix << " thread " << e.what() << std::endl;
337
338 return success;
339 }
340 }
341
342 std::cout << "\t\t\tflooded " << (lix + 1) * count << " threads" << std::endl;
343
344 success = true;
345 }
346
347 return success;
348 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000349};
Marc Slemko8a40a762006-07-19 17:46:50 +0000350
Konrad Grochowski293a40e2014-09-04 17:28:17 +0400351const double ThreadFactoryTests::TEST_TOLERANCE = .20;
Marc Slemko8a40a762006-07-19 17:46:50 +0000352
T Jake Lucianib5e62212009-01-31 22:36:20 +0000353}}}} // apache::thrift::concurrency::test