reSIProcate/rutil  9694
Classes | Defines | Typedefs | Functions
testRandomThread.cxx File Reference
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <vector>
#include <memory>
#include <set>
#include "rutil/Random.hxx"
#include "rutil/Time.hxx"
#include "rutil/Lock.hxx"
Include dependency graph for testRandomThread.cxx:

Go to the source code of this file.

Classes

class  Barrier
class  TestDummyThread
class  TestRandomThread

Defines

#define RANDINT_PER_CYCLE   (1000000)
 Helper to test the speed of of the random generator.
#define RANDSEQ_PER_CYCLE   (1000)

Typedefs

typedef std::set< DataDataSet

Functions

static UInt64 doSingleTest (int numCycles)
static int mergeCheckRandoms (DataSet &all, const DataSet &more)
static UInt64 doThreadedTest (int numCycles, int numThreads, int storeBytes)
static void doVariationTest (int numCycles, int numThreads, int numPass, int storeBytes)
int main (int argc, char **argv)

Define Documentation

#define RANDINT_PER_CYCLE   (1000000)

Helper to test the speed of of the random generator.

Used to optimize the different flavors.

Definition at line 18 of file testRandomThread.cxx.

Referenced by TestRandomThread::makeRandoms().

#define RANDSEQ_PER_CYCLE   (1000)

Definition at line 19 of file testRandomThread.cxx.

Referenced by TestRandomThread::makeAndStoreRandoms().


Typedef Documentation

typedef std::set<Data> DataSet

Definition at line 80 of file testRandomThread.cxx.


Function Documentation

static UInt64 doSingleTest ( int  numCycles) [static]

Definition at line 162 of file testRandomThread.cxx.

References TestRandomThread::makeRandoms().

Referenced by doVariationTest().

{
   UInt64 startUs = ResipClock::getTimeMicroSec();
   TestRandomThread::makeRandoms(numCycles);
   UInt64 doneUs = ResipClock::getTimeMicroSec();
   return doneUs - startUs;
}

Here is the call graph for this function:

static UInt64 doThreadedTest ( int  numCycles,
int  numThreads,
int  storeBytes 
) [static]

Definition at line 193 of file testRandomThread.cxx.

References TestRandomThread::getDupCnt(), TestRandomThread::getRandoms(), resip::ThreadIf::join(), mergeCheckRandoms(), resip::ThreadIf::run(), and Barrier::sync().

Referenced by doVariationTest().

{
   std::vector<TestRandomThread*> threadList;
   Barrier bar(numThreads);
   int pidx;
   for (pidx=0; pidx < numThreads; pidx++)
   {
      TestRandomThread* rth = new TestRandomThread(numCycles,bar, storeBytes);
      rth->run();
      threadList.push_back(rth);
   }
   // std::cerr << "Threads started." << std::endl;


   bar.sync(1, true);

   UInt64 startUs = ResipClock::getTimeMicroSec();
   // TestRandomThread::makeRandoms(numCycles);

   bar.sync(2, true);

   UInt64 doneUs = ResipClock::getTimeMicroSec();
   // std::cerr << "Threads finished."
   //    << " (barrier pre="<<Barrier::sPreWaitCnt
   //    << " post="<<Barrier::sPostWaitCnt
   //    <<")" << std::endl;

   DataSet allRandoms;
   int intraDupCnt = 0;
   int interDupCnt = 0;
   for (pidx=0; pidx < numThreads; pidx++)
   {
      TestRandomThread* rth = threadList[pidx];
      if ( storeBytes > 0 )
      {
         intraDupCnt += rth->getDupCnt();
         interDupCnt += mergeCheckRandoms(allRandoms, rth->getRandoms());
      }
      rth->join();
      delete rth;
   }
   if ( storeBytes > 0 )
   {
      std::cout << "Found "<<interDupCnt<< " inter-thread and "
         <<intraDupCnt<<" intra-thread duplicates." << std::endl;
   }
   return doneUs - startUs;
}

Here is the call graph for this function:

static void doVariationTest ( int  numCycles,
int  numThreads,
int  numPass,
int  storeBytes 
) [static]

Definition at line 243 of file testRandomThread.cxx.

References doSingleTest(), and doThreadedTest().

Referenced by main().

{
   UInt64 msMin = 0, msMax = 0;
   UInt64 msSum = 0;
   UInt64 msSumSq = 0;
   int passIdx=0;
   for (passIdx=0; passIdx < numPass; passIdx++)
   {
      UInt64 usTot = numThreads<=0
         ?  doSingleTest(numCycles) 
         : doThreadedTest(numCycles, numThreads, storeBytes);
      UInt64 usPerCycle = usTot/numCycles;
#if 0
      std::cerr << numCycles << " cycles/thread (1M plain 32-bit ints)"
         << " with " << numThreads << " threads"
          << " took " << usTot<<"us (" << usPerCycle << "us/cycle)"
          << std::endl;
#endif
      UInt64 msPerCycle = usPerCycle/1000;
      msSum += msPerCycle;
      msSumSq += msPerCycle*msPerCycle;
      if ( msPerCycle < msMin || passIdx==0 )
         msMin = msPerCycle;
      if ( msPerCycle > msMax || passIdx==0 )
         msMax = msPerCycle;
   }
   double msAvg = msSum/(numPass+0.0);
   double msVar = msSumSq/(numPass+0.0) - msAvg*msAvg;
   double msStd = sqrt(msVar);
   double msStdPct = msStd/msAvg*100;
   fprintf(stderr,"RESULT:plain:%s:cycles=%d,threads=%d,passes=%d:min=%d,avg=%d,max=%d,std=%.1f(%.1f%%)[ms/cycle]\n",
         Random::getImplName(),
         numCycles, numThreads, numPass,
         (int)msMin,(int)msAvg,(int)msMax, msStd, msStdPct);
}

Here is the call graph for this function:

int main ( int  argc,
char **  argv 
)

Definition at line 280 of file testRandomThread.cxx.

References doVariationTest().

{
   bool doSweep = true;
   int numCycles = 2;
   int numThreads = 3;
   int numPass = 10;
   int storeBytes = 0;

   {
      doSweep = false;
      if(argc >= 2)
         numCycles = atoi(argv[1]);
      if(argc >= 3)
         numThreads = atoi(argv[2]);
      if(argc >= 4)
         numPass = atoi(argv[3]);
      if(argc >= 5)
         storeBytes = atoi(argv[4]);
   }

   if (numCycles <= 0 || numThreads < -1 || numPass < 1)
   {
       std::cerr
          << "usage: testRandomThread [numCycles numThreads numPasses storeBytes]" << std::endl
           << "numCycles>0 is number of cycles to run in each thread." << std::endl
           << "    each cycle is one million random 32bit integers" << std::endl
           << "    each cycle is one thousand random sequences when storing (see below) " << std::endl
           << "numThreads>=-1 is number of threads to run " << std::endl
           << "    -1 ==> work in main thread only" << std::endl
           << "    0  ==> work in main thread, plus dummy thread doing nothing" << std::endl
           << "    1  ==> single working thread, plus dummy & main doing nothing" << std::endl
           << "    N  ==> this many working threads, plus dummy & main doing nothing" << std::endl
           << "numPasses>=1 is number of time to repeat test (for min/max/stdev) " << std::endl
           << "Reported metric (min/avg/max/stdev) are milliseconds per cycle for all threads to complete." << std::endl
           << "storeBytes>=0 will store random sequences of this many bytes" << std::endl
           << "    and check for duplicates. Mainly to check for thread safety." << std::endl
           << "    Timing numbers in this case are not so useful." << std::endl
           << "    0 ==> [default] Don't store, just time." << std::endl
           ;
      exit(-1);
   }

   std::auto_ptr<TestDummyThread> dummyThread;
   if ( numThreads >= 0 )
   {
       dummyThread.reset(new TestDummyThread);
       dummyThread->run();
   }

   std::cerr << "Starting..." << std::endl;

   {
      doVariationTest(numCycles, numThreads, numPass, storeBytes);
   }

   std::cerr << "Success." << std::endl;
   return 0;
}

Here is the call graph for this function:

static int mergeCheckRandoms ( DataSet all,
const DataSet more 
) [static]

Definition at line 171 of file testRandomThread.cxx.

Referenced by doThreadedTest().

{
   int dupCnt = 0;
   DataSet::const_iterator it = more.begin();
   // DataSet::iterator at = all.begin();
   for ( ; it != more.end(); ++it)
   {
      // STL is unbelieable: this form isn't supported:
      // std::pair<DataSet::iterator,bool> res = all.insert( at, *it);
      // So we have to do this NlgN style:
      std::pair<DataSet::iterator,bool> res = all.insert( *it);
      // at = res->first;
      if ( res.second == false )
      {
         ++dupCnt;
         // std::cerr << "Inter-thread duplicate found." << std::endl;
      }
   }
   return dupCnt;
}