LCOV - code coverage report
Current view: top level - src/test - scheduler_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 50 50 100.0 %
Date: 2015-10-12 22:39:14 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           1 : BOOST_AUTO_TEST_SUITE(scheduler_tests)
      17             : 
      18         400 : 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         400 :         counter += delta;
      23             :     }
      24         400 :     boost::chrono::system_clock::time_point noTime = boost::chrono::system_clock::time_point::min();
      25         400 :     if (rescheduleTime != noTime) {
      26         400 :         CScheduler::Function f = boost::bind(&microTask, boost::ref(s), boost::ref(mutex), boost::ref(counter), -delta + 1, noTime);
      27         400 :         s.schedule(f, rescheduleTime);
      28             :     }
      29         400 : }
      30             : 
      31             : static void MicroSleep(uint64_t n)
      32             : {
      33             : #if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
      34           1 :     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           6 : BOOST_AUTO_TEST_CASE(manythreads)
      44             : {
      45           1 :     seed_insecure_rand(false);
      46             : 
      47             :     // Stress test: hundreds of microsecond-scheduled tasks,
      48             :     // serviced by 10 threads.
      49             :     //
      50             :     // So... ten shared counters, which if all the tasks execute
      51             :     // properly will sum to the number of tasks done.
      52             :     // Each task adds or subtracts from one of the counters a
      53             :     // random amount, and then schedules another task 0-1000
      54             :     // microseconds in the future to subtract or add from
      55             :     // the counter -random_amount+1, so in the end the shared
      56             :     // counters should sum to the number of initial tasks performed.
      57           1 :     CScheduler microTasks;
      58             : 
      59          21 :     boost::mutex counterMutex[10];
      60           1 :     int counter[10] = { 0 };
      61           2 :     boost::random::mt19937 rng(insecure_rand());
      62             :     boost::random::uniform_int_distribution<> zeroToNine(0, 9);
      63             :     boost::random::uniform_int_distribution<> randomMsec(-11, 1000);
      64             :     boost::random::uniform_int_distribution<> randomDelta(-1000, 1000);
      65             : 
      66           1 :     boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();
      67           1 :     boost::chrono::system_clock::time_point now = start;
      68             :     boost::chrono::system_clock::time_point first, last;
      69           1 :     size_t nTasks = microTasks.getQueueInfo(first, last);
      70           8 :     BOOST_CHECK(nTasks == 0);
      71             : 
      72         100 :     for (int i = 0; i < 100; i++) {
      73         200 :         boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
      74         200 :         boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
      75         100 :         int whichCounter = zeroToNine(rng);
      76             :         CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
      77             :                                              boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
      78         300 :                                              randomDelta(rng), tReschedule);
      79         200 :         microTasks.schedule(f, t);
      80             :     }
      81           1 :     nTasks = microTasks.getQueueInfo(first, last);
      82           8 :     BOOST_CHECK(nTasks == 100);
      83           8 :     BOOST_CHECK(first < last);
      84           8 :     BOOST_CHECK(last > now);
      85             : 
      86             :     // As soon as these are created they will start running and servicing the queue
      87           2 :     boost::thread_group microThreads;
      88           5 :     for (int i = 0; i < 5; i++)
      89           5 :         microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
      90             : 
      91             :     MicroSleep(600);
      92           2 :     now = boost::chrono::system_clock::now();
      93             : 
      94             :     // More threads and more tasks:
      95           6 :     for (int i = 0; i < 5; i++)
      96           5 :         microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
      97         100 :     for (int i = 0; i < 100; i++) {
      98         200 :         boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
      99         200 :         boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
     100         100 :         int whichCounter = zeroToNine(rng);
     101             :         CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
     102             :                                              boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
     103         300 :                                              randomDelta(rng), tReschedule);
     104         200 :         microTasks.schedule(f, t);
     105             :     }
     106             : 
     107             :     // Drain the task queue then exit threads
     108           1 :     microTasks.stop(true);
     109           1 :     microThreads.join_all(); // ... wait until all the threads are done
     110             : 
     111           1 :     int counterSum = 0;
     112          11 :     for (int i = 0; i < 10; i++) {
     113          80 :         BOOST_CHECK(counter[i] != 0);
     114          10 :         counterSum += counter[i];
     115             :     }
     116           6 :     BOOST_CHECK_EQUAL(counterSum, 200);
     117           1 : }
     118             : 
     119           3 : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.11