blob: fda6c9e6c2b147f0e261cfe4a02abbda204eacef [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>
David Reiss5105b2e2009-05-21 02:28:27 +000027#include <unistd.h>
Marc Slemko8a40a762006-07-19 17:46:50 +000028#include <iostream>
29#include <set>
30
T Jake Lucianib5e62212009-01-31 22:36:20 +000031namespace apache { namespace thrift { namespace concurrency { namespace test {
Marc Slemko8a40a762006-07-19 17:46:50 +000032
Mark Slee5ea15f92007-03-05 22:55:59 +000033using boost::shared_ptr;
T Jake Lucianib5e62212009-01-31 22:36:20 +000034using namespace apache::thrift::concurrency;
Marc Slemko8a40a762006-07-19 17:46:50 +000035
Mark Sleef5f2be42006-09-05 21:05:31 +000036/**
Marc Slemko3a3b53b2007-05-22 23:59:54 +000037 * ThreadManagerTests class
Mark Sleef5f2be42006-09-05 21:05:31 +000038 *
Mark Sleef5f2be42006-09-05 21:05:31 +000039 * @version $Id:$
40 */
Marc Slemko8a40a762006-07-19 17:46:50 +000041class ThreadFactoryTests {
42
Marc Slemko6f038a72006-08-03 18:58:09 +000043public:
44
45 static const double ERROR;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000046
Marc Slemko6f038a72006-08-03 18:58:09 +000047 class Task: public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +000048
49 public:
50
51 Task() {}
52
53 void run() {
54 std::cout << "\t\t\tHello World" << std::endl;
55 }
56 };
57
Mark Sleef5f2be42006-09-05 21:05:31 +000058 /**
59 * Hello world test
60 */
Marc Slemko8a40a762006-07-19 17:46:50 +000061 bool helloWorldTest() {
62
Roger Meier3faaedf2011-10-02 10:51:45 +000063 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +000064
Marc Slemko6f038a72006-08-03 18:58:09 +000065 shared_ptr<Task> task = shared_ptr<Task>(new ThreadFactoryTests::Task());
Marc Slemko8a40a762006-07-19 17:46:50 +000066
Marc Slemko6f038a72006-08-03 18:58:09 +000067 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemko8a40a762006-07-19 17:46:50 +000068
69 thread->start();
70
71 thread->join();
72
Marc Slemko8a40a762006-07-19 17:46:50 +000073 std::cout << "\t\t\tSuccess!" << std::endl;
74
75 return true;
76 }
77
Mark Sleef5f2be42006-09-05 21:05:31 +000078 /**
79 * Reap N threads
80 */
81 class ReapNTask: public Runnable {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000082
Mark Sleef5f2be42006-09-05 21:05:31 +000083 public:
Marc Slemko3a3b53b2007-05-22 23:59:54 +000084
Mark Sleef5f2be42006-09-05 21:05:31 +000085 ReapNTask(Monitor& monitor, int& activeCount) :
86 _monitor(monitor),
87 _count(activeCount) {}
Marc Slemko3a3b53b2007-05-22 23:59:54 +000088
Marc Slemko8a40a762006-07-19 17:46:50 +000089 void run() {
Mark Sleef5f2be42006-09-05 21:05:31 +000090 Synchronized s(_monitor);
Marc Slemko3a3b53b2007-05-22 23:59:54 +000091
Mark Sleef5f2be42006-09-05 21:05:31 +000092 _count--;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000093
Mark Sleef5f2be42006-09-05 21:05:31 +000094 //std::cout << "\t\t\tthread count: " << _count << std::endl;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000095
Mark Sleef5f2be42006-09-05 21:05:31 +000096 if (_count == 0) {
97 _monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +000098 }
99 }
100
101 Monitor& _monitor;
102
103 int& _count;
104 };
105
Marc Slemko67606e52007-06-04 21:01:19 +0000106 bool reapNThreads(int loop=1, int count=10) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000107
Roger Meier3faaedf2011-10-02 10:51:45 +0000108 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +0000109
Marc Slemko67606e52007-06-04 21:01:19 +0000110 Monitor* monitor = new Monitor();
Marc Slemko8a40a762006-07-19 17:46:50 +0000111
Marc Slemko67606e52007-06-04 21:01:19 +0000112 for(int lix = 0; lix < loop; lix++) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000113
Marc Slemko67606e52007-06-04 21:01:19 +0000114 int* activeCount = new int(count);
Marc Slemko8a40a762006-07-19 17:46:50 +0000115
Marc Slemko67606e52007-06-04 21:01:19 +0000116 std::set<shared_ptr<Thread> > threads;
Marc Slemko8a40a762006-07-19 17:46:50 +0000117
Marc Slemko67606e52007-06-04 21:01:19 +0000118 int tix;
Marc Slemko8a40a762006-07-19 17:46:50 +0000119
Marc Slemko67606e52007-06-04 21:01:19 +0000120 for (tix = 0; tix < count; tix++) {
121 try {
122 threads.insert(threadFactory.newThread(shared_ptr<Runnable>(new ReapNTask(*monitor, *activeCount))));
123 } catch(SystemResourceException& e) {
124 std::cout << "\t\t\tfailed to create " << lix * count + tix << " thread " << e.what() << std::endl;
125 throw e;
126 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000127 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000128
Marc Slemko67606e52007-06-04 21:01:19 +0000129 tix = 0;
130 for (std::set<shared_ptr<Thread> >::const_iterator thread = threads.begin(); thread != threads.end(); tix++, ++thread) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000131
Marc Slemko67606e52007-06-04 21:01:19 +0000132 try {
133 (*thread)->start();
134 } catch(SystemResourceException& e) {
135 std::cout << "\t\t\tfailed to start " << lix * count + tix << " thread " << e.what() << std::endl;
136 throw e;
137 }
138 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000139
Marc Slemko67606e52007-06-04 21:01:19 +0000140 {
141 Synchronized s(*monitor);
142 while (*activeCount > 0) {
143 monitor->wait(1000);
144 }
145 }
Roger Meier3075ffc2011-08-04 22:36:07 +0000146 delete activeCount;
Marc Slemko67606e52007-06-04 21:01:19 +0000147 std::cout << "\t\t\treaped " << lix * count << " threads" << std::endl;
Marc Slemko8a40a762006-07-19 17:46:50 +0000148 }
149
150 std::cout << "\t\t\tSuccess!" << std::endl;
151
152 return true;
153 }
154
Mark Sleef5f2be42006-09-05 21:05:31 +0000155 class SynchStartTask: public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +0000156
Mark Sleef5f2be42006-09-05 21:05:31 +0000157 public:
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000158
Marc Slemko8a40a762006-07-19 17:46:50 +0000159 enum STATE {
Marc Slemko03dedd92006-07-20 00:58:47 +0000160 UNINITIALIZED,
161 STARTING,
162 STARTED,
163 STOPPING,
164 STOPPED
Marc Slemko8a40a762006-07-19 17:46:50 +0000165 };
166
Mark Sleef5f2be42006-09-05 21:05:31 +0000167 SynchStartTask(Monitor& monitor, volatile STATE& state) :
168 _monitor(monitor),
169 _state(state) {}
Marc Slemko8a40a762006-07-19 17:46:50 +0000170
171 void run() {
Mark Sleef5f2be42006-09-05 21:05:31 +0000172 {
173 Synchronized s(_monitor);
David Reiss96d23882007-07-26 21:10:32 +0000174 if (_state == SynchStartTask::STARTING) {
175 _state = SynchStartTask::STARTED;
176 _monitor.notify();
177 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000178 }
179
Mark Sleef5f2be42006-09-05 21:05:31 +0000180 {
181 Synchronized s(_monitor);
182 while (_state == SynchStartTask::STARTED) {
David Reiss96d23882007-07-26 21:10:32 +0000183 _monitor.wait();
184 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000185
David Reiss96d23882007-07-26 21:10:32 +0000186 if (_state == SynchStartTask::STOPPING) {
Mark Sleef5f2be42006-09-05 21:05:31 +0000187 _state = SynchStartTask::STOPPED;
188 _monitor.notifyAll();
David Reiss96d23882007-07-26 21:10:32 +0000189 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000190 }
191 }
192
Mark Sleef5f2be42006-09-05 21:05:31 +0000193 private:
Marc Slemko8a40a762006-07-19 17:46:50 +0000194 Monitor& _monitor;
195 volatile STATE& _state;
196 };
197
198 bool synchStartTest() {
199
200 Monitor monitor;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000201
Marc Slemko8a40a762006-07-19 17:46:50 +0000202 SynchStartTask::STATE state = SynchStartTask::UNINITIALIZED;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000203
Marc Slemko6f038a72006-08-03 18:58:09 +0000204 shared_ptr<SynchStartTask> task = shared_ptr<SynchStartTask>(new SynchStartTask(monitor, state));
Marc Slemko8a40a762006-07-19 17:46:50 +0000205
Roger Meier3faaedf2011-10-02 10:51:45 +0000206 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +0000207
Marc Slemko6f038a72006-08-03 18:58:09 +0000208 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemko8a40a762006-07-19 17:46:50 +0000209
Mark Sleef5f2be42006-09-05 21:05:31 +0000210 if (state == SynchStartTask::UNINITIALIZED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000211
212 state = SynchStartTask::STARTING;
213
214 thread->start();
215 }
216
Mark Sleef5f2be42006-09-05 21:05:31 +0000217 {
218 Synchronized s(monitor);
219 while (state == SynchStartTask::STARTING) {
David Reiss96d23882007-07-26 21:10:32 +0000220 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000221 }
222 }
223
224 assert(state != SynchStartTask::STARTING);
225
Mark Sleef5f2be42006-09-05 21:05:31 +0000226 {
227 Synchronized s(monitor);
Marc Slemko8a40a762006-07-19 17:46:50 +0000228
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000229 try {
230 monitor.wait(100);
231 } catch(TimedOutException& e) {
232 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000233
Mark Sleef5f2be42006-09-05 21:05:31 +0000234 if (state == SynchStartTask::STARTED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000235
David Reiss96d23882007-07-26 21:10:32 +0000236 state = SynchStartTask::STOPPING;
Marc Slemko8a40a762006-07-19 17:46:50 +0000237
David Reiss96d23882007-07-26 21:10:32 +0000238 monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +0000239 }
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000240
Mark Sleef5f2be42006-09-05 21:05:31 +0000241 while (state == SynchStartTask::STOPPING) {
David Reiss96d23882007-07-26 21:10:32 +0000242 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000243 }
244 }
245
246 assert(state == SynchStartTask::STOPPED);
247
Marc Slemkoc7782972006-07-25 02:26:35 +0000248 bool success = true;
249
250 std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "!" << std::endl;
251
Marc Slemko8a40a762006-07-19 17:46:50 +0000252 return true;
253 }
254
Marc Slemkoc7782972006-07-25 02:26:35 +0000255 /** See how accurate monitor timeout is. */
256
Mark Slee9b82d272007-05-23 05:16:07 +0000257 bool monitorTimeoutTest(size_t count=1000, int64_t timeout=10) {
Marc Slemkoc7782972006-07-25 02:26:35 +0000258
259 Monitor monitor;
260
Mark Slee9b82d272007-05-23 05:16:07 +0000261 int64_t startTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000262
Mark Sleef5f2be42006-09-05 21:05:31 +0000263 for (size_t ix = 0; ix < count; ix++) {
264 {
265 Synchronized s(monitor);
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000266 try {
267 monitor.wait(timeout);
268 } catch(TimedOutException& e) {
269 }
Marc Slemkoc7782972006-07-25 02:26:35 +0000270 }
271 }
272
Mark Slee9b82d272007-05-23 05:16:07 +0000273 int64_t endTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000274
275 double error = ((endTime - startTime) - (count * timeout)) / (double)(count * timeout);
276
Mark Sleef5f2be42006-09-05 21:05:31 +0000277 if (error < 0.0) {
Marc Slemkoc7782972006-07-25 02:26:35 +0000278
279 error *= 1.0;
280 }
281
Marc Slemko6f038a72006-08-03 18:58:09 +0000282 bool success = error < ThreadFactoryTests::ERROR;
Marc Slemkoc7782972006-07-25 02:26:35 +0000283
284 std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "! expected time: " << count * timeout << "ms elapsed time: "<< endTime - startTime << "ms error%: " << error * 100.0 << std::endl;
285
286 return success;
287 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000288
289
290 class FloodTask : public Runnable {
291 public:
292
293 FloodTask(const size_t id) :_id(id) {}
294 ~FloodTask(){
295 if(_id % 1000 == 0) {
296 std::cout << "\t\tthread " << _id << " done" << std::endl;
297 }
298 }
299
300 void run(){
301 if(_id % 1000 == 0) {
302 std::cout << "\t\tthread " << _id << " started" << std::endl;
303 }
304
305 usleep(1);
306 }
307 const size_t _id;
308 };
309
Roger Meier3faaedf2011-10-02 10:51:45 +0000310 void foo(PlatformThreadFactory *tf) {
Roger Meier3b771a12010-11-17 22:11:26 +0000311 (void) tf;
Marc Slemkoa6479032007-06-05 22:20:14 +0000312 }
313
314 bool floodNTest(size_t loop=1, size_t count=100000) {
315
316 bool success = false;
317
318 for(size_t lix = 0; lix < loop; lix++) {
319
Roger Meier3faaedf2011-10-02 10:51:45 +0000320 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemkoa6479032007-06-05 22:20:14 +0000321 threadFactory.setDetached(true);
322
323 for(size_t tix = 0; tix < count; tix++) {
324
325 try {
326
327 shared_ptr<FloodTask> task(new FloodTask(lix * count + tix ));
328
329 shared_ptr<Thread> thread = threadFactory.newThread(task);
330
331 thread->start();
332
333 usleep(1);
334
335 } catch (TException& e) {
336
337 std::cout << "\t\t\tfailed to start " << lix * count + tix << " thread " << e.what() << std::endl;
338
339 return success;
340 }
341 }
342
343 std::cout << "\t\t\tflooded " << (lix + 1) * count << " threads" << std::endl;
344
345 success = true;
346 }
347
348 return success;
349 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000350};
Marc Slemko8a40a762006-07-19 17:46:50 +0000351
Marc Slemko6f038a72006-08-03 18:58:09 +0000352const double ThreadFactoryTests::ERROR = .20;
Marc Slemko8a40a762006-07-19 17:46:50 +0000353
T Jake Lucianib5e62212009-01-31 22:36:20 +0000354}}}} // apache::thrift::concurrency::test
Marc Slemko8a40a762006-07-19 17:46:50 +0000355