Commit 649bb7ac authored by Alexander Alekhin's avatar Alexander Alekhin

core: parallel_for_(): update RNG state of the main thread

parent ebdd7410
...@@ -2834,6 +2834,8 @@ public: ...@@ -2834,6 +2834,8 @@ public:
double gaussian(double sigma); double gaussian(double sigma);
uint64 state; uint64 state;
bool operator ==(const RNG& other) const;
}; };
/** @brief Mersenne Twister random number generator /** @brief Mersenne Twister random number generator
......
...@@ -349,6 +349,8 @@ inline int RNG::uniform(int a, int b) { return a == b ? a : (int)(next( ...@@ -349,6 +349,8 @@ inline int RNG::uniform(int a, int b) { return a == b ? a : (int)(next(
inline float RNG::uniform(float a, float b) { return ((float)*this)*(b - a) + a; } inline float RNG::uniform(float a, float b) { return ((float)*this)*(b - a) + a; }
inline double RNG::uniform(double a, double b) { return ((double)*this)*(b - a) + a; } inline double RNG::uniform(double a, double b) { return ((double)*this)*(b - a) + a; }
inline bool RNG::operator ==(const RNG& other) const { return state == other.state; }
inline unsigned RNG::next() inline unsigned RNG::next()
{ {
state = (uint64)(unsigned)state* /*CV_RNG_COEFF*/ 4164903690U + (unsigned)(state >> 32); state = (uint64)(unsigned)state* /*CV_RNG_COEFF*/ 4164903690U + (unsigned)(state >> 32);
......
...@@ -166,7 +166,8 @@ namespace ...@@ -166,7 +166,8 @@ namespace
class ParallelLoopBodyWrapper : public cv::ParallelLoopBody class ParallelLoopBodyWrapper : public cv::ParallelLoopBody
{ {
public: public:
ParallelLoopBodyWrapper(const cv::ParallelLoopBody& _body, const cv::Range& _r, double _nstripes) ParallelLoopBodyWrapper(const cv::ParallelLoopBody& _body, const cv::Range& _r, double _nstripes) :
is_rng_used(false)
{ {
body = &_body; body = &_body;
...@@ -181,13 +182,23 @@ namespace ...@@ -181,13 +182,23 @@ namespace
pThreadRoot = cv::instr::getInstrumentTLSStruct().pCurrentNode; pThreadRoot = cv::instr::getInstrumentTLSStruct().pCurrentNode;
#endif #endif
} }
#ifdef ENABLE_INSTRUMENTATION
~ParallelLoopBodyWrapper() ~ParallelLoopBodyWrapper()
{ {
#ifdef ENABLE_INSTRUMENTATION
for(size_t i = 0; i < pThreadRoot->m_childs.size(); i++) for(size_t i = 0; i < pThreadRoot->m_childs.size(); i++)
SyncNodes(pThreadRoot->m_childs[i]); SyncNodes(pThreadRoot->m_childs[i]);
}
#endif #endif
if (is_rng_used)
{
// Some parallel backends execute nested jobs in the main thread,
// so we need to restore initial RNG state here.
cv::theRNG() = rng;
// We can't properly update RNG state based on RNG usage in worker threads,
// so lets just change main thread RNG state to the next value.
// Note: this behaviour is not equal to single-threaded mode.
cv::theRNG().next();
}
}
void operator()(const cv::Range& sr) const void operator()(const cv::Range& sr) const
{ {
#ifdef ENABLE_INSTRUMENTATION #ifdef ENABLE_INSTRUMENTATION
...@@ -207,6 +218,9 @@ namespace ...@@ -207,6 +218,9 @@ namespace
r.end = sr.end >= nstripes ? wholeRange.end : (int)(wholeRange.start + r.end = sr.end >= nstripes ? wholeRange.end : (int)(wholeRange.start +
((uint64)sr.end*(wholeRange.end - wholeRange.start) + nstripes/2)/nstripes); ((uint64)sr.end*(wholeRange.end - wholeRange.start) + nstripes/2)/nstripes);
(*body)(r); (*body)(r);
if (!is_rng_used && !(cv::theRNG() == rng))
is_rng_used = true;
} }
cv::Range stripeRange() const { return cv::Range(0, nstripes); } cv::Range stripeRange() const { return cv::Range(0, nstripes); }
...@@ -215,6 +229,7 @@ namespace ...@@ -215,6 +229,7 @@ namespace
cv::Range wholeRange; cv::Range wholeRange;
int nstripes; int nstripes;
cv::RNG rng; cv::RNG rng;
mutable bool is_rng_used;
#ifdef ENABLE_INSTRUMENTATION #ifdef ENABLE_INSTRUMENTATION
cv::instr::InstrNode *pThreadRoot; cv::instr::InstrNode *pThreadRoot;
#endif #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment