I've modified Symbolic's random game generator so that each thread has its own non-thread-safe (fast) PRNG and all threads poll the same early-quit interrupt flag.
Code: Select all
typedef struct
{
volatile bool *stopptr;
ui64 limit;
ui64 ptvec[PosTermLen];
ui64 totalply;
ui plymax;
} RgRec;
static void * RgTask(void *ptr)
{
RgRec * const rgrptr = (RgRec *) ptr;
Position position;
PRNG prng(false);
ui64 index = 0;
ForEachPosTerm(posterm)
rgrptr->ptvec[posterm] = 0;
rgrptr->totalply = 0;
rgrptr->plymax = 0;
position.LoadInitialArray();
while (!(*rgrptr->stopptr) && (index < rgrptr->limit))
{
const PosTerm posterm = position.RandomGame(prng);
const ui plycount = position.GetPlyCount();
rgrptr->ptvec[posterm]++;
rgrptr->totalply += plycount;
rgrptr->plymax = std::max(plycount, rgrptr->plymax);
index++;
};
return 0;
}
void IntCoPro::DoRandomGames(void)
{
const ui64 limit = (ui64) strtoll(tokens.Arg(1).c_str(), 0, 10);
const ui distthreadcount = DIPtr->GetDistThreadCount();
const ui64 splitlimit = limit / distthreadcount;
Thread *threadptrvec[DistThreadLen];
RgRec rgvec[DistThreadLen];
ui64 ptvec[PosTermLen];
ui64 totalply = 0;
ui plymax = 0;
// Reset the reportable results
ForEachPosTerm(posterm)
ptvec[posterm] = 0;
// Create the threads
ZOL(index, distthreadcount)
{
RgRec * const rgrptr = &rgvec[index];
rgrptr->stopptr = &DIPtr->PendingSignals[SignalInt];
if (index < (distthreadcount - 1))
rgrptr->limit = splitlimit;
else
rgrptr->limit = limit - (splitlimit * (distthreadcount - 1));
// Start the thread
threadptrvec[index] = new Thread(RgTask, rgrptr);
};
// Destroy the threads
ZOL(index, distthreadcount)
{
const RgRec * const rgrptr = &rgvec[index];
// End the thread
delete threadptrvec[index];
ForEachPosTerm(posterm)
ptvec[posterm] += rgrptr->ptvec[posterm];
totalply += rgrptr->totalply;
plymax = std::max(rgrptr->plymax, plymax);
};
// In case of interrupt signal
DIPtr->PendingSignals[SignalInt] = false;
// Calculate actual game count
ui64 gamecount = 0;
ForEachPosTerm(posterm)
gamecount += ptvec[posterm];
// Report
ForEachPosTerm(posterm)
if (posterm != PosTermUnterminated)
{
const ui64 count = ptvec[posterm];
const double ratio = count / (double) gamecount;
std::ostringstream oss;
oss <<
std::setw(12) << PosTermNameVec[posterm] << " " <<
std::setw(8) << count << " " <<
std::setprecision(6) << ratio;
WriteLn(oss.str());
};
WriteLn("Average ply length: " + EncodeDouble(totalply / (double) gamecount));
WriteLn("Maximum ply length: " + EncodeUi(plymax));
}