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
Konrad Grochowski240120c2014-11-18 11:33:31 +010030namespace 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:
Konrad Grochowski240120c2014-11-18 11:33:31 +010043
Konrad Grochowski293a40e2014-09-04 17:28:17 +040044 static const double TEST_TOLERANCE;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000045
Konrad Grochowski240120c2014-11-18 11:33:31 +010046 class Task: public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +000047
48 public:
Konrad Grochowski240120c2014-11-18 11:33:31 +010049
Marc Slemko8a40a762006-07-19 17:46:50 +000050 Task() {}
51
Konrad Grochowski240120c2014-11-18 11:33:31 +010052 void run() {
53 std::cout << "\t\t\tHello World" << std::endl;
54 }
Marc Slemko8a40a762006-07-19 17:46:50 +000055 };
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 */
Konrad Grochowski240120c2014-11-18 11:33:31 +010080 class ReapNTask: public Runnable {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000081
Konrad Grochowski240120c2014-11-18 11:33:31 +010082 public:
83
84 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
Konrad Grochowski240120c2014-11-18 11:33:31 +010093 //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
Konrad Grochowski240120c2014-11-18 11:33:31 +0100105 bool reapNThreads(int loop=1, int count=10) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000106
Konrad Grochowski240120c2014-11-18 11:33:31 +0100107 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
Konrad Grochowski240120c2014-11-18 11:33:31 +0100111 for(int lix = 0; lix < loop; lix++) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000112
Konrad Grochowski240120c2014-11-18 11:33:31 +0100113 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 {
Konrad Grochowski240120c2014-11-18 11:33:31 +0100121 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;
Marc Slemko67606e52007-06-04 21:01:19 +0000124 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;
Konrad Grochowski240120c2014-11-18 11:33:31 +0100129 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();
Konrad Grochowski240120c2014-11-18 11:33:31 +0100133 } catch(SystemResourceException& e) {
134 std::cout << "\t\t\tfailed to start " << lix * count + tix << " thread " << e.what() << std::endl;
Marc Slemko67606e52007-06-04 21:01:19 +0000135 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;
Konrad Grochowski240120c2014-11-18 11:33:31 +0100146 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
Konrad Grochowski240120c2014-11-18 11:33:31 +0100154 class SynchStartTask: public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +0000155
Konrad Grochowski240120c2014-11-18 11:33:31 +0100156 public:
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000157
Konrad Grochowski240120c2014-11-18 11:33:31 +0100158 enum STATE {
159 UNINITIALIZED,
160 STARTING,
161 STARTED,
162 STOPPING,
163 STOPPED
164 };
165
166 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
Konrad Grochowski240120c2014-11-18 11:33:31 +0100192 private:
Marc Slemko8a40a762006-07-19 17:46:50 +0000193 Monitor& _monitor;
Konrad Grochowski240120c2014-11-18 11:33:31 +0100194 volatile STATE& _state;
Marc Slemko8a40a762006-07-19 17:46:50 +0000195 };
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
Konrad Grochowski240120c2014-11-18 11:33:31 +0100203 shared_ptr<SynchStartTask> task = shared_ptr<SynchStartTask>(new SynchStartTask(monitor, state));
Marc Slemko8a40a762006-07-19 17:46:50 +0000204
Konrad Grochowski240120c2014-11-18 11:33:31 +0100205 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 {
Konrad Grochowski240120c2014-11-18 11:33:31 +0100229 monitor.wait(100);
230 } catch(TimedOutException& e) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000231 }
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
Konrad Grochowski240120c2014-11-18 11:33:31 +0100256 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 {
Konrad Grochowski240120c2014-11-18 11:33:31 +0100266 monitor.wait(timeout);
267 } catch(TimedOutException& e) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000268 }
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
Konrad Grochowski240120c2014-11-18 11:33:31 +0100276 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
Konrad Grochowski240120c2014-11-18 11:33:31 +0100283 std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "! expected time: " << count * timeout << "ms elapsed time: "<< endTime - startTime << "ms error%: " << error * 100.0 << std::endl;
Marc Slemkoc7782972006-07-25 02:26:35 +0000284
285 return success;
286 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000287
Konrad Grochowski240120c2014-11-18 11:33:31 +0100288
Marc Slemkoa6479032007-06-05 22:20:14 +0000289 class FloodTask : public Runnable {
290 public:
Konrad Grochowski240120c2014-11-18 11:33:31 +0100291
292 FloodTask(const size_t id) :_id(id) {}
293 ~FloodTask(){
294 if(_id % 1000 == 0) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000295 std::cout << "\t\tthread " << _id << " done" << std::endl;
296 }
297 }
298
Konrad Grochowski240120c2014-11-18 11:33:31 +0100299 void run(){
300 if(_id % 1000 == 0) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000301 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
Konrad Grochowski240120c2014-11-18 11:33:31 +0100309 void foo(PlatformThreadFactory *tf) {
310 (void) tf;
311 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000312
Konrad Grochowski240120c2014-11-18 11:33:31 +0100313 bool floodNTest(size_t loop=1, size_t count=100000) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000314
315 bool success = false;
316
Konrad Grochowski240120c2014-11-18 11:33:31 +0100317 for(size_t lix = 0; lix < loop; lix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000318
Roger Meier3faaedf2011-10-02 10:51:45 +0000319 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemkoa6479032007-06-05 22:20:14 +0000320 threadFactory.setDetached(true);
321
Konrad Grochowski240120c2014-11-18 11:33:31 +0100322 for(size_t tix = 0; tix < count; tix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000323
Konrad Grochowski240120c2014-11-18 11:33:31 +0100324 try {
Marc Slemkoa6479032007-06-05 22:20:14 +0000325
Konrad Grochowski240120c2014-11-18 11:33:31 +0100326 shared_ptr<FloodTask> task(new FloodTask(lix * count + tix ));
Marc Slemkoa6479032007-06-05 22:20:14 +0000327
Konrad Grochowski240120c2014-11-18 11:33:31 +0100328 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemkoa6479032007-06-05 22:20:14 +0000329
Konrad Grochowski240120c2014-11-18 11:33:31 +0100330 thread->start();
Marc Slemkoa6479032007-06-05 22:20:14 +0000331
Konrad Grochowski240120c2014-11-18 11:33:31 +0100332 THRIFT_SLEEP_USEC(1);
Marc Slemkoa6479032007-06-05 22:20:14 +0000333
Konrad Grochowski240120c2014-11-18 11:33:31 +0100334 } catch (TException& e) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000335
Konrad Grochowski240120c2014-11-18 11:33:31 +0100336 std::cout << "\t\t\tfailed to start " << lix * count + tix << " thread " << e.what() << std::endl;
Marc Slemkoa6479032007-06-05 22:20:14 +0000337
Konrad Grochowski240120c2014-11-18 11:33:31 +0100338 return success;
339 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000340 }
341
Konrad Grochowski240120c2014-11-18 11:33:31 +0100342 std::cout << "\t\t\tflooded " << (lix + 1) * count << " threads" << std::endl;
Marc Slemkoa6479032007-06-05 22:20:14 +0000343
Konrad Grochowski240120c2014-11-18 11:33:31 +0100344 success = true;
Marc Slemkoa6479032007-06-05 22:20:14 +0000345 }
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;
Konrad Grochowski240120c2014-11-18 11:33:31 +0100352
353}}}} // apache::thrift::concurrency::test