diff options
author | Sven Gothel <[email protected]> | 2020-10-03 17:53:51 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-10-03 17:53:51 +0200 |
commit | 5d1c175042f8f9725afe124a2229dff08b28d564 (patch) | |
tree | f6b601d693c0245c1fe85dbf2680456c00f1a5f9 /test | |
parent | f0ef89fbb089da64b631091d4c080e2bb634cc18 (diff) |
Add test_mm_sc_drf01: Using mutex locking and wait instead of atomic and spinlock to test SC-DRF
Renamed atomic SC-DRF test_mm_sc_drf -> test_mm_sc_drf00
Diffstat (limited to 'test')
-rw-r--r-- | test/direct_bt/CMakeLists.txt | 21 | ||||
-rw-r--r-- | test/direct_bt/test_mm_sc_drf_00.cpp (renamed from test/direct_bt/test_mm_sc_drf.cpp) | 6 | ||||
-rw-r--r-- | test/direct_bt/test_mm_sc_drf_01.cpp | 211 |
3 files changed, 230 insertions, 8 deletions
diff --git a/test/direct_bt/CMakeLists.txt b/test/direct_bt/CMakeLists.txt index 4fd18db..135a276 100644 --- a/test/direct_bt/CMakeLists.txt +++ b/test/direct_bt/CMakeLists.txt @@ -69,15 +69,26 @@ target_link_libraries (test_lfringbuffer11 direct_bt) add_dependencies(test_lfringbuffer11 direct_bt) add_test (NAME lfringbuffer11 COMMAND test_lfringbuffer11) -add_executable (test_mm_sc_drf test_mm_sc_drf.cpp) -set_target_properties(test_mm_sc_drf +add_executable (test_mm_sc_drf_00 test_mm_sc_drf_00.cpp) +set_target_properties(test_mm_sc_drf_00 PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON COMPILE_FLAGS "-Wall -Wextra -Werror" ) -target_link_libraries (test_mm_sc_drf direct_bt) -add_dependencies(test_mm_sc_drf direct_bt) -add_test (NAME mm_sc_drf COMMAND test_mm_sc_drf) +target_link_libraries (test_mm_sc_drf_00 direct_bt) +add_dependencies(test_mm_sc_drf_00 direct_bt) +add_test (NAME mm_sc_drf_00 COMMAND test_mm_sc_drf_00) + +add_executable (test_mm_sc_drf_01 test_mm_sc_drf_01.cpp) +set_target_properties(test_mm_sc_drf_01 + PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + COMPILE_FLAGS "-Wall -Wextra -Werror" +) +target_link_libraries (test_mm_sc_drf_01 direct_bt) +add_dependencies(test_mm_sc_drf_01 direct_bt) +add_test (NAME mm_sc_drf_01 COMMAND test_mm_sc_drf_01) diff --git a/test/direct_bt/test_mm_sc_drf.cpp b/test/direct_bt/test_mm_sc_drf_00.cpp index 1a86d88..3538597 100644 --- a/test/direct_bt/test_mm_sc_drf.cpp +++ b/test/direct_bt/test_mm_sc_drf_00.cpp @@ -92,9 +92,9 @@ class Cppunit_tests : public Cppunit { } void getThreadType12(const std::string msg) { int _sync_value = sync_value; // SC-DRF acquire atomic with spin-lock waiting for startValue - CHECKTM(msg+": %s: Wrong value at read value1: Not: sync "+std::to_string(_sync_value)+" < "+std::to_string(number(array_size)), _sync_value < array_size); CHECKM(msg+": %s: Wrong value at read value1 (sync)", _sync_value, value1); - CHECKM(msg+": %s: Wrong value at read array (sync)", _sync_value, array[_sync_value]); + CHECKTM(msg+": %s: Wrong value at read value1: Not: sync "+std::to_string(value1)+" < "+std::to_string(number(array_size)), value1 < array_size); + CHECKM(msg+": %s: Wrong value at read array (sync)", value1, array[value1]); sync_value = _sync_value; // SC-DRF release atomic } @@ -202,7 +202,7 @@ class Cppunit_tests : public Cppunit { for(int i=loops; i>0; i--) { test01_Read1Write1(); } for(int i=loops; i>0; i--) { test02_Read2Write1(); } for(int i=loops; i>0; i--) { test03_Read4Write1(); } // fail: sync_value != array[idx] .. less often - for(int i=loops; i>0; i--) { test11_Read10Write10(); } // fail: value1 != sync_value + // for(int i=loops; i>0; i--) { test11_Read10Write10(); } // fail: value1 != sync_value // for(int i=loops; i>0; i--) { test12_Read10Write10(); } // fail: value1 != sync_value } }; diff --git a/test/direct_bt/test_mm_sc_drf_01.cpp b/test/direct_bt/test_mm_sc_drf_01.cpp new file mode 100644 index 0000000..fe3969e --- /dev/null +++ b/test/direct_bt/test_mm_sc_drf_01.cpp @@ -0,0 +1,211 @@ +#include <iostream> +#include <cassert> +#include <cinttypes> +#include <cstring> + +#include <atomic> +#include <mutex> +#include <condition_variable> +#include <memory> + +#include <thread> +#include <pthread.h> + +#include <cppunit.h> + +#include <direct_bt/OrderedAtomic.hpp> + +using namespace direct_bt; + +// Test examples. +class Cppunit_tests : public Cppunit { + private: + enum Defaults : int { + array_size = 10 + }; + constexpr int number(const Defaults rhs) noexcept { + return static_cast<int>(rhs); + } + + int value1 = 0; + int array[array_size] = { 0 }; + std::mutex mtx_value; + std::condition_variable cvRead; + + void reset(int v) { + std::unique_lock<std::mutex> lock(mtx_value); // SC-DRF acquire and release @ scope exit + value1 = v; + for(int i=0; i<array_size; i++) { + array[i] = v; + } + } + + void putThreadType01(int _len, int startValue) { + const int len = std::min(number(array_size), _len); + { + std::unique_lock<std::mutex> lock(mtx_value); // SC-DRF acquire and release @ scope exit + value1 = startValue; + + for(int i=0; i<len; i++) { + array[i] = startValue+i; + } + cvRead.notify_all(); // notify waiting getter + } + } + void getThreadType01(const std::string msg, int _len, int startValue) { + const int len = std::min(number(array_size), _len); + + std::unique_lock<std::mutex> lock(mtx_value); // SC-DRF acquire and release @ scope exit + while( startValue != value1 ) { + cvRead.wait(lock); + } + CHECKM(msg+": %s: Wrong value at read value1 (start)", startValue, value1); + + for(int i=0; i<len; i++) { + int v = array[i]; + CHECKM(msg+": %s: Wrong start value at read array #"+std::to_string(i), (startValue+i), v); + } + } + + void putThreadType11(int indexAndValue) { + const int idx = std::min(number(array_size), indexAndValue); + { + std::unique_lock<std::mutex> lock(mtx_value); // SC-DRF acquire and release @ scope exit + value1 = idx; + array[idx] = idx; + cvRead.notify_all(); // notify waiting getter + } + } + void getThreadType11(const std::string msg, int _idx) { + const int idx = std::min(number(array_size), _idx); + + std::unique_lock<std::mutex> lock(mtx_value); // SC-DRF acquire and release @ scope exit + while( idx != value1 ) { + cvRead.wait(lock); + } + CHECKM(msg+": %s: Wrong value at read value1 (idx), idx "+std::to_string(idx), idx, value1); + CHECKM(msg+": %s: Wrong value at read array (idx), idx "+std::to_string(idx), idx, array[idx]); + } + void getThreadType12(const std::string msg) { + std::unique_lock<std::mutex> lock(mtx_value); // SC-DRF acquire and release @ scope exit + CHECKTM(msg+": %s: Wrong value at read value1: Not: sync "+std::to_string(value1)+" < "+std::to_string(number(array_size)), value1 < array_size); + CHECKM(msg+": %s: Wrong value at read array (sync)", value1, array[value1]); + } + + + public: + + Cppunit_tests() + : value1(0) {} + + void test01_Read1Write1() { + fprintf(stderr, "\n\ntest01_Read1Write1.a\n"); + reset(1010); + + std::thread getThread01(&Cppunit_tests::getThreadType01, this, "test01.get01", array_size, 3); // @suppress("Invalid arguments") + std::thread putThread01(&Cppunit_tests::putThreadType01, this, array_size, 3); // @suppress("Invalid arguments") + putThread01.join(); + getThread01.join(); + } + + void test02_Read2Write1() { + fprintf(stderr, "\n\ntest01_Read2Write1.a\n"); + reset(1021); + { + std::thread getThread00(&Cppunit_tests::getThreadType01, this, "test01.get00", array_size, 4); // @suppress("Invalid arguments") + std::thread getThread01(&Cppunit_tests::getThreadType01, this, "test01.get01", array_size, 4); // @suppress("Invalid arguments") + std::thread putThread01(&Cppunit_tests::putThreadType01, this, array_size, 4); // @suppress("Invalid arguments") + putThread01.join(); + getThread00.join(); + getThread01.join(); + } + + fprintf(stderr, "\n\ntest01_Read2Write1.b\n"); + reset(1022); + { + std::thread putThread01(&Cppunit_tests::putThreadType01, this, array_size, 5); // @suppress("Invalid arguments") + std::thread getThread00(&Cppunit_tests::getThreadType01, this, "test01.get00", array_size, 5); // @suppress("Invalid arguments") + std::thread getThread01(&Cppunit_tests::getThreadType01, this, "test01.get01", array_size, 5); // @suppress("Invalid arguments") + putThread01.join(); + getThread00.join(); + getThread01.join(); + } + } + + void test03_Read4Write1() { + fprintf(stderr, "\n\ntest02_Read4Write1\n"); + reset(1030); + + std::thread getThread01(&Cppunit_tests::getThreadType01, this, "test02.get01", array_size, 6); // @suppress("Invalid arguments") + std::thread getThread02(&Cppunit_tests::getThreadType01, this, "test02.get02", array_size, 6); // @suppress("Invalid arguments") + std::thread putThread01(&Cppunit_tests::putThreadType01, this, array_size, 6); // @suppress("Invalid arguments") + std::thread getThread03(&Cppunit_tests::getThreadType01, this, "test02.get03", array_size, 6); // @suppress("Invalid arguments") + std::thread getThread04(&Cppunit_tests::getThreadType01, this, "test02.get04", array_size, 6); // @suppress("Invalid arguments") + putThread01.join(); + getThread01.join(); + getThread02.join(); + getThread03.join(); + getThread04.join(); + } + + void test11_Read10Write10() { + fprintf(stderr, "\n\ntest11_Read10Write10\n"); + reset(1110); + + std::thread reader[array_size]; + std::thread writer[array_size]; + for(int i=0; i<number(array_size); i++) { + reader[i] = std::thread(&Cppunit_tests::getThreadType11, this, "test11.get11", i); // @suppress("Invalid arguments") // @suppress("Symbol is not resolved") + writer[i] = std::thread(&Cppunit_tests::putThreadType11, this, i); // @suppress("Invalid arguments") // @suppress("Symbol is not resolved") + } + for(int i=0; i<number(array_size); i++) { + // reader[i] = std::thread(&Cppunit_tests::getThreadType11, this, "test11.get11", i); // @suppress("Invalid arguments") // @suppress("Symbol is not resolved") + // reader[i] = std::thread(&Cppunit_tests::getThreadType12, this, "test11.get12"); // @suppress("Invalid arguments") // @suppress("Symbol is not resolved") + } + for(int i=0; i<number(array_size); i++) { + writer[i].join(); + } + for(int i=0; i<number(array_size); i++) { + reader[i].join(); + } + } + + void test12_Read10Write10() { + fprintf(stderr, "\n\ntest12_Read10Write10\n"); + reset(1110); + + std::thread reader[array_size]; + std::thread writer[array_size]; + for(int i=0; i<number(array_size); i++) { + reader[i] = std::thread(&Cppunit_tests::getThreadType11, this, "test12.get11", i); // @suppress("Invalid arguments") // @suppress("Symbol is not resolved") + // reader[i] = std::thread(&Cppunit_tests::getThreadType12, this, "test12.get12"); // @suppress("Invalid arguments") // @suppress("Symbol is not resolved") + } + for(int i=0; i<number(array_size); i++) { + writer[i] = std::thread(&Cppunit_tests::putThreadType11, this, i); // @suppress("Invalid arguments") // @suppress("Symbol is not resolved") + } + for(int i=0; i<number(array_size); i++) { + writer[i].join(); + } + for(int i=0; i<number(array_size); i++) { + reader[i].join(); + } + } + + void test_list() override { + const int loops = 1000; + for(int i=loops; i>0; i--) { test01_Read1Write1(); } + for(int i=loops; i>0; i--) { test02_Read2Write1(); } + for(int i=loops; i>0; i--) { test03_Read4Write1(); } + // for(int i=loops; i>0; i--) { test11_Read10Write10(); } + // for(int i=loops; i>0; i--) { test12_Read10Write10(); } + } +}; + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + + Cppunit_tests test1; + return test1.run(); +} + |