autoconf/automake/libtool-ized thrift cpp bits:
Fixed to build on solaris.
Used clock_gettime() where available
Fixed rounding of time to ms
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664733 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cpp/src/concurrency/Util.h b/lib/cpp/src/concurrency/Util.h
index 8467a2c..6e8891d 100644
--- a/lib/cpp/src/concurrency/Util.h
+++ b/lib/cpp/src/concurrency/Util.h
@@ -1,6 +1,8 @@
#if !defined(_concurrency_Util_h_)
#define _concurrency_Util_h_ 1
+#include <config.h>
+
#include <assert.h>
#include <stddef.h>
#include <sys/time.h>
@@ -18,6 +20,12 @@
class Util {
+ static const long long NS_PER_S = 1000000000LL;
+
+ static const long long MS_PER_S = 1000LL;
+
+ static const long long NS_PER_MS = 1000000LL;
+
public:
/** Converts timespec to milliseconds
@@ -26,28 +34,39 @@
@param time or duration in milliseconds */
static void toTimespec(struct timespec& result, long long value) {
+
+ result.tv_sec = value / MS_PER_S; // ms to s
- result.tv_sec = value / 1000; // ms to s
-
- result.tv_nsec = (value % 1000) * 1000000; // ms to ns
+ result.tv_nsec = (value % MS_PER_S) * NS_PER_MS; // ms to ns
}
/** Converts timespec to milliseconds */
static const void toMilliseconds(long long& result, const struct timespec& value) {
- result = value.tv_sec * 1000 + value.tv_nsec / 1000000;
+ result = (value.tv_sec * MS_PER_S) + (value.tv_nsec / NS_PER_MS) + (value.tv_nsec % NS_PER_MS >= 500000 ? 1 : 0) ;
}
/** Get current time as milliseconds from epoch */
static const long long currentTime() {
+#if defined(HAVE_CLOCK_GETTIME)
+
+ struct timespec now;
+
+ assert(clock_gettime(&now, NULL) == 0);
+
+ return = (now.tv_sec * MS_PER_S) + (now.tv_nsec / NS_PER_MS) + (now.tv_nsec % NS_PER_MS >= 500000 ? 1 : 0) ;
+
+#elif defined(HAVE_GETTIMEOFDAY)
+
struct timeval now;
assert(gettimeofday(&now, NULL) == 0);
- return ((long long)now.tv_sec) * 1000LL + now.tv_usec / 1000;
+ return (((long long)now.tv_sec) * MS_PER_S) + (now.tv_usec / MS_PER_S) + (now.tv_usec % MS_PER_S >= 500 ? 1 : 0);
+#endif // defined(HAVE_GETTIMEDAY)
}
};
diff --git a/lib/cpp/src/concurrency/test/Tests.cc b/lib/cpp/src/concurrency/test/Tests.cc
index 19e1f4a..5c4dd24 100644
--- a/lib/cpp/src/concurrency/test/Tests.cc
+++ b/lib/cpp/src/concurrency/test/Tests.cc
@@ -1,4 +1,5 @@
#include <iostream>
+#include <vector>
#include <string>
#include "ThreadFactoryTests.h"
@@ -9,27 +10,22 @@
std::string arg;
- if(argc < 2) {
+ std::vector<std::string> args(argc - 1 > 1 ? argc - 1 : 1);
- arg = "all";
+ args[0] = "all";
- } else {
-
- arg = std::string(argv[1]);
+ for(int ix = 1; ix < argc; ix++) {
+ args[ix - 1] = std::string(argv[ix]);
}
- bool runAll = arg.compare("all") == 0;
+ bool runAll = args[0].compare("all") == 0;
- if(runAll || arg.compare("thread-factory") == 0) {
+ if(runAll || args[0].compare("thread-factory") == 0) {
ThreadFactoryTests threadFactoryTests;
std::cout << "ThreadFactory tests..." << std::endl;
- std::cout << "\tThreadFactory hello-world test" << std::endl;
-
- assert(threadFactoryTests.helloWorldTest());
-
size_t count = 1000;
std::cout << "\t\tThreadFactory reap N threads test: N = " << count << std::endl;
@@ -39,9 +35,37 @@
std::cout << "\t\tThreadFactory synchronous start test" << std::endl;
assert(threadFactoryTests.synchStartTest());
+
+ std::cout << "\t\tThreadFactory monitor timeout test" << std::endl;
+
+ assert(threadFactoryTests.monitorTimeoutTest());
}
- if(runAll || arg.compare("timer-manager") == 0) {
+ if(runAll || args[0].compare("util") == 0) {
+
+ std::cout << "Util tests..." << std::endl;
+
+ std::cout << "\t\tUtil minimum time" << std::endl;
+
+ long long time00 = Util::currentTime();
+ long long time01 = Util::currentTime();
+
+ std::cout << "\t\t\tMinimum time: " << time01 - time00 << "ms" << std::endl;
+
+ time00 = Util::currentTime();
+ time01 = time00;
+ size_t count = 0;
+
+ while(time01 < time00 + 10) {
+ count++;
+ time01 = Util::currentTime();
+ }
+
+ std::cout << "\t\t\tscall per ms: " << count / (time01 - time00) << std::endl;
+ }
+
+
+ if(runAll || args[0].compare("timer-manager") == 0) {
std::cout << "TimerManager tests..." << std::endl;
@@ -52,21 +76,51 @@
assert(timerManagerTests.test00());
}
- if(runAll || arg.compare("thread-manager") == 0) {
+ if(runAll || args[0].compare("thread-manager") == 0) {
std::cout << "ThreadManager tests..." << std::endl;
- size_t workerCount = 100;
+ {
- size_t taskCount = 100000;
+ size_t workerCount = 100;
- long long delay = 10LL;
+ size_t taskCount = 100000;
- std::cout << "\t\tThreadManager load test: worker count: " << workerCount << " task count: " << taskCount << " delay: " << delay << std::endl;
+ long long delay = 10LL;
- ThreadManagerTests threadManagerTests;
+ std::cout << "\t\tThreadManager load test: worker count: " << workerCount << " task count: " << taskCount << " delay: " << delay << std::endl;
- assert(threadManagerTests.loadTest(taskCount, delay, workerCount));
+ ThreadManagerTests threadManagerTests;
+
+ assert(threadManagerTests.loadTest(taskCount, delay, workerCount));
+ }
+ }
+
+ if(runAll || args[0].compare("thread-manager-benchmark") == 0) {
+
+ std::cout << "ThreadManager benchmark tests..." << std::endl;
+
+ {
+
+ size_t minWorkerCount = 2;
+
+ size_t maxWorkerCount = 512;
+
+ size_t tasksPerWorker = 1000;
+
+ long long delay = 10LL;
+
+ for(size_t workerCount = minWorkerCount; workerCount < maxWorkerCount; workerCount*= 2) {
+
+ size_t taskCount = workerCount * tasksPerWorker;
+
+ std::cout << "\t\tThreadManager load test: worker count: " << workerCount << " task count: " << taskCount << " delay: " << delay << std::endl;
+
+ ThreadManagerTests threadManagerTests;
+
+ threadManagerTests.loadTest(taskCount, delay, workerCount);
+ }
+ }
}
}
diff --git a/lib/cpp/src/concurrency/test/ThreadFactoryTests.h b/lib/cpp/src/concurrency/test/ThreadFactoryTests.h
index 1e0b139..d1ec0df 100644
--- a/lib/cpp/src/concurrency/test/ThreadFactoryTests.h
+++ b/lib/cpp/src/concurrency/test/ThreadFactoryTests.h
@@ -1,6 +1,7 @@
#include <Thread.h>
#include <PosixThreadFactory.h>
#include <Monitor.h>
+#include <Util.h>
#include <assert.h>
#include <iostream>
@@ -216,9 +217,42 @@
assert(state == SynchStartTask::STOPPED);
+ bool success = true;
+
+ std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "!" << std::endl;
+
return true;
}
+ /** See how accurate monitor timeout is. */
+
+ bool monitorTimeoutTest(size_t count=1000, long long timeout=10) {
+
+ Monitor monitor;
+
+ long long startTime = Util::currentTime();
+
+ for(size_t ix = 0; ix < count; ix++) {
+ {Synchronized s(monitor);
+ monitor.wait(timeout);
+ }
+ }
+
+ long long endTime = Util::currentTime();
+
+ double error = ((endTime - startTime) - (count * timeout)) / (double)(count * timeout);
+
+ if(error < 0.0) {
+
+ error *= 1.0;
+ }
+
+ bool success = error < .10;
+
+ std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "! expected time: " << count * timeout << "ms elapsed time: "<< endTime - startTime << "ms error%: " << error * 100.0 << std::endl;
+
+ return success;
+ }
};
diff --git a/lib/cpp/src/concurrency/test/ThreadManagerTests.h b/lib/cpp/src/concurrency/test/ThreadManagerTests.h
index 6132571..8b2dda8 100644
--- a/lib/cpp/src/concurrency/test/ThreadManagerTests.h
+++ b/lib/cpp/src/concurrency/test/ThreadManagerTests.h
@@ -1,3 +1,4 @@
+#include <config.h>
#include <ThreadManager.h>
#include <PosixThreadFactory.h>
#include <Monitor.h>
@@ -6,6 +7,8 @@
#include <assert.h>
#include <set>
#include <iostream>
+#include <set>
+#include <stdint.h>
namespace facebook { namespace thrift { namespace concurrency { namespace test {
@@ -32,29 +35,16 @@
void run() {
- Monitor sleep;
+ _startTime = Util::currentTime();
- {Synchronized s(sleep);
+ {Synchronized s(_sleep);
- long long time00 = Util::currentTime();
- sleep.wait(_timeout);
-
- long long time01 = Util::currentTime();
-
- double error = ((time01 - time00) - _timeout) / (double)_timeout;
-
- if(error < 0.0) {
-
- error*= -1.0;
- }
-
- if(error > .20) {
-
- assert(false);
- }
+ _sleep.wait(_timeout);
}
+ _endTime = Util::currentTime();
+
_done = true;
{Synchronized s(_monitor);
@@ -73,7 +63,10 @@
Monitor& _monitor;
size_t& _count;
long long _timeout;
+ long long _startTime;
+ long long _endTime;
bool _done;
+ Monitor _sleep;
};
/** Dispatch count tasks, each of which blocks for timeout milliseconds then completes.
@@ -86,8 +79,12 @@
size_t activeCount = count;
ThreadManager* threadManager = ThreadManager::newSimpleThreadManager(workerCount);
+
+ PosixThreadFactory* threadFactory = new PosixThreadFactory();
+
+ threadFactory->priority(PosixThreadFactory::HIGHEST);
- threadManager->threadFactory(new PosixThreadFactory());
+ threadManager->threadFactory(threadFactory);
threadManager->start();
@@ -115,11 +112,45 @@
long long time01 = Util::currentTime();
+ long long firstTime = 9223372036854775807LL;
+ long long lastTime = 0;
+
+ double averageTime = 0;
+ long long minTime = 9223372036854775807LL;
+ long long maxTime = 0;
+
for(std::set<ThreadManagerTests::Task*>::iterator ix = tasks.begin(); ix != tasks.end(); ix++) {
+
+ ThreadManagerTests::Task* task = *ix;
+
+ long long delta = task->_endTime - task->_startTime;
+
+ assert(delta > 0);
+
+ if(task->_startTime < firstTime) {
+ firstTime = task->_startTime;
+ }
+
+ if(task->_endTime > lastTime) {
+ lastTime = task->_endTime;
+ }
+
+ if(delta < minTime) {
+ minTime = delta;
+ }
+
+ if(delta > maxTime) {
+ maxTime = delta;
+ }
+
+ averageTime+= delta;
delete *ix;
-
}
+
+ averageTime /= count;
+
+ std::cout << "\t\t\tfirst start: " << firstTime << "ms Last end: " << lastTime << "ms min: " << minTime << "ms max: " << maxTime << "ms average: " << averageTime << "ms" << std::endl;
double expectedTime = ((count + (workerCount - 1)) / workerCount) * timeout;
@@ -133,9 +164,11 @@
delete threadManager;
+ delete threadFactory;
+
std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "! expected time: " << expectedTime << "ms elapsed time: "<< time01 - time00 << "ms error%: " << error * 100.0 << std::endl;
- return true;
+ return success;
}
};