Skip to content

Commit 68d370b

Browse files
committed
CScheduler unit test
1 parent cfefe5b commit 68d370b

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ BITCOIN_TESTS =\
6060
test/pow_tests.cpp \
6161
test/rpc_tests.cpp \
6262
test/sanity_tests.cpp \
63+
test/scheduler_tests.cpp \
6364
test/script_P2SH_tests.cpp \
6465
test/script_tests.cpp \
6566
test/scriptnum_tests.cpp \

src/test/scheduler_tests.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright (c) 2012-2013 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include "random.h"
6+
#include "scheduler.h"
7+
8+
#include "test/test_bitcoin.h"
9+
10+
#include <boost/bind.hpp>
11+
#include <boost/random/mersenne_twister.hpp>
12+
#include <boost/random/uniform_int_distribution.hpp>
13+
#include <boost/thread.hpp>
14+
#include <boost/test/unit_test.hpp>
15+
16+
BOOST_AUTO_TEST_SUITE(scheduler_tests)
17+
18+
static void microTask(CScheduler& s, boost::mutex& mutex, int& counter, int delta, boost::chrono::system_clock::time_point rescheduleTime)
19+
{
20+
{
21+
boost::unique_lock<boost::mutex> lock(mutex);
22+
counter += delta;
23+
}
24+
boost::chrono::system_clock::time_point noTime = boost::chrono::system_clock::time_point::min();
25+
if (rescheduleTime != noTime) {
26+
CScheduler::Function f = boost::bind(&microTask, boost::ref(s), boost::ref(mutex), boost::ref(counter), -delta + 1, noTime);
27+
s.schedule(f, rescheduleTime);
28+
}
29+
}
30+
31+
static void MicroSleep(uint64_t n)
32+
{
33+
#if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
34+
boost::this_thread::sleep_for(boost::chrono::microseconds(n));
35+
#elif defined(HAVE_WORKING_BOOST_SLEEP)
36+
boost::this_thread::sleep(boost::posix_time::microseconds(n));
37+
#else
38+
//should never get here
39+
#error missing boost sleep implementation
40+
#endif
41+
}
42+
43+
BOOST_AUTO_TEST_CASE(manythreads)
44+
{
45+
// Stress test: hundreds of microsecond-scheduled tasks,
46+
// serviced by 10 threads.
47+
//
48+
// So... ten shared counters, which if all the tasks execute
49+
// properly will sum to the number of tasks done.
50+
// Each task adds or subtracts from one of the counters a
51+
// random amount, and then schedules another task 0-1000
52+
// microseconds in the future to subtract or add from
53+
// the counter -random_amount+1, so in the end the shared
54+
// counters should sum to the number of initial tasks performed.
55+
CScheduler microTasks;
56+
57+
boost::thread_group microThreads;
58+
for (int i = 0; i < 5; i++)
59+
microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
60+
61+
boost::mutex counterMutex[10];
62+
int counter[10] = { 0 };
63+
boost::random::mt19937 rng(insecure_rand());
64+
boost::random::uniform_int_distribution<> zeroToNine(0, 9);
65+
boost::random::uniform_int_distribution<> randomMsec(-11, 1000);
66+
boost::random::uniform_int_distribution<> randomDelta(-1000, 1000);
67+
68+
boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();
69+
boost::chrono::system_clock::time_point now = start;
70+
71+
for (int i = 0; i < 100; i++) {
72+
boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
73+
boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
74+
int whichCounter = zeroToNine(rng);
75+
CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
76+
boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
77+
randomDelta(rng), tReschedule);
78+
microTasks.schedule(f, t);
79+
}
80+
81+
MicroSleep(600);
82+
now = boost::chrono::system_clock::now();
83+
// More threads and more tasks:
84+
for (int i = 0; i < 5; i++)
85+
microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
86+
for (int i = 0; i < 100; i++) {
87+
boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
88+
boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
89+
int whichCounter = zeroToNine(rng);
90+
CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
91+
boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
92+
randomDelta(rng), tReschedule);
93+
microTasks.schedule(f, t);
94+
}
95+
96+
// All 2,000 tasks should be finished within 2 milliseconds. Sleep a bit longer.
97+
MicroSleep(2100);
98+
99+
microThreads.interrupt_all();
100+
microThreads.join_all();
101+
102+
int counterSum = 0;
103+
for (int i = 0; i < 10; i++) {
104+
BOOST_CHECK(counter[i] != 0);
105+
counterSum += counter[i];
106+
}
107+
BOOST_CHECK_EQUAL(counterSum, 200);
108+
}
109+
110+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)