From c74b83be5b08f22b37c93fd6ccba4b8111b928c1 Mon Sep 17 00:00:00 2001 From: Stepan Fomenko Date: Tue, 1 Sep 2020 16:31:36 +0300 Subject: [PATCH] Refactor --- CMakeLists.txt | 44 +---- can | 2 +- experiments/CMakeLists.txt | 7 + experiments/can/CMakeLists.txt | 20 +++ experiments/{ => can}/can_send.cpp | 6 +- experiments/{ => can}/can_send.h | 0 .../{ => can}/can_send_multithread.cpp | 6 +- experiments/pip/CMakeLists.txt | 16 ++ experiments/{ => pip}/mutex.cpp | 9 - experiments/{ => pip}/mutex_multithread.cpp | 11 -- experiments/{ => pip}/vectors.cpp | 0 experiments/sm/CMakeLists.txt | 12 ++ experiments/sm/block.h | 63 +++++++ experiments/{ => sm}/block_choice.cpp | 2 +- experiments/sm/smbusdata_crash_test.cpp | 164 ++++++++++++++++++ experiments/smbusdata_crash_test.cpp | 77 -------- 16 files changed, 296 insertions(+), 143 deletions(-) create mode 100644 experiments/CMakeLists.txt create mode 100644 experiments/can/CMakeLists.txt rename experiments/{ => can}/can_send.cpp (56%) rename experiments/{ => can}/can_send.h (100%) rename experiments/{ => can}/can_send_multithread.cpp (53%) create mode 100644 experiments/pip/CMakeLists.txt rename experiments/{ => pip}/mutex.cpp (82%) rename experiments/{ => pip}/mutex_multithread.cpp (83%) rename experiments/{ => pip}/vectors.cpp (100%) create mode 100644 experiments/sm/CMakeLists.txt create mode 100644 experiments/sm/block.h rename experiments/{ => sm}/block_choice.cpp (99%) create mode 100644 experiments/sm/smbusdata_crash_test.cpp delete mode 100644 experiments/smbusdata_crash_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f2b4b0..936bc29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,12 @@ cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0020 NEW) +set (CMAKE_CXX_STANDARD 17) project(multithread_experiments) -find_package(SM REQUIRED) +if (DEFINED PATH_TO_SMSDK OR DEFINED ENV{SMSDK_DIR}) + find_package(SM REQUIRED) +endif() if (CMAKE_BUILD_TYPE MATCHES Debug) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -fPIC -std=c++11") @@ -13,40 +16,5 @@ else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -fPIC") endif() -include_directories(experiments ${SMBRICKS_INCLUDES} ${PIP_INCLUDES} ${PROJECT_SOURCE_DIR}) - -if(WIN32) - include_directories(can) - - add_subdirectory(can) - - add_custom_target(copy_dependencies - COMMAND ${CMAKE_COMMAND} -E copy ${PCAN_LIB} ${CMAKE_CURRENT_BINARY_DIR}/PCANBasic${CMAKE_SHARED_LIBRARY_SUFFIX} - COMMAND ${CMAKE_COMMAND} -E copy ${VSCAN_LIB} ${CMAKE_CURRENT_BINARY_DIR}/vs_can_api${CMAKE_SHARED_LIBRARY_SUFFIX}) - - add_executable(can_send_multithread experiments/can_send_multithread.cpp) - target_link_libraries(can_send_multithread can) - add_dependencies(can_send_multithread copy_dependencies) - - add_executable(can_send experiments/can_send.cpp) - target_link_libraries(can_send can) - add_dependencies(can_send copy_dependencies) -endif() - -add_executable(mutex experiments/mutex.cpp) -target_link_libraries(mutex ${PIP_LIBRARY} ${PIP_CONCURRENT_LIBRARY}) - -add_executable(mutex_multithread experiments/mutex_multithread.cpp) -target_link_libraries(mutex_multithread ${PIP_LIBRARY} ${PIP_CONCURRENT_LIBRARY}) - -add_executable(vectors experiments/vectors.cpp) -target_link_libraries(vectors ${PIP_LIBRARY}) - -add_executable(block_choice experiments/block_choice.cpp) -target_link_libraries(block_choice ${PIP_LIBRARY}) - -add_executable(smbusdata_crash_test experiments/smbusdata_crash_test.cpp) -target_link_libraries(smbusdata_crash_test SMBricks_shared ${PIP_LIBRARY} ${PIP_CONCURRENT_LIBRARY} ${PIP_CRYPT_LIBRARY}) - -add_executable(packaged_task experiments/packaged_task.cpp) -target_link_libraries(packaged_task SMBricks_shared ${PIP_LIBRARY} ${PIP_CONCURRENT_LIBRARY} ${PIP_CRYPT_LIBRARY}) \ No newline at end of file +add_subdirectory(can) +add_subdirectory(experiments) \ No newline at end of file diff --git a/can b/can index 6807666..d71e584 160000 --- a/can +++ b/can @@ -1 +1 @@ -Subproject commit 6807666d0bc9c4fba4d6bf0ab1e00e40cf86a439 +Subproject commit d71e58468ec14085adec43aeafccff53b561a0c0 diff --git a/experiments/CMakeLists.txt b/experiments/CMakeLists.txt new file mode 100644 index 0000000..a2b7f08 --- /dev/null +++ b/experiments/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(can) +add_subdirectory(pip) +#add_subdirectory(concurrent) + +if (DEFINED PATH_TO_SMSDK OR DEFINED ENV{SMSDK_DIR}) + add_subdirectory(sm) +endif() \ No newline at end of file diff --git a/experiments/can/CMakeLists.txt b/experiments/can/CMakeLists.txt new file mode 100644 index 0000000..f48d6d2 --- /dev/null +++ b/experiments/can/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0) +cmake_policy(SET CMP0020 NEW) + +find_package(PIP REQUIRED) + +if(WIN32) + add_custom_target(copy_dependencies + COMMAND ${CMAKE_COMMAND} -E copy ${PCAN_LIB} ${CMAKE_CURRENT_BINARY_DIR}/PCANBasic${CMAKE_SHARED_LIBRARY_SUFFIX} + COMMAND ${CMAKE_COMMAND} -E copy ${VSCAN_LIB} ${CMAKE_CURRENT_BINARY_DIR}/vs_can_api${CMAKE_SHARED_LIBRARY_SUFFIX}) + + add_executable(can_send_multithread can_send_multithread.cpp) + target_include_directories(can_send_multithread PUBLIC ${PIP_INCLUDES} ${CAN_INCLUDES}) + target_link_libraries(can_send_multithread can) + add_dependencies(can_send_multithread copy_dependencies) + + add_executable(can_send can_send.cpp) + target_include_directories(can_send PUBLIC ${PIP_INCLUDES} ${CAN_INCLUDES}) + target_link_libraries(can_send can) + add_dependencies(can_send copy_dependencies) +endif() \ No newline at end of file diff --git a/experiments/can_send.cpp b/experiments/can/can_send.cpp similarity index 56% rename from experiments/can_send.cpp rename to experiments/can/can_send.cpp index 26a768f..498cbbc 100644 --- a/experiments/can_send.cpp +++ b/experiments/can/can_send.cpp @@ -1,16 +1,16 @@ #include "can_send.h" #include -#include +#include int main() { auto time1 = std::async(std::launch::deferred, [] { return test_send(PCAN_USBBUS1); }); auto time2 = std::async(std::launch::deferred, [] { return test_send(PCAN_USBBUS2); }); time1.wait(); - piCout << "measurements for PCAN_USBBUS1:" << time1.get() / 1000.f << "ms"; + std::cout << "measurements for PCAN_USBBUS1: " << time1.get() / 1000.f << " ms" << std::endl; time2.wait(); - piCout << "measurements for PCAN_USBBUS2:" << time2.get() / 1000.f << "ms"; + std::cout << "measurements for PCAN_USBBUS2: " << time2.get() / 1000.f << " ms" << std::endl; return 0; } \ No newline at end of file diff --git a/experiments/can_send.h b/experiments/can/can_send.h similarity index 100% rename from experiments/can_send.h rename to experiments/can/can_send.h diff --git a/experiments/can_send_multithread.cpp b/experiments/can/can_send_multithread.cpp similarity index 53% rename from experiments/can_send_multithread.cpp rename to experiments/can/can_send_multithread.cpp index c742aa9..39c6827 100644 --- a/experiments/can_send_multithread.cpp +++ b/experiments/can/can_send_multithread.cpp @@ -1,13 +1,13 @@ #include "can_send.h" #include -#include +#include int main() { auto time1 = std::async(std::launch::async, [] { return test_send(PCAN_USBBUS1); }); auto time2 = std::async(std::launch::async, [] { return test_send(PCAN_USBBUS2); }); - piCout << "measurements for PCAN_USBBUS1:" << time1.get() / 1000.f << "ms"; - piCout << "measurements for PCAN_USBBUS2:" << time2.get() / 1000.f << "ms"; + std::cout << "measurements for PCAN_USBBUS1: " << time1.get() / 1000.f << " ms" << std::endl; + std::cout << "measurements for PCAN_USBBUS2: " << time2.get() / 1000.f << " ms" << std::endl; return 0; } \ No newline at end of file diff --git a/experiments/pip/CMakeLists.txt b/experiments/pip/CMakeLists.txt new file mode 100644 index 0000000..382cc8c --- /dev/null +++ b/experiments/pip/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.0) +cmake_policy(SET CMP0020 NEW) + +find_package(PIP REQUIRED) + +add_executable(mutex mutex.cpp) +target_include_directories(mutex PUBLIC ${PIP_INCLUDES}) +target_link_libraries(mutex ${PIP_LIBRARY} ${PIP_CONCURRENT_LIBRARY}) + +add_executable(mutex_multithread mutex_multithread.cpp) +target_include_directories(mutex_multithread PUBLIC ${PIP_INCLUDES}) +target_link_libraries(mutex_multithread ${PIP_LIBRARY} ${PIP_CONCURRENT_LIBRARY}) + +add_executable(vectors vectors.cpp) +target_include_directories(vectors PUBLIC ${PIP_INCLUDES}) +target_link_libraries(vectors ${PIP_LIBRARY}) \ No newline at end of file diff --git a/experiments/mutex.cpp b/experiments/pip/mutex.cpp similarity index 82% rename from experiments/mutex.cpp rename to experiments/pip/mutex.cpp index bdf0bba..b69c079 100644 --- a/experiments/mutex.cpp +++ b/experiments/pip/mutex.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -30,14 +29,6 @@ int main() { }); piCout << "piMutex:" << piMutexPerformance.get() << "ms"; - PIConditionLock piConditionLock; - auto piConditionLockPerformance = check_performance([&piConditionLock](){ - piConditionLock.lock(); - int i = 0; while (i < 1000) i++; - piConditionLock.unlock(); - }); - piCout << "piConditionLock:" << piConditionLockPerformance.get() << "ms"; - std::mutex stdMutex; auto stdMutexPerformance = check_performance([&stdMutex](){ stdMutex.lock(); diff --git a/experiments/mutex_multithread.cpp b/experiments/pip/mutex_multithread.cpp similarity index 83% rename from experiments/mutex_multithread.cpp rename to experiments/pip/mutex_multithread.cpp index b623421..0cb87fc 100644 --- a/experiments/mutex_multithread.cpp +++ b/experiments/pip/mutex_multithread.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -37,16 +36,6 @@ int main() { }); piCout << "piMutex:" << piMutexPerformance << "ms"; - PIConditionLock piConditionLock; - auto piConditionLockPerformance = check_performance([&piConditionLock](long& k){ - piConditionLock.lock(); - int i = 0; while (i < 1000) { i++; } - long res = ++k; - piConditionLock.unlock(); - return res; - }); - piCout << "piConditionLock:" << piConditionLockPerformance << "ms"; - std::mutex stdMutex; auto stdMutexPerformance = check_performance([&stdMutex](long& k){ stdMutex.lock(); diff --git a/experiments/vectors.cpp b/experiments/pip/vectors.cpp similarity index 100% rename from experiments/vectors.cpp rename to experiments/pip/vectors.cpp diff --git a/experiments/sm/CMakeLists.txt b/experiments/sm/CMakeLists.txt new file mode 100644 index 0000000..b621ea9 --- /dev/null +++ b/experiments/sm/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.0) +cmake_policy(SET CMP0020 NEW) + +find_package(SM REQUIRED) + +add_executable(block_choice block_choice.cpp) +target_include_directories(block_choice PUBLIC ${SMBRICKS_INCLUDES} ${PIP_INCLUDES}) +target_link_libraries(block_choice ${PIP_LIBRARY}) + +add_executable(smbusdata_crash_test smbusdata_crash_test.cpp) +target_include_directories(smbusdata_crash_test PUBLIC ${SMBRICKS_INCLUDES} ${PIP_INCLUDES}) +target_link_libraries(smbusdata_crash_test SMBricks_shared ${PIP_LIBRARY} ${PIP_CRYPT_LIBRARY}) diff --git a/experiments/sm/block.h b/experiments/sm/block.h new file mode 100644 index 0000000..8525337 --- /dev/null +++ b/experiments/sm/block.h @@ -0,0 +1,63 @@ +#ifndef MULTITHREAD_EXPERIMENTS_BLOCK_H +#define MULTITHREAD_EXPERIMENTS_BLOCK_H + +#include +#include +#include +#include + +namespace sm { + + struct block { + PIVector input_blocks; + PIVector output_blocks; + std::atomic_flag barrier = ATOMIC_FLAG_INIT; + const int is_calc_idx; + const std::chrono::microseconds calc_time; + + static std::chrono::microseconds random_time() { + float val = powf(rand() % 1000 / 1000.f, 20.f) * 30.f * 1000.f; +// std::cout << int(val) << std::endl; + return std::chrono::microseconds(int(val)); + } + + explicit block(const int is_calc_idx) : is_calc_idx(is_calc_idx), calc_time(random_time()) {} + + void calc() { + std::this_thread::sleep_for(calc_time); + } + + void unlock(int locks_count = -1) { + if (locks_count == -1) locks_count = this->input_blocks.size(); + for (int i = 0; i < locks_count; ++i) { + this->input_blocks[i]->barrier.clear(std::memory_order_release); + } + this->barrier.clear(std::memory_order_release); + } + + bool try_lock() { + if (this->barrier.test_and_set(std::memory_order_acquire)) return false; + + int locks_count = 0; + for (auto & input_block : this->input_blocks) { + if (input_block->barrier.test_and_set(std::memory_order_acquire)) break; + locks_count++; + } + + if (locks_count == this->input_blocks.size()) { + return true; + } else { + unlock(locks_count); + return false; + } + } + }; + + struct time_report { + double calc_time_ms; + double sync_time_ms; + }; + +} + +#endif //MULTITHREAD_EXPERIMENTS_BLOCK_H diff --git a/experiments/block_choice.cpp b/experiments/sm/block_choice.cpp similarity index 99% rename from experiments/block_choice.cpp rename to experiments/sm/block_choice.cpp index 73c8abc..6bd7c7b 100644 --- a/experiments/block_choice.cpp +++ b/experiments/sm/block_choice.cpp @@ -1,4 +1,4 @@ -#include "sm/block.h" +#include "block.h" #include #include #include diff --git a/experiments/sm/smbusdata_crash_test.cpp b/experiments/sm/smbusdata_crash_test.cpp new file mode 100644 index 0000000..0db41f8 --- /dev/null +++ b/experiments/sm/smbusdata_crash_test.cpp @@ -0,0 +1,164 @@ +#include +#include +#include + +struct SomeLargeData { + uint8_t data[4]{}; + + SomeLargeData() { memset(data, 0xff, sizeof(data)); } + + ~SomeLargeData() { + memset(data, 0x00, sizeof(data)); + } +}; + +inline PIByteArray & operator <<(PIByteArray & s, const SomeLargeData & v) { + s << PIByteArray::RawData(v.data, sizeof(v.data)); + return s; +} + +inline PIByteArray & operator >>(PIByteArray & s, SomeLargeData & v) { + if (s.size() < sizeof(v.data)) { + piCout << "Error in operator >> for SomeLargeData"; + exit(1); + } + s >> PIByteArray::RawData(v.data, sizeof(v.data)); + return s; +} + +REGISTER_BUS_TYPE(SomeLargeData) + +void test_blocking_queue() { + std::atomic_bool is_end(false); + PIBlockingQueue out_dequeue; + PIBlockingQueue in_dequeue; + + auto runnable = [&](){ + while (true) { + SMBlockData data; + bool is_ok; + data = in_dequeue.poll(100, SMBlockData(), &is_ok); + + if (!is_ok) { + if (is_end) break; + continue; + } + + out_dequeue.put(data); + +// if (!is_ok) { +// if (is_end) break; +// std::this_thread::yield(); +// } + } + }; + + PIVector> futures; + for (int i = 0; i < 4; ++i) { + futures.append(std::async(std::launch::async, runnable)); + } + + SomeLargeData content; + int iteration_count = 100 * 1000; + for (int i = 0; i < iteration_count / 20; ++i) { + for (int j = 0; j < 20; ++j) { + SMBlockData block_data(j+1); + for (int k = 0; k < j+1; ++k) { + block_data[k].value() = content; + } +// bus_data << SMBusData::create(content); + SMBlockData out_data = block_data.clone(); + in_dequeue.put(out_data); + } + for (int j = 0; j < 20; ++j) { + auto block_data = out_dequeue.take(); + if (block_data[0].isInvalid()) { + piCout << "Error: bus_data is invalid"; + exit(1); + } + } +// printf("It's alive! %d\n", i); + } + + is_end = true; + for (auto& future: futures) future.get(); +} + +void test_mutexes() { + std::atomic_bool is_end(false); + PIDeque out_dequeue; + PIDeque in_dequeue; + PIMutex out_mutex; + PIMutex in_mutex; + + auto runnable = [&](){ + while (true) { + SMBlockData data; + in_mutex.lock(); + bool is_ok = !in_dequeue.isEmpty(); + if (is_ok) data = in_dequeue.take_front(); + in_mutex.unlock(); + + if (!is_ok) { + if (is_end) break; + std::this_thread::yield(); + continue; + } + + out_mutex.lock(); + out_dequeue.push_back(data); + out_mutex.unlock(); + +// if (!is_ok) { +// if (is_end) break; +// std::this_thread::yield(); +// } + } + }; + + PIVector> futures; + for (int i = 0; i < 4; ++i) { + futures.append(std::async(std::launch::async, runnable)); + } + + SomeLargeData content; + int iteration_count = 100 * 1000; + for (int i = 0; i < iteration_count / 20; ++i) { + for (int j = 0; j < 20; ++j) { + SMBlockData block_data(j+1); + for (int k = 0; k < j+1; ++k) { + block_data[k].value() = content; + } +// bus_data << SMBusData::create(content); + SMBlockData out_data = block_data.clone(); + in_mutex.lock(); + in_dequeue.push_back(out_data); + in_mutex.unlock(); + } + for (int j = 0; j < 20; ++j) { + out_mutex.lock(); + if (out_dequeue.isEmpty()) { + out_mutex.unlock(); + j--; + std::this_thread::yield(); + continue; + } + auto block_data = out_dequeue.take_front(); + out_mutex.unlock(); + if (block_data[0].isInvalid()) { + piCout << "Error: bus_data is invalid"; + exit(1); + } + } +// printf("It's alive! %d\n", i); + } + + is_end = true; + for (auto& future: futures) future.get(); + +} + +int main() { + test_blocking_queue(); + return 0; +} \ No newline at end of file diff --git a/experiments/smbusdata_crash_test.cpp b/experiments/smbusdata_crash_test.cpp deleted file mode 100644 index 47563f0..0000000 --- a/experiments/smbusdata_crash_test.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include - -struct SomeLargeData { - uint8_t data[4]{}; - - SomeLargeData() { memset(data, 0xff, sizeof(data)); } - - ~SomeLargeData() { - memset(data, 0x00, sizeof(data)); - } -}; - -inline PIByteArray & operator <<(PIByteArray & s, const SomeLargeData & v) { - s << PIByteArray::RawData(v.data, sizeof(v.data)); - return s; -} - -inline PIByteArray & operator >>(PIByteArray & s, SomeLargeData & v) { - if (s.size() < sizeof(v.data)) { - piCout << "Error in operator >> for SomeLargeData"; - exit(1); - } - s >> PIByteArray::RawData(v.data, sizeof(v.data)); - return s; -} - -REGISTER_BUS_TYPE(SomeLargeData) - -int main() { - std::atomic_bool is_end(false); - PIThreadPoolExecutor executor(4); - PIBlockingDequeue out_dequeue; - PIBlockingDequeue in_dequeue; - - executor.execute([&](){ - while (true) { - bool is_ok; - SMBlockData data; - data = in_dequeue.poll(100, data, &is_ok); - if (!is_ok) { - if (is_end) break; - } - - out_dequeue.offer(data, 100); - if (!is_ok) { - if (is_end) break; - } - } - }); - - SomeLargeData content; - int iteration_count = 100 * 1000; - for (int i = 0; i < iteration_count / 20; ++i) { - for (int j = 0; j < 20; ++j) { - SMBlockData block_data(j+1); - for (int k = 0; k < j+1; ++k) { - block_data[k].sharedData() = content; - } -// bus_data << SMBusData::create(content); - in_dequeue.offer(block_data.clone()); - } - for (int j = 0; j < 20; ++j) { - auto block_data = out_dequeue.take(); - if (block_data[0].isInvalid()) { - piCout << "Error: bus_data is invalid"; - exit(1); - } - } -// printf("It's alive! %d\n", i); - } - - is_end = true; - executor.shutdownNow(); - - return 0; -} \ No newline at end of file