core(test): add regression test for RNG in parallel_for_()
authorAlexander Alekhin <alexander.alekhin@intel.com>
Tue, 28 Feb 2017 15:01:41 +0000 (18:01 +0300)
committerAlexander Alekhin <alexander.alekhin@intel.com>
Tue, 28 Feb 2017 15:22:58 +0000 (18:22 +0300)
modules/core/test/test_rand.cpp

index 63b9094..b687a8f 100644 (file)
@@ -382,3 +382,39 @@ TEST(Core_Rand, Regression_Stack_Corruption)
     ASSERT_EQ(param1, -9);
     ASSERT_EQ(param2,  2);
 }
+
+namespace {
+
+class RandRowFillParallelLoopBody : public cv::ParallelLoopBody
+{
+public:
+    RandRowFillParallelLoopBody(Mat& dst) : dst_(dst) {}
+    ~RandRowFillParallelLoopBody() {}
+    void operator()(const cv::Range& r) const
+    {
+        cv::RNG rng = cv::theRNG(); // copy state
+        for (int y = r.start; y < r.end; y++)
+        {
+            cv::theRNG() = cv::RNG(rng.state + y); // seed is based on processed row
+            cv::randu(dst_.row(y), Scalar(-100), Scalar(100));
+        }
+        // theRNG() state is changed here (but state collision has low probability, so we don't check this)
+    }
+protected:
+    Mat& dst_;
+};
+
+TEST(Core_Rand, parallel_for_stable_results)
+{
+    cv::RNG rng = cv::theRNG(); // save rng state
+    Mat dst1(1000, 100, CV_8SC1);
+    parallel_for_(cv::Range(0, dst1.rows), RandRowFillParallelLoopBody(dst1));
+
+    cv::theRNG() = rng; // restore rng state
+    Mat dst2(1000, 100, CV_8SC1);
+    parallel_for_(cv::Range(0, dst2.rows), RandRowFillParallelLoopBody(dst2));
+
+    ASSERT_EQ(0, countNonZero(dst1 != dst2));
+}
+
+} // namespace