summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2020-10-03 17:53:51 +0200
committerSven Gothel <[email protected]>2020-10-03 17:53:51 +0200
commitf330b1d5f58b05627a13fb62099fbbe5deaf7322 (patch)
tree57c1d9eb5a70a0a00479636263c4918115e4e8b1 /test
parentb9f497fb16b6367631c9b01e8a66ce590013eddc (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.txt21
-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.cpp211
3 files changed, 230 insertions, 8 deletions
diff --git a/test/direct_bt/CMakeLists.txt b/test/direct_bt/CMakeLists.txt
index 4fd18db1..135a2766 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 1a86d885..3538597e 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 00000000..fe3969e0
--- /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();
+}
+