blob: d7431a803e8b1e4886d0c2f9931b91e22e765c24 [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 Grochowski16a23a62014-11-13 15:33:38 +010030namespace apache {
31namespace thrift {
32namespace concurrency {
33namespace test {
Marc Slemko8a40a762006-07-19 17:46:50 +000034
Mark Slee5ea15f92007-03-05 22:55:59 +000035using boost::shared_ptr;
T Jake Lucianib5e62212009-01-31 22:36:20 +000036using namespace apache::thrift::concurrency;
Marc Slemko8a40a762006-07-19 17:46:50 +000037
Mark Sleef5f2be42006-09-05 21:05:31 +000038/**
Marc Slemko3a3b53b2007-05-22 23:59:54 +000039 * ThreadManagerTests class
Mark Sleef5f2be42006-09-05 21:05:31 +000040 *
Mark Sleef5f2be42006-09-05 21:05:31 +000041 * @version $Id:$
42 */
Marc Slemko8a40a762006-07-19 17:46:50 +000043class ThreadFactoryTests {
44
Marc Slemko6f038a72006-08-03 18:58:09 +000045public:
Konrad Grochowski293a40e2014-09-04 17:28:17 +040046 static const double TEST_TOLERANCE;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000047
Konrad Grochowski16a23a62014-11-13 15:33:38 +010048 class Task : public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +000049
50 public:
Marc Slemko8a40a762006-07-19 17:46:50 +000051 Task() {}
52
Konrad Grochowski16a23a62014-11-13 15:33:38 +010053 void run() { std::cout << "\t\t\tHello World" << std::endl; }
Marc Slemko8a40a762006-07-19 17:46:50 +000054 };
55
Mark Sleef5f2be42006-09-05 21:05:31 +000056 /**
57 * Hello world test
58 */
Marc Slemko8a40a762006-07-19 17:46:50 +000059 bool helloWorldTest() {
60
Roger Meier3faaedf2011-10-02 10:51:45 +000061 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +000062
Marc Slemko6f038a72006-08-03 18:58:09 +000063 shared_ptr<Task> task = shared_ptr<Task>(new ThreadFactoryTests::Task());
Marc Slemko8a40a762006-07-19 17:46:50 +000064
Marc Slemko6f038a72006-08-03 18:58:09 +000065 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemko8a40a762006-07-19 17:46:50 +000066
67 thread->start();
68
69 thread->join();
70
Marc Slemko8a40a762006-07-19 17:46:50 +000071 std::cout << "\t\t\tSuccess!" << std::endl;
72
73 return true;
74 }
75
Mark Sleef5f2be42006-09-05 21:05:31 +000076 /**
77 * Reap N threads
78 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +010079 class ReapNTask : public Runnable {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000080
Konrad Grochowski16a23a62014-11-13 15:33:38 +010081 public:
82 ReapNTask(Monitor& monitor, int& activeCount) : _monitor(monitor), _count(activeCount) {}
Marc Slemko3a3b53b2007-05-22 23:59:54 +000083
Marc Slemko8a40a762006-07-19 17:46:50 +000084 void run() {
Mark Sleef5f2be42006-09-05 21:05:31 +000085 Synchronized s(_monitor);
Marc Slemko3a3b53b2007-05-22 23:59:54 +000086
Mark Sleef5f2be42006-09-05 21:05:31 +000087 _count--;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000088
Konrad Grochowski16a23a62014-11-13 15:33:38 +010089 // std::cout << "\t\t\tthread count: " << _count << std::endl;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000090
Mark Sleef5f2be42006-09-05 21:05:31 +000091 if (_count == 0) {
92 _monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +000093 }
94 }
95
96 Monitor& _monitor;
97
98 int& _count;
99 };
100
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100101 bool reapNThreads(int loop = 1, int count = 10) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000102
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100103 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +0000104
Marc Slemko67606e52007-06-04 21:01:19 +0000105 Monitor* monitor = new Monitor();
Marc Slemko8a40a762006-07-19 17:46:50 +0000106
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100107 for (int lix = 0; lix < loop; lix++) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000108
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100109 int* activeCount = new int(count);
Marc Slemko8a40a762006-07-19 17:46:50 +0000110
Marc Slemko67606e52007-06-04 21:01:19 +0000111 std::set<shared_ptr<Thread> > threads;
Marc Slemko8a40a762006-07-19 17:46:50 +0000112
Marc Slemko67606e52007-06-04 21:01:19 +0000113 int tix;
Marc Slemko8a40a762006-07-19 17:46:50 +0000114
Marc Slemko67606e52007-06-04 21:01:19 +0000115 for (tix = 0; tix < count; tix++) {
116 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100117 threads.insert(
118 threadFactory.newThread(shared_ptr<Runnable>(new ReapNTask(*monitor, *activeCount))));
119 } catch (SystemResourceException& e) {
120 std::cout << "\t\t\tfailed to create " << lix* count + tix << " thread " << e.what()
121 << std::endl;
Marc Slemko67606e52007-06-04 21:01:19 +0000122 throw e;
123 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000124 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000125
Marc Slemko67606e52007-06-04 21:01:19 +0000126 tix = 0;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100127 for (std::set<shared_ptr<Thread> >::const_iterator thread = threads.begin();
128 thread != threads.end();
129 tix++, ++thread) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000130
Marc Slemko67606e52007-06-04 21:01:19 +0000131 try {
132 (*thread)->start();
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100133 } catch (SystemResourceException& e) {
134 std::cout << "\t\t\tfailed to start " << lix* count + tix << " thread " << e.what()
135 << std::endl;
Marc Slemko67606e52007-06-04 21:01:19 +0000136 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;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100147 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
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100155 class SynchStartTask : public Runnable {
Marc Slemko8a40a762006-07-19 17:46:50 +0000156
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100157 public:
158 enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000159
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100160 SynchStartTask(Monitor& monitor, volatile STATE& state) : _monitor(monitor), _state(state) {}
Marc Slemko8a40a762006-07-19 17:46:50 +0000161
162 void run() {
Mark Sleef5f2be42006-09-05 21:05:31 +0000163 {
164 Synchronized s(_monitor);
David Reiss96d23882007-07-26 21:10:32 +0000165 if (_state == SynchStartTask::STARTING) {
166 _state = SynchStartTask::STARTED;
167 _monitor.notify();
168 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000169 }
170
Mark Sleef5f2be42006-09-05 21:05:31 +0000171 {
172 Synchronized s(_monitor);
173 while (_state == SynchStartTask::STARTED) {
David Reiss96d23882007-07-26 21:10:32 +0000174 _monitor.wait();
175 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000176
David Reiss96d23882007-07-26 21:10:32 +0000177 if (_state == SynchStartTask::STOPPING) {
Mark Sleef5f2be42006-09-05 21:05:31 +0000178 _state = SynchStartTask::STOPPED;
179 _monitor.notifyAll();
David Reiss96d23882007-07-26 21:10:32 +0000180 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000181 }
182 }
183
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100184 private:
Marc Slemko8a40a762006-07-19 17:46:50 +0000185 Monitor& _monitor;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100186 volatile STATE& _state;
Marc Slemko8a40a762006-07-19 17:46:50 +0000187 };
188
189 bool synchStartTest() {
190
191 Monitor monitor;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000192
Marc Slemko8a40a762006-07-19 17:46:50 +0000193 SynchStartTask::STATE state = SynchStartTask::UNINITIALIZED;
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000194
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100195 shared_ptr<SynchStartTask> task
196 = shared_ptr<SynchStartTask>(new SynchStartTask(monitor, state));
Marc Slemko8a40a762006-07-19 17:46:50 +0000197
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100198 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemko8a40a762006-07-19 17:46:50 +0000199
Marc Slemko6f038a72006-08-03 18:58:09 +0000200 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemko8a40a762006-07-19 17:46:50 +0000201
Mark Sleef5f2be42006-09-05 21:05:31 +0000202 if (state == SynchStartTask::UNINITIALIZED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000203
204 state = SynchStartTask::STARTING;
205
206 thread->start();
207 }
208
Mark Sleef5f2be42006-09-05 21:05:31 +0000209 {
210 Synchronized s(monitor);
211 while (state == SynchStartTask::STARTING) {
David Reiss96d23882007-07-26 21:10:32 +0000212 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000213 }
214 }
215
216 assert(state != SynchStartTask::STARTING);
217
Mark Sleef5f2be42006-09-05 21:05:31 +0000218 {
219 Synchronized s(monitor);
Marc Slemko8a40a762006-07-19 17:46:50 +0000220
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000221 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100222 monitor.wait(100);
223 } catch (TimedOutException& e) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000224 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000225
Mark Sleef5f2be42006-09-05 21:05:31 +0000226 if (state == SynchStartTask::STARTED) {
Marc Slemko8a40a762006-07-19 17:46:50 +0000227
David Reiss96d23882007-07-26 21:10:32 +0000228 state = SynchStartTask::STOPPING;
Marc Slemko8a40a762006-07-19 17:46:50 +0000229
David Reiss96d23882007-07-26 21:10:32 +0000230 monitor.notify();
Marc Slemko8a40a762006-07-19 17:46:50 +0000231 }
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000232
Mark Sleef5f2be42006-09-05 21:05:31 +0000233 while (state == SynchStartTask::STOPPING) {
David Reiss96d23882007-07-26 21:10:32 +0000234 monitor.wait();
Marc Slemko8a40a762006-07-19 17:46:50 +0000235 }
236 }
237
238 assert(state == SynchStartTask::STOPPED);
239
Marc Slemkoc7782972006-07-25 02:26:35 +0000240 bool success = true;
241
242 std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "!" << std::endl;
243
Marc Slemko8a40a762006-07-19 17:46:50 +0000244 return true;
245 }
246
Marc Slemkoc7782972006-07-25 02:26:35 +0000247 /** See how accurate monitor timeout is. */
248
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100249 bool monitorTimeoutTest(size_t count = 1000, int64_t timeout = 10) {
Marc Slemkoc7782972006-07-25 02:26:35 +0000250
251 Monitor monitor;
252
Mark Slee9b82d272007-05-23 05:16:07 +0000253 int64_t startTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000254
Mark Sleef5f2be42006-09-05 21:05:31 +0000255 for (size_t ix = 0; ix < count; ix++) {
256 {
257 Synchronized s(monitor);
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000258 try {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100259 monitor.wait(timeout);
260 } catch (TimedOutException& e) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +0000261 }
Marc Slemkoc7782972006-07-25 02:26:35 +0000262 }
263 }
264
Mark Slee9b82d272007-05-23 05:16:07 +0000265 int64_t endTime = Util::currentTime();
Marc Slemkoc7782972006-07-25 02:26:35 +0000266
267 double error = ((endTime - startTime) - (count * timeout)) / (double)(count * timeout);
268
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100269 if (error < 0.0) {
Marc Slemkoc7782972006-07-25 02:26:35 +0000270
271 error *= 1.0;
272 }
273
Konrad Grochowski293a40e2014-09-04 17:28:17 +0400274 bool success = error < ThreadFactoryTests::TEST_TOLERANCE;
Marc Slemkoc7782972006-07-25 02:26:35 +0000275
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100276 std::cout << "\t\t\t" << (success ? "Success" : "Failure")
277 << "! expected time: " << count * timeout
278 << "ms elapsed time: " << endTime - startTime << "ms error%: " << error * 100.0
279 << std::endl;
Marc Slemkoc7782972006-07-25 02:26:35 +0000280
281 return success;
282 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000283
Marc Slemkoa6479032007-06-05 22:20:14 +0000284 class FloodTask : public Runnable {
285 public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100286 FloodTask(const size_t id) : _id(id) {}
287 ~FloodTask() {
288 if (_id % 1000 == 0) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000289 std::cout << "\t\tthread " << _id << " done" << std::endl;
290 }
291 }
292
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100293 void run() {
294 if (_id % 1000 == 0) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000295 std::cout << "\t\tthread " << _id << " started" << std::endl;
296 }
297
Konrad Grochowski293a40e2014-09-04 17:28:17 +0400298 THRIFT_SLEEP_USEC(1);
Marc Slemkoa6479032007-06-05 22:20:14 +0000299 }
300 const size_t _id;
301 };
302
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100303 void foo(PlatformThreadFactory* tf) { (void)tf; }
Marc Slemkoa6479032007-06-05 22:20:14 +0000304
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100305 bool floodNTest(size_t loop = 1, size_t count = 100000) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000306
307 bool success = false;
308
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100309 for (size_t lix = 0; lix < loop; lix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000310
Roger Meier3faaedf2011-10-02 10:51:45 +0000311 PlatformThreadFactory threadFactory = PlatformThreadFactory();
Marc Slemkoa6479032007-06-05 22:20:14 +0000312 threadFactory.setDetached(true);
313
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100314 for (size_t tix = 0; tix < count; tix++) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000315
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100316 try {
Marc Slemkoa6479032007-06-05 22:20:14 +0000317
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100318 shared_ptr<FloodTask> task(new FloodTask(lix * count + tix));
Marc Slemkoa6479032007-06-05 22:20:14 +0000319
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100320 shared_ptr<Thread> thread = threadFactory.newThread(task);
Marc Slemkoa6479032007-06-05 22:20:14 +0000321
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100322 thread->start();
Marc Slemkoa6479032007-06-05 22:20:14 +0000323
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100324 THRIFT_SLEEP_USEC(1);
Marc Slemkoa6479032007-06-05 22:20:14 +0000325
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100326 } catch (TException& e) {
Marc Slemkoa6479032007-06-05 22:20:14 +0000327
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100328 std::cout << "\t\t\tfailed to start " << lix* count + tix << " thread " << e.what()
329 << std::endl;
Marc Slemkoa6479032007-06-05 22:20:14 +0000330
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100331 return success;
Marc Slemkoa6479032007-06-05 22:20:14 +0000332 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100333 }
Marc Slemkoa6479032007-06-05 22:20:14 +0000334
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100335 std::cout << "\t\t\tflooded " << (lix + 1) * count << " threads" << std::endl;
Marc Slemkoa6479032007-06-05 22:20:14 +0000336
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100337 success = true;
Marc Slemkoa6479032007-06-05 22:20:14 +0000338 }
339
340 return success;
341 }
Marc Slemko8a40a762006-07-19 17:46:50 +0000342};
Marc Slemko8a40a762006-07-19 17:46:50 +0000343
Konrad Grochowski293a40e2014-09-04 17:28:17 +0400344const double ThreadFactoryTests::TEST_TOLERANCE = .20;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100345}
346}
347}
348} // apache::thrift::concurrency::test