aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGavin Andresen <gavinandresen@gmail.com>2015-04-10 10:31:02 -0400
committerGavin Andresen <gavinandresen@gmail.com>2015-05-14 12:50:41 -0400
commit68d370bec44dd6c0b9bdc76308de1a96fe34e5b8 (patch)
tree5c1afe95dcf1d8a47ae88e6f4faf1a6aac18a5d5 /src
parentcfefe5b88c57c08759492647b360c17126acb826 (diff)
CScheduler unit test
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/test/scheduler_tests.cpp110
2 files changed, 111 insertions, 0 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 9aec13ccef..3fba198d99 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -60,6 +60,7 @@ BITCOIN_TESTS =\
test/pow_tests.cpp \
test/rpc_tests.cpp \
test/sanity_tests.cpp \
+ test/scheduler_tests.cpp \
test/script_P2SH_tests.cpp \
test/script_tests.cpp \
test/scriptnum_tests.cpp \
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
new file mode 100644
index 0000000000..a26d0afaed
--- /dev/null
+++ b/src/test/scheduler_tests.cpp
@@ -0,0 +1,110 @@
+// Copyright (c) 2012-2013 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "random.h"
+#include "scheduler.h"
+
+#include "test/test_bitcoin.h"
+
+#include <boost/bind.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int_distribution.hpp>
+#include <boost/thread.hpp>
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(scheduler_tests)
+
+static void microTask(CScheduler& s, boost::mutex& mutex, int& counter, int delta, boost::chrono::system_clock::time_point rescheduleTime)
+{
+ {
+ boost::unique_lock<boost::mutex> lock(mutex);
+ counter += delta;
+ }
+ boost::chrono::system_clock::time_point noTime = boost::chrono::system_clock::time_point::min();
+ if (rescheduleTime != noTime) {
+ CScheduler::Function f = boost::bind(&microTask, boost::ref(s), boost::ref(mutex), boost::ref(counter), -delta + 1, noTime);
+ s.schedule(f, rescheduleTime);
+ }
+}
+
+static void MicroSleep(uint64_t n)
+{
+#if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
+ boost::this_thread::sleep_for(boost::chrono::microseconds(n));
+#elif defined(HAVE_WORKING_BOOST_SLEEP)
+ boost::this_thread::sleep(boost::posix_time::microseconds(n));
+#else
+ //should never get here
+ #error missing boost sleep implementation
+#endif
+}
+
+BOOST_AUTO_TEST_CASE(manythreads)
+{
+ // Stress test: hundreds of microsecond-scheduled tasks,
+ // serviced by 10 threads.
+ //
+ // So... ten shared counters, which if all the tasks execute
+ // properly will sum to the number of tasks done.
+ // Each task adds or subtracts from one of the counters a
+ // random amount, and then schedules another task 0-1000
+ // microseconds in the future to subtract or add from
+ // the counter -random_amount+1, so in the end the shared
+ // counters should sum to the number of initial tasks performed.
+ CScheduler microTasks;
+
+ boost::thread_group microThreads;
+ for (int i = 0; i < 5; i++)
+ microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
+
+ boost::mutex counterMutex[10];
+ int counter[10] = { 0 };
+ boost::random::mt19937 rng(insecure_rand());
+ boost::random::uniform_int_distribution<> zeroToNine(0, 9);
+ boost::random::uniform_int_distribution<> randomMsec(-11, 1000);
+ boost::random::uniform_int_distribution<> randomDelta(-1000, 1000);
+
+ boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();
+ boost::chrono::system_clock::time_point now = start;
+
+ for (int i = 0; i < 100; i++) {
+ boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
+ boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
+ int whichCounter = zeroToNine(rng);
+ CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
+ boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
+ randomDelta(rng), tReschedule);
+ microTasks.schedule(f, t);
+ }
+
+ MicroSleep(600);
+ now = boost::chrono::system_clock::now();
+ // More threads and more tasks:
+ for (int i = 0; i < 5; i++)
+ microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
+ for (int i = 0; i < 100; i++) {
+ boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
+ boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
+ int whichCounter = zeroToNine(rng);
+ CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
+ boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
+ randomDelta(rng), tReschedule);
+ microTasks.schedule(f, t);
+ }
+
+ // All 2,000 tasks should be finished within 2 milliseconds. Sleep a bit longer.
+ MicroSleep(2100);
+
+ microThreads.interrupt_all();
+ microThreads.join_all();
+
+ int counterSum = 0;
+ for (int i = 0; i < 10; i++) {
+ BOOST_CHECK(counter[i] != 0);
+ counterSum += counter[i];
+ }
+ BOOST_CHECK_EQUAL(counterSum, 200);
+}
+
+BOOST_AUTO_TEST_SUITE_END()