mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-15 09:31:45 +00:00
Compare commits
83 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
53a4d17f8b | ||
|
20544e1f18 | ||
|
b32e04db60 | ||
|
0d03c76a75 | ||
|
2916a491b9 | ||
|
b56e32eb11 | ||
|
4b516de81a | ||
|
361fb0cba5 | ||
|
df574c6466 | ||
|
dbdabd23a4 | ||
|
ccbf0be572 | ||
|
7a67719a3c | ||
|
f4a54ff550 | ||
|
d22023bcb5 | ||
|
a15d59c725 | ||
|
8cfc04721e | ||
|
e9318dd234 | ||
|
c8fc5ad33f | ||
|
59e32437a2 | ||
|
a3afadb824 | ||
|
9992811822 | ||
|
4218c185a4 | ||
|
5a49c5b9b1 | ||
|
960b612d80 | ||
|
e1a113aabe | ||
|
5721ea9510 | ||
|
330687772f | ||
|
7cbd154344 | ||
|
036561ab38 | ||
|
274ba5ec00 | ||
|
c5efd3e4a6 | ||
|
0a5820c07f | ||
|
5788daa410 | ||
|
46014118f0 | ||
|
adc4688f9b | ||
|
c3127f22e5 | ||
|
926ee743ed | ||
|
c7b1304a2c | ||
|
32764e1b12 | ||
|
96348b8462 | ||
|
cd83efadea | ||
|
38eb9d22e4 | ||
|
a20ac7af08 | ||
|
24aabdb854 | ||
|
539b088ade | ||
|
b05782af16 | ||
|
3a8f34efaa | ||
|
8160edfd04 | ||
|
3d4cd02812 | ||
|
0ae53fd7d9 | ||
|
a545bee3b1 | ||
|
f00519b99b | ||
|
41fc27d504 | ||
|
811d1b8973 | ||
|
ced67d8952 | ||
|
8123a6ecab | ||
|
beff0af51b | ||
|
21835cc104 | ||
|
334d81a1ab | ||
|
c1719eb285 | ||
|
fcd1022997 | ||
|
e221242f9a | ||
|
e853d121bf | ||
|
14d6d717a3 | ||
|
119cbe37f1 | ||
|
0e72a9bf54 | ||
|
3785fd9ff9 | ||
|
278cd62049 | ||
|
6c63b01cfe | ||
|
66acde2a69 | ||
|
19ab8bba3b | ||
|
be524d838a | ||
|
92af823135 | ||
|
50dacbcdde | ||
|
264a178424 | ||
|
1c8ad03f3c | ||
|
25658370fa | ||
|
f42945b3a3 | ||
|
9544de0647 | ||
|
d608abf31c | ||
|
15de80cfd3 | ||
|
f2da29a650 | ||
|
c180300303 |
@@ -1,3 +1,3 @@
|
||||
---
|
||||
Checks: '*,-google-*,-fuchsia-*,-cert-*,-llvm-header-guard,-readability-named-parameter,-misc-non-private-member-variables-in-classes,-*-magic-numbers,-llvm-include-order,-hicpp-no-array-decay,-performance-unnecessary-value-param,-cppcoreguidelines-pro-bounds-array-to-pointer-decay'
|
||||
Checks: '*,-google-*,-fuchsia-*,-cert-*,-llvm-header-guard,-readability-named-parameter,-misc-non-private-member-variables-in-classes,-*-magic-numbers,-llvm-include-order,-hicpp-no-array-decay,-performance-unnecessary-value-param,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-modernize-use-trailing-return-type,-readability-redundant-member-init'
|
||||
HeaderFilterRegex: '/(fairmq/)'
|
||||
|
@@ -6,8 +6,8 @@
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.11 FATAL_ERROR)
|
||||
cmake_policy(VERSION 3.11...3.15)
|
||||
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
|
||||
cmake_policy(VERSION 3.12...3.15)
|
||||
|
||||
# Project ######################################################################
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||
@@ -35,8 +35,6 @@ fairmq_build_option(BUILD_FAIRMQ "Build FairMQ library and devices."
|
||||
DEFAULT ON)
|
||||
fairmq_build_option(BUILD_TESTING "Build tests."
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||
fairmq_build_option(BUILD_NANOMSG_TRANSPORT "Build nanomsg transport."
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||
fairmq_build_option(BUILD_OFI_TRANSPORT "Build experimental OFI transport."
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||
fairmq_build_option(BUILD_SDK_COMMANDS "Build the FairMQ SDK commands."
|
||||
@@ -53,6 +51,8 @@ fairmq_build_option(BUILD_DOCS "Build FairMQ documentation."
|
||||
DEFAULT OFF)
|
||||
fairmq_build_option(FAST_BUILD "Fast production build. Not recommended for development."
|
||||
DEFAULT OFF)
|
||||
fairmq_build_option(USE_EXTERNAL_GTEST "Do not use bundled GTest. Not recommended."
|
||||
DEFAULT OFF)
|
||||
################################################################################
|
||||
|
||||
|
||||
@@ -65,11 +65,6 @@ set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
find_package2(PRIVATE nanomsg REQUIRED)
|
||||
set(PROJECT_nanomsg_VERSION 1.1.3) # Once upstream releases 1.1.5, we should bump again and use version check
|
||||
endif()
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
find_package2(PRIVATE asiofi REQUIRED
|
||||
VERSION 0.3.1
|
||||
@@ -79,12 +74,6 @@ if(BUILD_OFI_TRANSPORT)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
find_package2(PRIVATE msgpack REQUIRED
|
||||
VERSION 3.1.0
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
find_package2(PRIVATE Flatbuffers REQUIRED)
|
||||
endif()
|
||||
@@ -160,7 +149,9 @@ if(BUILD_FAIRMQ)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package2(PRIVATE GTest VERSION 1.7.0)
|
||||
if(USE_EXTERNAL_GTEST)
|
||||
find_package2(PRIVATE GTest VERSION 1.7.0)
|
||||
endif()
|
||||
if(NOT GTest_FOUND)
|
||||
build_bundled(GTest extern/googletest)
|
||||
find_package2(PRIVATE GTest REQUIRED)
|
||||
@@ -215,9 +206,6 @@ endif()
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS pmix_plugin)
|
||||
endif()
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS nanomsg_transport)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS ofi_transport)
|
||||
endif()
|
||||
@@ -320,16 +308,10 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||
endif()
|
||||
elseif(${dep} STREQUAL GTest)
|
||||
get_filename_component(prefix ${GTEST_INCLUDE_DIRS}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL msgpack)
|
||||
get_target_property(msgpack_include msgpackc-cxx INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_filename_component(prefix ${msgpack_include}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL asiofi)
|
||||
set(prefix ${asiofi_ROOT})
|
||||
elseif(${dep} STREQUAL OFI)
|
||||
get_filename_component(prefix ${${dep}_INCLUDE_DIRS}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL nanomsg)
|
||||
get_target_property(nn_include nanomsg INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_filename_component(prefix ${nn_include}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL DDS)
|
||||
set(prefix "${DDS_INSTALL_PREFIX}")
|
||||
elseif(${dep} STREQUAL Boost)
|
||||
@@ -378,12 +360,6 @@ else()
|
||||
set(tests_summary "${BRed} NO${CR} (enable with ${BMagenta}-DBUILD_TESTING=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}tests${CR} ${tests_summary}")
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
set(nn_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_NANOMSG_TRANSPORT=OFF${CR})")
|
||||
else()
|
||||
set(nn_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_NANOMSG_TRANSPORT=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}nanomsg_transport${CR} ${nn_summary}")
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(ofi_summary "${BGreen}YES${CR} EXPERIMENTAL (requires C++14) (disable with ${BMagenta}-DBUILD_OFI_TRANSPORT=OFF${CR})")
|
||||
else()
|
||||
|
@@ -4,6 +4,7 @@ Eulisse, Giulio
|
||||
Karabowicz, Radoslaw
|
||||
Kretz, Matthias <kretz@kde.org>
|
||||
Krzewicki, Mikolaj
|
||||
Lebedev, Andrey
|
||||
Mrnjavac, Teo <teo.m@cern.ch>
|
||||
Neskovic, Gvozden
|
||||
Richter, Matthias
|
||||
|
@@ -26,7 +26,6 @@ Set(configure_options "${configure_options};-DCTEST_USE_LAUNCHERS=${CTEST_USE_LA
|
||||
|
||||
Set(configure_options "${configure_options};-DDISABLE_COLOR=ON")
|
||||
Set(configure_options "${configure_options};-DCMAKE_PREFIX_PATH=$ENV{SIMPATH}")
|
||||
Set(configure_options "${configure_options};-DBUILD_NANOMSG_TRANSPORT=ON")
|
||||
# Set(configure_options "${configure_options};-DBUILD_OFI_TRANSPORT=ON")
|
||||
Set(configure_options "${configure_options};-DBUILD_DDS_PLUGIN=ON")
|
||||
Set(configure_options "${configure_options};-DBUILD_SDK=ON")
|
||||
|
10
README.md
10
README.md
@@ -21,7 +21,7 @@ FairMQ is designed to help implementing large-scale data processing workflows ne
|
||||
The core of FairMQ provides an abstract asynchronous message passing API with scalability protocols
|
||||
inspired by [ZeroMQ](https://github.com/zeromq/libzmq) (e.g. PUSH/PULL, PUB/SUB).
|
||||
FairMQ provides multiple implementations for its API (so-called "transports",
|
||||
e.g. `zeromq`, `shmem`, `nanomsg`, and `ofi` (in development)) to cover a variety of use cases
|
||||
e.g. `zeromq`, `shmem` and `ofi` (in development)) to cover a variety of use cases
|
||||
(e.g. inter-thread, inter-process, inter-node communication) and machines (e.g. Ethernet, Infiniband).
|
||||
In addition to this core functionality FairMQ provides a framework for creating "devices" - actors which
|
||||
are communicating through message passing. FairMQ does not only allow the user to use different transport but also to mix them; i.e: A Device can communicate using different transport on different channels at the same time. Device execution is modelled as a simple state machine that
|
||||
@@ -47,7 +47,7 @@ cmake --build fairmq_build --target install
|
||||
|
||||
Please consult the [manpages of your CMake version](https://cmake.org/cmake/help/latest/manual/cmake.1.html) for more options.
|
||||
|
||||
If dependencies are not installed in standard system directories, you can hint the installation location via `-DCMAKE_PREFIX_PATH=...` or per dependency via `-D{DEPENDENCY}_ROOT=...`. `{DEPENDENCY}` can be `GTEST`, `BOOST`, `FAIRLOGGER`, `ZEROMQ`, `MSGPACK`, `NANOMSG`, `OFI`, `PMIX`, `ASIO`, `ASIOFI` or `DDS` (`*_ROOT` variables can also be environment variables).
|
||||
If dependencies are not installed in standard system directories, you can hint the installation location via `-DCMAKE_PREFIX_PATH=...` or per dependency via `-D{DEPENDENCY}_ROOT=...`. `{DEPENDENCY}` can be `GTEST`, `BOOST`, `FAIRLOGGER`, `ZEROMQ`, `OFI`, `PMIX`, `ASIO`, `ASIOFI` or `DDS` (`*_ROOT` variables can also be environment variables).
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -86,7 +86,7 @@ If your project shares a dependency with FairMQ or if you want to omit a certain
|
||||
Optionally, you can require certain FairMQ package components and a minimum version:
|
||||
|
||||
```cmake
|
||||
find_package(FairMQ 1.1.0 COMPONENTS nanomsg_transport dds_plugin)
|
||||
find_package(FairMQ 1.1.0 COMPONENTS dds_plugin)
|
||||
```
|
||||
|
||||
When building FairMQ, CMake will print a summary table of all available package components.
|
||||
@@ -101,8 +101,6 @@ When building FairMQ, CMake will print a summary table of all available package
|
||||
* [Doxygen](http://www.doxygen.org/)
|
||||
* [FairLogger](https://github.com/FairRootGroup/FairLogger)
|
||||
* [GTest](https://github.com/google/googletest) (optionally bundled)
|
||||
* [Msgpack](https://msgpack.org/index.html)
|
||||
* [nanomsg](http://nanomsg.org/)
|
||||
* [PMIx](https://pmix.org/)
|
||||
* [ZeroMQ](http://zeromq.org/)
|
||||
|
||||
@@ -117,7 +115,6 @@ On command line:
|
||||
* `-DDISABLE_COLOR=ON` disables coloured console output.
|
||||
* `-DBUILD_TESTING=OFF` disables building of tests.
|
||||
* `-DBUILD_EXAMPLES=OFF` disables building of examples.
|
||||
* `-DBUILD_NANOMSG_TRANSPORT=ON` enables building of nanomsg transport.
|
||||
* `-DBUILD_OFI_TRANSPORT=ON` enables building of the experimental OFI transport.
|
||||
* `-DBUILD_DDS_PLUGIN=ON` enables building of the DDS plugin.
|
||||
* `-DBUILD_PMIX_PLUGIN=ON` enables building of the PMIx plugin.
|
||||
@@ -182,4 +179,3 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
|
||||
1. [DDS](docs/Plugins.md#731-dds)
|
||||
2. [PMIx](docs/Plugins.md#732-pmix)
|
||||
8. [Controller SDK](docs/SDK.md)
|
||||
|
||||
|
@@ -143,15 +143,17 @@ macro(set_fairmq_defaults)
|
||||
set(PROJECT_EXPORT_SET ${PROJECT_NAME}Targets)
|
||||
|
||||
# Configure build types
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" "RelWithDebInfo" "Nightly" "Profile" "Experimental" "AdressSan" "ThreadSan")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wshadow -Wall -Wextra")
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" "RelWithDebInfo" "Nightly" "Profile" "Experimental" "AddressSan" "ThreadSan")
|
||||
set(_warnings "-Wshadow -Wall -Wextra -Wpedantic")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g ${_warnings}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -Wshadow -Wall -Wextra -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_NIGHTLY "-O2 -g -Wshadow -Wall -Wextra")
|
||||
set(CMAKE_CXX_FLAGS_PROFILE "-g3 -Wshadow -Wall -Wextra -fno-inline -ftest-coverage -fprofile-arcs")
|
||||
set(CMAKE_CXX_FLAGS_EXPERIMENTAL "-O2 -g -Wshadow -Wall -Wextra -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_ADRESSSAN "-O2 -g -Wshadow -Wall -Wextra -fsanitize=address -fno-omit-frame-pointer")
|
||||
set(CMAKE_CXX_FLAGS_THREADSAN "-O2 -g -Wshadow -Wall -Wextra -fsanitize=thread")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g ${_warnings} -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_NIGHTLY "-O2 -g ${_warnings}")
|
||||
set(CMAKE_CXX_FLAGS_PROFILE "-g3 ${_warnings} -fno-inline -ftest-coverage -fprofile-arcs")
|
||||
set(CMAKE_CXX_FLAGS_EXPERIMENTAL "-O2 -g ${_warnings} -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_ADDRESSSAN "-O2 -g ${_warnings} -fsanitize=address -fno-omit-frame-pointer")
|
||||
set(CMAKE_CXX_FLAGS_THREADSAN "-O2 -g ${_warnings} -fsanitize=thread")
|
||||
unset(_warnings)
|
||||
|
||||
if(CMAKE_GENERATOR STREQUAL "Ninja" AND
|
||||
((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) OR
|
||||
@@ -522,7 +524,7 @@ macro(fairmq_build_option option description)
|
||||
if(${__requires_condition__})
|
||||
else()
|
||||
if(${option})
|
||||
message(WARNING "Cannot enable build option ${option}, depending option is not set: ${__requires_condition__}")
|
||||
message(FATAL_ERROR "Cannot enable build option ${option}, depending option is not set: ${__requires_condition__}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
@@ -18,7 +18,7 @@ Topology configuration is currently happening via setup scripts. This is very ru
|
||||
|
||||
## 1.2 Communication Patterns
|
||||
|
||||
FairMQ devices communicate via the communication patterns offered by ZeroMQ (or nanomsg): PUSH-PULL, PUB-SUB, REQ-REP, PAIR, [more info here](http://api.zeromq.org/4-0:zmq-socket). Each transport may provide further patterns.
|
||||
FairMQ devices communicate via the communication patterns offered by ZeroMQ: PUSH-PULL, PUB-SUB, REQ-REP, PAIR, [more info here](http://api.zeromq.org/4-0:zmq-socket). Each transport may provide further patterns.
|
||||
|
||||
## 1.3 State Machine
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
# 2. Transport Interface
|
||||
|
||||
The communication layer is available through the transport interface. Three interface implementations are currently available. Main implementation uses the [ZeroMQ](http://zeromq.org) library. Alternative implementation relies on the [nanomsg](http://nanomsg.org) library. Third transport implementation is using shared memory via boost::interprocess & ZeroMQ combination.
|
||||
The communication layer is available through the transport interface. Three interface implementations are currently available. Main implementation uses the [ZeroMQ](http://zeromq.org) library. Second transport implementation is using shared memory via boost::interprocess & ZeroMQ combination.
|
||||
|
||||
Here is an overview to give an idea how the interface is implemented:
|
||||
|
||||
@@ -10,20 +10,20 @@ Here is an overview to give an idea how the interface is implemented:
|
||||
|
||||
Currently, the transports have been tested to work with these communication patterns:
|
||||
|
||||
| | zeromq | nanomsg | shmem |
|
||||
| ------------- |--------| ------- | ----- |
|
||||
| PAIR | yes | yes | yes |
|
||||
| PUSH/PULL | yes | yes | yes |
|
||||
| PUB/SUB | yes | yes | no |
|
||||
| REQ/REP | yes | yes | yes |
|
||||
| | zeromq | shmem |
|
||||
| ------------- |--------| ----- |
|
||||
| PAIR | yes | yes |
|
||||
| PUSH/PULL | yes | yes |
|
||||
| PUB/SUB | yes | no |
|
||||
| REQ/REP | yes | yes |
|
||||
|
||||
The next table shows the supported address types for each transport implementation:
|
||||
|
||||
| | zeromq | nanomsg | shmem | comment |
|
||||
| ----------- | ------ | ------- | ----- | --------------------------------------------- |
|
||||
| `inproc://` | yes | yes | yes | in process: useful for unit testing |
|
||||
| `ipc://` | yes | yes | yes | inter process comm: useful on single machine |
|
||||
| `tcp://` | yes | yes | yes | useful for any communication, local or remote |
|
||||
| | zeromq | shmem | comment |
|
||||
| ----------- | ------ | ----- | --------------------------------------------- |
|
||||
| `inproc://` | yes | yes | in process: useful for unit testing |
|
||||
| `ipc://` | yes | yes | inter process comm: useful on single machine |
|
||||
| `tcp://` | yes | yes | useful for any communication, local or remote |
|
||||
|
||||
## 2.1 Message
|
||||
|
||||
|
@@ -34,11 +34,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-1-1.sh.in ${CMAKE_CURRENT_BIN
|
||||
add_test(NAME Example.1-1.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh zeromq)
|
||||
set_tests_properties(Example.1-1.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.1-1.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh nanomsg)
|
||||
set_tests_properties(Example.1-1.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.1-1.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh shmem)
|
||||
set_tests_properties(Example.1-1.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
|
@@ -42,11 +42,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-1-n-1.sh.in ${CMAKE_CURRENT_B
|
||||
add_test(NAME Example.1-n-1.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh zeromq)
|
||||
set_tests_properties(Example.1-n-1.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.1-n-1.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh nanomsg)
|
||||
set_tests_properties(Example.1-n-1.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.1-n-1.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh shmem)
|
||||
set_tests_properties(Example.1-n-1.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
|
@@ -13,9 +13,9 @@ add_subdirectory(copypush)
|
||||
add_subdirectory(dds)
|
||||
add_subdirectory(multipart)
|
||||
add_subdirectory(multiple-channels)
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_subdirectory(multiple-transports)
|
||||
endif()
|
||||
add_subdirectory(multiple-transports)
|
||||
add_subdirectory(n-m)
|
||||
add_subdirectory(qc)
|
||||
add_subdirectory(readout)
|
||||
add_subdirectory(region)
|
||||
add_subdirectory(req-rep)
|
||||
|
@@ -6,41 +6,50 @@ Set of FairMQ examples. More examples that combine FairMQ with FairRoot can be f
|
||||
|
||||
A simple topology of two devices - **Sampler** and **Sink**. **Sampler** sends data to **Sink** with the **PUSH-PULL** pattern.
|
||||
|
||||
|
||||
## 1-n-1
|
||||
|
||||
A simple topology of three device types - **Sampler**, **Processor** and **Sink**. **Sampler** sends data to one or more **Processor**s, who modify the data and send it to one **Sink**. Transport with the **PUSH-PULL** pattern. The example also shows the configuration via JSON files, as oposed to `--channel-config` that is used by other examples.
|
||||
|
||||
## Built-in devices
|
||||
|
||||
## DDS
|
||||
|
||||
This example demonstrates usage of the Dynamic Deployment System ([DDS](http://dds.gsi.de/)) to dynamically deploy and configure a topology of devices. The topology is similar to those of Example 2, but now it can be easily distributed on different computing nodes without the need for manual reconfiguration of the devices.
|
||||
|
||||
Usage of generic devies provided with FairMQ.
|
||||
|
||||
## Copy & Push
|
||||
|
||||
A topology consisting of one **Sampler** and two **Sink**s. The **Sampler** uses the `Copy` method to send the same data to both sinks with the **PUSH-PULL** pattern. In countrary to the **PUB-SUB** pattern, this ensures that all receivers are connected and no data is lost, but requires additional channels to be configured.
|
||||
|
||||
## DDS
|
||||
|
||||
## Request & Reply
|
||||
This example demonstrates usage of the Dynamic Deployment System ([DDS](http://dds.gsi.de/)) to dynamically deploy and configure a topology of devices. The topology is similar to those of Example 2, but now it can be easily distributed on different computing nodes without the need for manual reconfiguration of the devices.
|
||||
|
||||
This topology contains two devices that communicate with each other via the **REQ-REP** pettern. Bidirectional communication via a single socket.
|
||||
## Multipart
|
||||
|
||||
This example shows how to send a multipart message from one device to the other. (two parts message parts - header and body).
|
||||
|
||||
## Multiple Channels
|
||||
|
||||
This example demonstrates how to work with multiple channels and multiplex between them.
|
||||
|
||||
## Multiple Transports
|
||||
|
||||
## Sending Multipart messages
|
||||
This examples shows how to combine different channel transports (zeromq/shmem) inside of one device and/or topology.
|
||||
|
||||
This example shows how to send a multipart message from one device to the other. (two parts message parts - header and body).
|
||||
## n-m
|
||||
|
||||
A topology consisting of three layers of devices: synchronizer -> n * senders -> m * receivers.
|
||||
|
||||
## Multiple Transports example
|
||||
## QC
|
||||
|
||||
This examples shows how to combine different channel transports (zeromq/nanomsg/shmem) inside of one device and/or topology.
|
||||
A topology consisting of 4 devices - Sampler, QCDispatcher, QCTask and Sink. The data flows from Sampler through QCDispatcher to Sink. On demand - by setting the corresponding configuration property - the QCDispatcher device will duplicate the data to the QCTask device. The property is set by the topology controller, in this example this is the `fairmq-dds-command-ui` utility.
|
||||
|
||||
## Region example
|
||||
## Readout
|
||||
|
||||
Two example topologies of setups to be distributed to two kinds of nodes - detector readout node and processing node. Detector readout node contains readout process, data builder and data sender (and optionally an additional processor), while processing node contains data receiver devices. communication within readout nodes is done via unmanaged region through shared memory transport.
|
||||
|
||||
## Region
|
||||
|
||||
This example demonstrates the use of a more advanced feature - UnmanagedRegion, that can be used to create a buffer through one of FairMQ transports. The contents of this buffer are managed by the user, who can also create messages out of sub-buffers of the created buffer. Such feature can be interesting in environments that have special requirements by the hardware that writes the data, to keep the transfer efficient (e.g. shared memory).
|
||||
|
||||
## Request & Reply
|
||||
|
||||
This topology contains two devices that communicate with each other via the **REQ-REP** pettern. Bidirectional communication via a single socket.
|
||||
|
@@ -17,22 +17,12 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-builtin-devices.sh.in ${CMAKE
|
||||
add_test(NAME Example.BuiltinDevices.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh zeromq)
|
||||
set_tests_properties(Example.BuiltinDevices.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.BuiltinDevices.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh nanomsg)
|
||||
set_tests_properties(Example.BuiltinDevices.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.BuiltinDevices.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh shmem)
|
||||
set_tests_properties(Example.BuiltinDevices.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
add_test(NAME Example.BuiltinDevices.multipart.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh zeromq true 2)
|
||||
set_tests_properties(Example.BuiltinDevices.multipart.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.BuiltinDevices.multipart.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh nanomsg true 2)
|
||||
set_tests_properties(Example.BuiltinDevices.multipart.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.BuiltinDevices.multipart.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh shmem true 2)
|
||||
set_tests_properties(Example.BuiltinDevices.multipart.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
|
@@ -35,11 +35,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-copypush.sh.in ${CMAKE_CURREN
|
||||
add_test(NAME Example.CopyPush.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh zeromq)
|
||||
set_tests_properties(Example.CopyPush.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.CopyPush.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh nanomsg)
|
||||
set_tests_properties(Example.CopyPush.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.CopyPush.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh shmem)
|
||||
set_tests_properties(Example.CopyPush.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
|
||||
|
@@ -7,12 +7,12 @@
|
||||
################################################################################
|
||||
|
||||
add_library(ExampleDDSLib STATIC
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Processor.cxx"
|
||||
"Processor.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Processor.cxx"
|
||||
"Processor.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
)
|
||||
|
||||
target_link_libraries(ExampleDDSLib PUBLIC FairMQ)
|
||||
@@ -28,6 +28,7 @@ target_link_libraries(fairmq-ex-dds-sink PRIVATE ExampleDDSLib)
|
||||
|
||||
add_custom_target(ExampleDDS DEPENDS fairmq-ex-dds-sampler fairmq-ex-dds-processor fairmq-ex-dds-sink)
|
||||
|
||||
list(JOIN Boost_LIBRARY_DIRS ":" LIB_DIR)
|
||||
set(BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_BINARY_DIR}/fairmq/plugins/DDS)
|
||||
set(DATA_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-dds-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology.xml @ONLY)
|
||||
@@ -38,23 +39,24 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-dds.sh.in ${CMAKE_CUR
|
||||
|
||||
# test
|
||||
if(DDS_FOUND)
|
||||
add_test(NAME Example.DDS.localhost COMMAND ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh localhost)
|
||||
set_tests_properties(Example.DDS.localhost PROPERTIES
|
||||
add_test(NAME Example.DDS.localhost COMMAND ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh localhost)
|
||||
set_tests_properties(Example.DDS.localhost PROPERTIES
|
||||
TIMEOUT 15
|
||||
RUN_SERIAL true
|
||||
PASS_REGULAR_EXPRESSION "Example successful"
|
||||
)
|
||||
)
|
||||
endif()
|
||||
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-dds-sampler
|
||||
fairmq-ex-dds-processor
|
||||
fairmq-ex-dds-sink
|
||||
TARGETS
|
||||
fairmq-ex-dds-sampler
|
||||
fairmq-ex-dds-processor
|
||||
fairmq-ex-dds-sink
|
||||
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
# configure run script with different executable paths for build and for install directories
|
||||
@@ -66,30 +68,30 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-dds-env.sh ${CMAKE_CURRENT_
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh_install @ONLY)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology.xml_install
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||
RENAME ex-dds-topology.xml
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology.xml_install
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||
RENAME ex-dds-topology.xml
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology-infinite.xml_install
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||
RENAME ex-dds-topology-infinite.xml
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology-infinite.xml_install
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||
RENAME ex-dds-topology-infinite.xml
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-hosts.cfg
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-hosts.cfg
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-dds-env.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-ex-dds-env.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-dds-env.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-ex-dds-env.sh
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-dds.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-dds.sh
|
||||
)
|
||||
|
@@ -9,3 +9,8 @@
|
||||
################################################################################
|
||||
|
||||
export PATH=@BIN_DIR@:$PATH
|
||||
|
||||
OS=$(uname -s 2>&1)
|
||||
if [ "$OS" == "Darwin" ]; then
|
||||
export DYLD_LIBRARY_PATH=@LIB_DIR@:$DYLD_LIBRARY_PATH
|
||||
fi
|
||||
|
@@ -39,12 +39,12 @@ fi
|
||||
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||
dds-info --idle-count --wait ${requiredNofSlots}
|
||||
|
||||
topologyFile=@DATA_DIR@/ex-dds-topology.xml
|
||||
echo "TOPOLOGY FILE: ${topologyFile}"
|
||||
echo "TOPOLOGY NAME: $(dds-topology --disable-validation --topology-name ${topologyFile})"
|
||||
export FAIRMQ_DDS_TOPO_FILE=@DATA_DIR@/ex-dds-topology.xml
|
||||
echo "TOPOLOGY FILE: ${FAIRMQ_DDS_TOPO_FILE}"
|
||||
echo "TOPOLOGY NAME: $(dds-topology --disable-validation --topology-name ${FAIRMQ_DDS_TOPO_FILE})"
|
||||
|
||||
dds-info --active-topology
|
||||
dds-topology --activate ${topologyFile}
|
||||
dds-topology --activate ${FAIRMQ_DDS_TOPO_FILE}
|
||||
dds-info --active-topology
|
||||
echo "...waiting for ${requiredNofSlots} executing slots..."
|
||||
dds-info --executing-count --wait ${requiredNofSlots}
|
||||
@@ -52,21 +52,20 @@ dds-info --executing-count --wait ${requiredNofSlots}
|
||||
echo "------------------------"
|
||||
echo "...waiting for Topology to finish..."
|
||||
# TODO Retrieve number of devices from DDS topology API instead of having the user pass it explicitely
|
||||
fairmq-dds-command-ui -w "IDLE" -n ${requiredNofSlots}
|
||||
fairmq-dds-command-ui -c i -w "INITIALIZING DEVICE" -n ${requiredNofSlots}
|
||||
fairmq-dds-command-ui -c k -w "INITIALIZED" -n ${requiredNofSlots}
|
||||
fairmq-dds-command-ui -c b -w "BOUND" -n ${requiredNofSlots}
|
||||
fairmq-dds-command-ui -c x -w "DEVICE READY" -n ${requiredNofSlots}
|
||||
fairmq-dds-command-ui -c j -w "READY" -n ${requiredNofSlots}
|
||||
fairmq-dds-command-ui -w "IDLE"
|
||||
fairmq-dds-command-ui -c i
|
||||
fairmq-dds-command-ui -c k
|
||||
fairmq-dds-command-ui -c b
|
||||
fairmq-dds-command-ui -c x
|
||||
fairmq-dds-command-ui -c j
|
||||
fairmq-dds-command-ui -c r
|
||||
sampler_and_sink="main/(Sampler|Sink)"
|
||||
# processors="main/ProcessorGroup/Processor"
|
||||
fairmq-dds-command-ui -p $sampler_and_sink -w "RUNNING->READY" -n 2
|
||||
sampler_and_sink="main/(Sampler|Sink).*"
|
||||
fairmq-dds-command-ui -w "RUNNING->READY" -p $sampler_and_sink
|
||||
echo "...$sampler_and_sink are READY, sending shutdown..."
|
||||
fairmq-dds-command-ui -c s -w "RUNNING->READY" -n ${requiredNofSlots}
|
||||
fairmq-dds-command-ui -c t -w "DEVICE READY" -n ${requiredNofSlots}
|
||||
fairmq-dds-command-ui -c d -w "IDLE" -n ${requiredNofSlots}
|
||||
fairmq-dds-command-ui -c q -w "EXITING" -n ${requiredNofSlots}
|
||||
fairmq-dds-command-ui -c s
|
||||
fairmq-dds-command-ui -c t
|
||||
fairmq-dds-command-ui -c d
|
||||
fairmq-dds-command-ui -c q
|
||||
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||
dds-info --idle-count --wait ${requiredNofSlots}
|
||||
echo "------------------------"
|
||||
|
@@ -34,11 +34,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multipart.sh.in ${CMAKE_CURRE
|
||||
add_test(NAME Example.Multipart.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh zeromq)
|
||||
set_tests_properties(Example.Multipart.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 7 parts")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.Multipart.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh nanomsg)
|
||||
set_tests_properties(Example.Multipart.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 7 parts")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.Multipart.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh shmem)
|
||||
set_tests_properties(Example.Multipart.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 7 parts")
|
||||
|
||||
|
@@ -39,11 +39,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multiple-channels.sh.in ${CMA
|
||||
add_test(NAME Example.MultipleChannels.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh zeromq)
|
||||
set_tests_properties(Example.MultipleChannels.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.MultipleChannels.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh nanomsg)
|
||||
set_tests_properties(Example.MultipleChannels.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
endif()
|
||||
|
||||
# install
|
||||
|
||||
install(
|
||||
|
@@ -1,12 +1,12 @@
|
||||
Multiple Transports example
|
||||
===========================
|
||||
|
||||
This example demonstrates use of multiple transports (zeromq/nanomsg/shmem) within the same topology and/or device. It is a simple topology consisting of two samplers and a sink. The devices are connected via 3 channels:
|
||||
This example demonstrates use of multiple transports (zeromq/shmem) within the same topology and/or device. It is a simple topology consisting of two samplers and a sink. The devices are connected via 3 channels:
|
||||
|
||||

|
||||
|
||||
Each device has main transport that it uses. By default it is ZeroMQ, and can be overriden via the `--transport` cmd option. The device will initialize additional transports if any of the channels have them configured (e.g. as an option to `--channel-config`).
|
||||
|
||||
In this example sampler1 and sink are started with `--transport shmem`, making shared memory their main transport, sampler2 with `--transport nanomsg`. Additionally, the ack channel is configured to use zeromq as its transport.
|
||||
In this example sampler1 and sink are started with `--transport shmem`, making shared memory their main transport, sampler2 with `--transport zeromq`. Additionally, the ack channel is configured to use zeromq as its transport.
|
||||
|
||||
The main two things that a transport does is transfer of data and allocation of memory for the messages. By default, new messages are created via the main device transport. If a message has been created with one transport and is to be transferred with another, it has to be copied into a new message of the target transport. This happens automatically behind the scenes. To avoid this copy the device can create messages via `NewMessageFor(const string& channelName, int subChannelIndex, ...)` method, that creates the messages via the transport of the given channel (check sampler1 and sink for an example) or as the channel directly to create a message.
|
||||
|
@@ -13,7 +13,7 @@ xterm -geometry 80x30+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER1 &
|
||||
SAMPLER2="fairmq-ex-multiple-transports-sampler2"
|
||||
SAMPLER2+=" --id sampler2"
|
||||
SAMPLER2+=" --severity debug"
|
||||
SAMPLER2+=" --transport nanomsg"
|
||||
SAMPLER2+=" --transport shmem"
|
||||
SAMPLER2+=" --channel-config name=data2,type=push,method=bind,address=tcp://127.0.0.1:5556"
|
||||
xterm -geometry 80x30+0+450 -hold -e @EX_BIN_DIR@/$SAMPLER2 &
|
||||
|
||||
@@ -22,6 +22,6 @@ SINK+=" --id sink1"
|
||||
SINK+=" --severity debug"
|
||||
SINK+=" --transport shmem"
|
||||
SINK+=" --channel-config name=data1,type=pull,method=connect,address=tcp://127.0.0.1:5555"
|
||||
SINK+=" name=data2,type=pull,method=connect,address=tcp://127.0.0.1:5556,transport=nanomsg"
|
||||
SINK+=" name=data2,type=pull,method=connect,address=tcp://127.0.0.1:5556,transport=shmem"
|
||||
SINK+=" name=ack,type=pub,method=connect,address=tcp://127.0.0.1:5557,transport=zeromq"
|
||||
xterm -geometry 80x30+500+225 -hold -e @EX_BIN_DIR@/$SINK &
|
||||
|
@@ -14,7 +14,7 @@ SINK+=" --max-iterations 1"
|
||||
SINK+=" --control static --color false"
|
||||
SINK+=" --transport shmem"
|
||||
SINK+=" --channel-config name=data1,type=pull,method=connect,address=tcp://127.0.0.1:5555"
|
||||
SINK+=" name=data2,type=pull,method=connect,address=tcp://127.0.0.1:5556,transport=nanomsg"
|
||||
SINK+=" name=data2,type=pull,method=connect,address=tcp://127.0.0.1:5556,transport=zeromq"
|
||||
SINK+=" name=ack,type=pub,method=connect,address=tcp://127.0.0.1:5557,transport=zeromq"
|
||||
@CMAKE_CURRENT_BINARY_DIR@/$SINK &
|
||||
SINK_PID=$!
|
||||
@@ -37,7 +37,7 @@ SAMPLER2+=" --session $SESSION"
|
||||
SAMPLER2+=" --verbosity veryhigh"
|
||||
SAMPLER2+=" --max-iterations 1"
|
||||
SAMPLER2+=" --control static --color false"
|
||||
SAMPLER2+=" --transport nanomsg"
|
||||
SAMPLER2+=" --transport zeromq"
|
||||
SAMPLER2+=" --channel-config name=data2,type=push,method=bind,address=tcp://127.0.0.1:5556"
|
||||
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER2 &
|
||||
SAMPLER2_PID=$!
|
||||
|
99
examples/n-m/CMakeLists.txt
Normal file
99
examples/n-m/CMakeLists.txt
Normal file
@@ -0,0 +1,99 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
add_executable(fairmq-ex-n-m-synchronizer runSynchronizer.cxx)
|
||||
target_link_libraries(fairmq-ex-n-m-synchronizer PRIVATE FairMQ)
|
||||
|
||||
add_executable(fairmq-ex-n-m-sender runSender.cxx)
|
||||
target_link_libraries(fairmq-ex-n-m-sender PRIVATE FairMQ)
|
||||
|
||||
add_executable(fairmq-ex-n-m-receiver runReceiver.cxx)
|
||||
target_link_libraries(fairmq-ex-n-m-receiver PRIVATE FairMQ)
|
||||
|
||||
add_custom_target(ExampleNM DEPENDS fairmq-ex-n-m-synchronizer fairmq-ex-n-m-sender fairmq-ex-n-m-receiver)
|
||||
|
||||
list(JOIN Boost_LIBRARY_DIRS ":" LIB_DIR)
|
||||
set(BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_BINARY_DIR}/fairmq/plugins/DDS)
|
||||
set(DATA_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-n-m-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-topology.xml @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-n-m-pair-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-pair-topology.xml @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-n-m-env.sh ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-n-m-env.sh @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m.sh @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-pair.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair.sh @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-dds.sh @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-pair-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair-dds.sh @ONLY)
|
||||
|
||||
# test
|
||||
if(DDS_FOUND)
|
||||
add_test(NAME Example.N-M.localhost COMMAND ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-dds.sh localhost)
|
||||
set_tests_properties(Example.N-M.localhost PROPERTIES TIMEOUT 15 RUN_SERIAL true PASS_REGULAR_EXPRESSION "Example successful")
|
||||
add_test(NAME Example.N-M-pair.localhost COMMAND ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair-dds.sh localhost)
|
||||
set_tests_properties(Example.N-M-pair.localhost PROPERTIES TIMEOUT 15 RUN_SERIAL true PASS_REGULAR_EXPRESSION "Example successful")
|
||||
endif()
|
||||
|
||||
# install
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-n-m-synchronizer
|
||||
fairmq-ex-n-m-sender
|
||||
fairmq-ex-n-m-receiver
|
||||
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
# configure run script with different executable paths for build and for install directories
|
||||
set(BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
|
||||
set(DATA_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_DATADIR})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-n-m-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-topology.xml_install @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-n-m-pair-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-pair-topology.xml_install @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-n-m-env.sh ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-n-m-env.sh_install @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m.sh_install @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-pair.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair.sh_install @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-dds.sh_install @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-pair-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair-dds.sh_install @ONLY)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-topology.xml_install
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||
RENAME ex-n-m-topology.xml
|
||||
)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-pair-topology.xml_install
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||
RENAME ex-n-m-pair-topology.xml
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-n-m-env.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-ex-n-m-env.sh
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-n-m.sh
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-n-m-pair.sh
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-dds.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-n-m-dds.sh
|
||||
)
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair-dds.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-n-m-pair-dds.sh
|
||||
)
|
@@ -5,31 +5,20 @@
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
#ifndef FAIR_MQ_EXAMPLE_N_M_HEADER_H
|
||||
#define FAIR_MQ_EXAMPLE_N_M_HEADER_H
|
||||
|
||||
#include "FairMQUnmanagedRegionNN.h"
|
||||
#include "FairMQLogger.h"
|
||||
#include <cstdint>
|
||||
|
||||
using namespace std;
|
||||
|
||||
FairMQUnmanagedRegionNN::FairMQUnmanagedRegionNN(const size_t size, FairMQRegionCallback callback, const std::string& /*path = "" */, int /*flags = 0 */)
|
||||
: fBuffer(malloc(size))
|
||||
, fSize(size)
|
||||
, fCallback(callback)
|
||||
namespace example_n_m
|
||||
{
|
||||
}
|
||||
|
||||
void* FairMQUnmanagedRegionNN::GetData() const
|
||||
struct Header
|
||||
{
|
||||
return fBuffer;
|
||||
}
|
||||
std::uint16_t id;
|
||||
int senderIndex;
|
||||
};
|
||||
|
||||
size_t FairMQUnmanagedRegionNN::GetSize() const
|
||||
{
|
||||
return fSize;
|
||||
}
|
||||
} // namespace example_n_m
|
||||
|
||||
FairMQUnmanagedRegionNN::~FairMQUnmanagedRegionNN()
|
||||
{
|
||||
LOG(debug) << "destroying region";
|
||||
free(fBuffer);
|
||||
}
|
||||
#endif /* FAIR_MQ_EXAMPLE_N_M_HEADER_H */
|
4
examples/n-m/README.md
Normal file
4
examples/n-m/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
N-M
|
||||
==========================
|
||||
|
||||
A topology consisting of three layers of devices: synchronizer -> sender(s) -> receiver(s). Senders distribute data to receivers based on the data id contained in the message from the synchronizer (same id goes to the same receiver from every sender). The senders send the data in a non-blocking fashion - if queue is full or receiver is down, data is discarded. Two configurations are provided - one using push/pull channels between senders/receivers, another using pair channels. In push/pull case there is only one receiving channel on the receiver device. In pair case there are as many receiver (sub-)channels as there are senders.
|
44
examples/n-m/ex-n-m-pair-topology.xml
Normal file
44
examples/n-m/ex-n-m-pair-topology.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<topology name="myTopology">
|
||||
|
||||
<var name="numSenders" value="3" />
|
||||
<var name="numReceivers" value="4" />
|
||||
|
||||
<property name="fmqchan_sync" />
|
||||
<property name="fmqchan_data" />
|
||||
|
||||
<decltask name="Synchronizer">
|
||||
<exe reachable="true">fairmq-ex-n-m-synchronizer --id sync --rate 100 --color false -P dds --channel-config name=sync,type=pub,method=bind</exe>
|
||||
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||
<properties>
|
||||
<name access="write">fmqchan_sync</id>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<decltask name="Sender">
|
||||
<exe reachable="true">fairmq-ex-n-m-sender --id sender%taskIndex% --timeframe-size 100000 --num-receivers ${numReceivers} --color false -P dds --channel-config name=sync,type=sub,method=connect name=data,type=pair,method=connect,numSockets=${numReceivers} --dds-i data:%taskIndex%</exe>
|
||||
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||
<properties>
|
||||
<name access="read">fmqchan_sync</id>
|
||||
<name access="read">fmqchan_data</id>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<decltask name="Receiver">
|
||||
<exe reachable="true">fairmq-ex-n-m-receiver --id receiver%taskIndex% --num-senders ${numSenders} --color false -P dds --max-timeframes 10 --channel-config name=data,type=pair,method=bind,numSockets=${numSenders}</exe>
|
||||
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||
<properties>
|
||||
<name access="write">fmqchan_data</id>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<main name="main">
|
||||
<task>Synchronizer</task>
|
||||
<group name="Senders" n="${numSenders}">
|
||||
<task>Sender</task>
|
||||
</group>
|
||||
<group name="Receivers" n="${numReceivers}">
|
||||
<task>Receiver</task>
|
||||
</group>
|
||||
</main>
|
||||
|
||||
</topology>
|
44
examples/n-m/ex-n-m-topology.xml
Normal file
44
examples/n-m/ex-n-m-topology.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<topology name="myTopology">
|
||||
|
||||
<var name="numSenders" value="3" />
|
||||
<var name="numReceivers" value="4" />
|
||||
|
||||
<property name="fmqchan_sync" />
|
||||
<property name="fmqchan_data" />
|
||||
|
||||
<decltask name="Synchronizer">
|
||||
<exe reachable="true">fairmq-ex-n-m-synchronizer --id sync --rate 100 --color false -P dds --channel-config name=sync,type=pub,method=bind</exe>
|
||||
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||
<properties>
|
||||
<name access="write">fmqchan_sync</id>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<decltask name="Sender">
|
||||
<exe reachable="true">fairmq-ex-n-m-sender --id sender%taskIndex% --timeframe-size 100000 --num-receivers ${numReceivers} --color false -P dds --channel-config name=sync,type=sub,method=connect name=data,type=push,method=connect,numSockets=${numReceivers}</exe>
|
||||
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||
<properties>
|
||||
<name access="read">fmqchan_sync</id>
|
||||
<name access="read">fmqchan_data</id>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<decltask name="Receiver">
|
||||
<exe reachable="true">fairmq-ex-n-m-receiver --id receiver%taskIndex% --num-senders ${numSenders} --color false -P dds --max-timeframes 10 --channel-config name=data,type=pull,method=bind</exe>
|
||||
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||
<properties>
|
||||
<name access="write">fmqchan_data</id>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<main name="main">
|
||||
<task>Synchronizer</task>
|
||||
<group name="Senders" n="${numSenders}">
|
||||
<task>Sender</task>
|
||||
</group>
|
||||
<group name="Receivers" n="${numReceivers}">
|
||||
<task>Receiver</task>
|
||||
</group>
|
||||
</main>
|
||||
|
||||
</topology>
|
16
examples/n-m/fairmq-ex-n-m-env.sh
Executable file
16
examples/n-m/fairmq-ex-n-m-env.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
################################################################################
|
||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
export PATH=@BIN_DIR@:$PATH
|
||||
|
||||
OS=$(uname -s 2>&1)
|
||||
if [ "$OS" == "Darwin" ]; then
|
||||
export DYLD_LIBRARY_PATH=@LIB_DIR@:$DYLD_LIBRARY_PATH
|
||||
fi
|
76
examples/n-m/fairmq-start-ex-n-m-dds.sh.in
Executable file
76
examples/n-m/fairmq-start-ex-n-m-dds.sh.in
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
|
||||
################################################################################
|
||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
set -e
|
||||
|
||||
cleanup() {
|
||||
dds-session stop $1
|
||||
echo "CLEANUP PERFORMED"
|
||||
}
|
||||
|
||||
source @DDS_INSTALL_PREFIX@/DDS_env.sh
|
||||
export PATH=@BIN_DIR@:$PATH
|
||||
|
||||
exec 5>&1
|
||||
output=$(dds-session start | tee >(cat - >&5))
|
||||
export DDS_SESSION_ID=$(echo ${output} | grep "DDS session ID: " | cut -d' ' -f4)
|
||||
echo "SESSION ID: ${DDS_SESSION_ID}"
|
||||
|
||||
trap "cleanup ${DDS_SESSION_ID}" EXIT
|
||||
|
||||
requiredNofSlots=8
|
||||
dds-submit -r localhost --slots ${requiredNofSlots}
|
||||
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||
dds-info --idle-count --wait ${requiredNofSlots}
|
||||
|
||||
export FAIRMQ_DDS_TOPO_FILE=@DATA_DIR@/ex-n-m-topology.xml
|
||||
echo "TOPOLOGY FILE: ${FAIRMQ_DDS_TOPO_FILE}"
|
||||
echo "TOPOLOGY NAME: $(dds-topology --disable-validation --topology-name ${FAIRMQ_DDS_TOPO_FILE})"
|
||||
|
||||
dds-info --active-topology
|
||||
dds-topology --activate ${FAIRMQ_DDS_TOPO_FILE}
|
||||
dds-info --active-topology
|
||||
echo "...waiting for ${requiredNofSlots} executing slots..."
|
||||
dds-info --executing-count --wait ${requiredNofSlots}
|
||||
|
||||
echo "------------------------"
|
||||
echo "...waiting for Topology to finish..."
|
||||
# TODO Retrieve number of devices from DDS topology API instead of having the user pass it explicitely
|
||||
fairmq-dds-command-ui -w "IDLE"
|
||||
fairmq-dds-command-ui -c i
|
||||
fairmq-dds-command-ui -c k
|
||||
fairmq-dds-command-ui -c b
|
||||
fairmq-dds-command-ui -c x
|
||||
fairmq-dds-command-ui -c j
|
||||
fairmq-dds-command-ui -c r
|
||||
receivers="main/Receivers.*"
|
||||
fairmq-dds-command-ui -w "RUNNING->READY" -p $receivers
|
||||
echo "All receivers transitioned from RUNNING to READY"
|
||||
fairmq-dds-command-ui -c s
|
||||
fairmq-dds-command-ui -c t
|
||||
fairmq-dds-command-ui -c d
|
||||
fairmq-dds-command-ui -c q
|
||||
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||
dds-info --idle-count --wait ${requiredNofSlots}
|
||||
echo "------------------------"
|
||||
|
||||
dds-info --active-topology
|
||||
dds-topology --stop
|
||||
dds-info --active-topology
|
||||
|
||||
dds-agent-cmd getlog -a
|
||||
logDir="${wrkDir}/logs"
|
||||
for file in $(find "${logDir}" -name "*.tar.gz"); do tar -xf ${file} -C "${logDir}" ; done
|
||||
echo "AGENT LOG FILES IN: ${logDir}"
|
||||
|
||||
# This string is used by ctest to detect success
|
||||
echo "Example successful :)"
|
||||
|
||||
# Cleanup function is called by EXIT trap
|
76
examples/n-m/fairmq-start-ex-n-m-pair-dds.sh.in
Executable file
76
examples/n-m/fairmq-start-ex-n-m-pair-dds.sh.in
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
|
||||
################################################################################
|
||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
set -e
|
||||
|
||||
cleanup() {
|
||||
dds-session stop $1
|
||||
echo "CLEANUP PERFORMED"
|
||||
}
|
||||
|
||||
source @DDS_INSTALL_PREFIX@/DDS_env.sh
|
||||
export PATH=@BIN_DIR@:$PATH
|
||||
|
||||
exec 5>&1
|
||||
output=$(dds-session start | tee >(cat - >&5))
|
||||
export DDS_SESSION_ID=$(echo ${output} | grep "DDS session ID: " | cut -d' ' -f4)
|
||||
echo "SESSION ID: ${DDS_SESSION_ID}"
|
||||
|
||||
trap "cleanup ${DDS_SESSION_ID}" EXIT
|
||||
|
||||
requiredNofSlots=8
|
||||
dds-submit -r localhost --slots ${requiredNofSlots}
|
||||
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||
dds-info --idle-count --wait ${requiredNofSlots}
|
||||
|
||||
export FAIRMQ_DDS_TOPO_FILE=@DATA_DIR@/ex-n-m-pair-topology.xml
|
||||
echo "TOPOLOGY FILE: ${FAIRMQ_DDS_TOPO_FILE}"
|
||||
echo "TOPOLOGY NAME: $(dds-topology --disable-validation --topology-name ${FAIRMQ_DDS_TOPO_FILE})"
|
||||
|
||||
dds-info --active-topology
|
||||
dds-topology --activate ${FAIRMQ_DDS_TOPO_FILE}
|
||||
dds-info --active-topology
|
||||
echo "...waiting for ${requiredNofSlots} executing slots..."
|
||||
dds-info --executing-count --wait ${requiredNofSlots}
|
||||
|
||||
echo "------------------------"
|
||||
echo "...waiting for Topology to finish..."
|
||||
# TODO Retrieve number of devices from DDS topology API instead of having the user pass it explicitely
|
||||
fairmq-dds-command-ui -w "IDLE"
|
||||
fairmq-dds-command-ui -c i
|
||||
fairmq-dds-command-ui -c k
|
||||
fairmq-dds-command-ui -c b
|
||||
fairmq-dds-command-ui -c x
|
||||
fairmq-dds-command-ui -c j
|
||||
fairmq-dds-command-ui -c r
|
||||
receivers="main/Receivers.*"
|
||||
fairmq-dds-command-ui -w "RUNNING->READY" -p $receivers
|
||||
echo "All receivers transitioned from RUNNING to READY"
|
||||
fairmq-dds-command-ui -c s
|
||||
fairmq-dds-command-ui -c t
|
||||
fairmq-dds-command-ui -c d
|
||||
fairmq-dds-command-ui -c q
|
||||
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||
dds-info --idle-count --wait ${requiredNofSlots}
|
||||
echo "------------------------"
|
||||
|
||||
dds-info --active-topology
|
||||
dds-topology --stop
|
||||
dds-info --active-topology
|
||||
|
||||
dds-agent-cmd getlog -a
|
||||
logDir="${wrkDir}/logs"
|
||||
for file in $(find "${logDir}" -name "*.tar.gz"); do tar -xf ${file} -C "${logDir}" ; done
|
||||
echo "AGENT LOG FILES IN: ${logDir}"
|
||||
|
||||
# This string is used by ctest to detect success
|
||||
echo "Example successful :)"
|
||||
|
||||
# Cleanup function is called by EXIT trap
|
60
examples/n-m/fairmq-start-ex-n-m-pair.sh.in
Executable file
60
examples/n-m/fairmq-start-ex-n-m-pair.sh.in
Executable file
@@ -0,0 +1,60 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PATH=@BIN_DIR@:$PATH
|
||||
|
||||
SYNC="fairmq-ex-n-m-synchronizer"
|
||||
SYNC+=" --id Sync"
|
||||
SYNC+=" --channel-config name=sync,type=pub,method=bind,address=tcp://localhost:8010"
|
||||
SYNC+=" --rate 100"
|
||||
xterm -geometry 80x25+0+0 -hold -e $SYNC &
|
||||
|
||||
SENDER0="fairmq-ex-n-m-sender"
|
||||
SENDER0+=" --id Sender1"
|
||||
SENDER0+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||
SENDER0+=" name=data,type=pair,method=connect,address=tcp://localhost:8021,address=tcp://localhost:8022,address=tcp://localhost:8023,address=tcp://localhost:8024"
|
||||
SENDER0+=" --sender-index 0"
|
||||
SENDER0+=" --subtimeframe-size 1000000"
|
||||
SENDER0+=" --num-receivers 4"
|
||||
xterm -geometry 80x25+500+0 -hold -e $SENDER0 &
|
||||
|
||||
SENDER1="fairmq-ex-n-m-sender"
|
||||
SENDER1+=" --id Sender2"
|
||||
SENDER1+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||
SENDER1+=" name=data,type=pair,method=connect,address=tcp://localhost:8031,address=tcp://localhost:8032,address=tcp://localhost:8033,address=tcp://localhost:8034"
|
||||
SENDER1+=" --sender-index 1"
|
||||
SENDER1+=" --subtimeframe-size 1000000"
|
||||
SENDER1+=" --num-receivers 4"
|
||||
xterm -geometry 80x25+500+350 -hold -e $SENDER1 &
|
||||
|
||||
SENDER2="fairmq-ex-n-m-sender"
|
||||
SENDER2+=" --id Sender3"
|
||||
SENDER2+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||
SENDER2+=" name=data,type=pair,method=connect,address=tcp://localhost:8041,address=tcp://localhost:8042,address=tcp://localhost:8043,address=tcp://localhost:8044"
|
||||
SENDER2+=" --sender-index 2"
|
||||
SENDER2+=" --subtimeframe-size 1000000"
|
||||
SENDER2+=" --num-receivers 4"
|
||||
xterm -geometry 80x25+500+700 -hold -e $SENDER2 &
|
||||
|
||||
RECEIVER0="fairmq-ex-n-m-receiver"
|
||||
RECEIVER0+=" --id Receiver1"
|
||||
RECEIVER0+=" --channel-config name=data,type=pair,method=bind,address=tcp://localhost:8021,address=tcp://localhost:8031,address=tcp://localhost:8041"
|
||||
RECEIVER0+=" --num-senders 3"
|
||||
xterm -geometry 80x25+1000+0 -hold -e $RECEIVER0 &
|
||||
|
||||
RECEIVER1="fairmq-ex-n-m-receiver"
|
||||
RECEIVER1+=" --id Receiver2"
|
||||
RECEIVER1+=" --channel-config name=data,type=pair,method=bind,address=tcp://localhost:8022,address=tcp://localhost:8032,address=tcp://localhost:8042"
|
||||
RECEIVER1+=" --num-senders 3"
|
||||
xterm -geometry 80x25+1000+350 -hold -e $RECEIVER1 &
|
||||
|
||||
RECEIVER2="fairmq-ex-n-m-receiver"
|
||||
RECEIVER2+=" --id Receiver3"
|
||||
RECEIVER2+=" --channel-config name=data,type=pair,method=bind,address=tcp://localhost:8023,address=tcp://localhost:8033,address=tcp://localhost:8043"
|
||||
RECEIVER2+=" --num-senders 3"
|
||||
xterm -geometry 80x25+1000+700 -hold -e $RECEIVER2 &
|
||||
|
||||
RECEIVER3="fairmq-ex-n-m-receiver"
|
||||
RECEIVER3+=" --id Receiver4"
|
||||
RECEIVER3+=" --channel-config name=data,type=pair,method=bind,address=tcp://localhost:8024,address=tcp://localhost:8034,address=tcp://localhost:8044"
|
||||
RECEIVER3+=" --num-senders 3"
|
||||
xterm -geometry 80x25+1000+1050 -hold -e $RECEIVER3 &
|
60
examples/n-m/fairmq-start-ex-n-m.sh.in
Executable file
60
examples/n-m/fairmq-start-ex-n-m.sh.in
Executable file
@@ -0,0 +1,60 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PATH=@BIN_DIR@:$PATH
|
||||
|
||||
SYNC="fairmq-ex-n-m-synchronizer"
|
||||
SYNC+=" --id Sync"
|
||||
SYNC+=" --channel-config name=sync,type=pub,method=bind,address=tcp://localhost:8010"
|
||||
SYNC+=" --rate 100"
|
||||
xterm -geometry 80x25+0+0 -hold -e $SYNC &
|
||||
|
||||
SENDER0="fairmq-ex-n-m-sender"
|
||||
SENDER0+=" --id Sender1"
|
||||
SENDER0+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||
SENDER0+=" name=data,type=push,method=connect,address=tcp://localhost:8021,address=tcp://localhost:8022,address=tcp://localhost:8023,address=tcp://localhost:8024"
|
||||
SENDER0+=" --sender-index 0"
|
||||
SENDER0+=" --subtimeframe-size 1000000"
|
||||
SENDER0+=" --num-receivers 4"
|
||||
xterm -geometry 80x25+500+0 -hold -e $SENDER0 &
|
||||
|
||||
SENDER1="fairmq-ex-n-m-sender"
|
||||
SENDER1+=" --id Sender2"
|
||||
SENDER1+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||
SENDER1+=" name=data,type=push,method=connect,address=tcp://localhost:8021,address=tcp://localhost:8022,address=tcp://localhost:8023,address=tcp://localhost:8024"
|
||||
SENDER1+=" --sender-index 1"
|
||||
SENDER1+=" --subtimeframe-size 1000000"
|
||||
SENDER1+=" --num-receivers 4"
|
||||
xterm -geometry 80x25+500+350 -hold -e $SENDER1 &
|
||||
|
||||
SENDER2="fairmq-ex-n-m-sender"
|
||||
SENDER2+=" --id Sender3"
|
||||
SENDER2+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||
SENDER2+=" name=data,type=push,method=connect,address=tcp://localhost:8021,address=tcp://localhost:8022,address=tcp://localhost:8023,address=tcp://localhost:8024"
|
||||
SENDER2+=" --sender-index 2"
|
||||
SENDER2+=" --subtimeframe-size 1000000"
|
||||
SENDER2+=" --num-receivers 4"
|
||||
xterm -geometry 80x25+500+700 -hold -e $SENDER2 &
|
||||
|
||||
RECEIVER0="fairmq-ex-n-m-receiver"
|
||||
RECEIVER0+=" --id Receiver1"
|
||||
RECEIVER0+=" --channel-config name=data,type=pull,method=bind,address=tcp://localhost:8021"
|
||||
RECEIVER0+=" --num-senders 3"
|
||||
xterm -geometry 80x25+1000+0 -hold -e $RECEIVER0 &
|
||||
|
||||
RECEIVER1="fairmq-ex-n-m-receiver"
|
||||
RECEIVER1+=" --id Receiver2"
|
||||
RECEIVER1+=" --channel-config name=data,type=pull,method=bind,address=tcp://localhost:8022"
|
||||
RECEIVER1+=" --num-senders 3"
|
||||
xterm -geometry 80x25+1000+350 -hold -e $RECEIVER1 &
|
||||
|
||||
RECEIVER2="fairmq-ex-n-m-receiver"
|
||||
RECEIVER2+=" --id Receiver3"
|
||||
RECEIVER2+=" --channel-config name=data,type=pull,method=bind,address=tcp://localhost:8023"
|
||||
RECEIVER2+=" --num-senders 3"
|
||||
xterm -geometry 80x25+1000+700 -hold -e $RECEIVER2 &
|
||||
|
||||
RECEIVER3="fairmq-ex-n-m-receiver"
|
||||
RECEIVER3+=" --id Receiver4"
|
||||
RECEIVER3+=" --channel-config name=data,type=pull,method=bind,address=tcp://localhost:8024"
|
||||
RECEIVER3+=" --num-senders 3"
|
||||
xterm -geometry 80x25+1000+1050 -hold -e $RECEIVER3 &
|
119
examples/n-m/runReceiver.cxx
Normal file
119
examples/n-m/runReceiver.cxx
Normal file
@@ -0,0 +1,119 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "Header.h"
|
||||
|
||||
#include <FairMQDevice.h>
|
||||
#include <runFairMQDevice.h>
|
||||
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace std;
|
||||
using namespace example_n_m;
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
struct TFBuffer
|
||||
{
|
||||
FairMQParts parts;
|
||||
chrono::steady_clock::time_point start;
|
||||
chrono::steady_clock::time_point end;
|
||||
};
|
||||
|
||||
class Receiver : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Receiver()
|
||||
: fBuffer()
|
||||
, fDiscardedSet()
|
||||
, fNumSenders(0)
|
||||
, fBufferTimeoutInMs(5000)
|
||||
, fMaxTimeframes(0)
|
||||
, fTimeframeCounter(0)
|
||||
{
|
||||
OnData("data", &Receiver::HandleData);
|
||||
}
|
||||
|
||||
~Receiver() = default;
|
||||
|
||||
void InitTask() override
|
||||
{
|
||||
fNumSenders = GetConfig()->GetValue<int>("num-senders");
|
||||
fBufferTimeoutInMs = GetConfig()->GetValue<int>("buffer-timeout");
|
||||
fMaxTimeframes = GetConfig()->GetValue<int>("max-timeframes");
|
||||
}
|
||||
|
||||
protected:
|
||||
bool HandleData(FairMQParts& parts, int /* index */)
|
||||
{
|
||||
Header& h = *(static_cast<Header*>(parts.At(0)->GetData()));
|
||||
// LOG(info) << "Received sub-time frame #" << h.id << " from Sender" << h.senderIndex;
|
||||
|
||||
if (fDiscardedSet.find(h.id) == fDiscardedSet.end()) {
|
||||
if (fBuffer.find(h.id) == fBuffer.end()) {
|
||||
// if this is the first part with this ID, save the receive time.
|
||||
fBuffer[h.id].start = chrono::steady_clock::now();
|
||||
}
|
||||
// if the received ID has not previously been discarded, store the data part in the buffer
|
||||
fBuffer[h.id].parts.AddPart(move(parts.At(1)));
|
||||
} else {
|
||||
// if received ID has been previously discarded.
|
||||
LOG(debug) << "Received part from an already discarded timeframe with id " << h.id;
|
||||
}
|
||||
|
||||
if (fBuffer[h.id].parts.Size() == fNumSenders) {
|
||||
LOG(info) << "Successfully completed timeframe #" << h.id;
|
||||
fBuffer.erase(h.id);
|
||||
|
||||
if (fMaxTimeframes > 0 && ++fTimeframeCounter >= fMaxTimeframes) {
|
||||
LOG(info) << "Reached configured maximum number of timeframes (" << fMaxTimeframes << "). Exiting RUNNING state.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DiscardIncompleteTimeframes()
|
||||
{
|
||||
auto it = fBuffer.begin();
|
||||
while (it != fBuffer.end()) {
|
||||
if (chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - (it->second).start).count() > fBufferTimeoutInMs) {
|
||||
LOG(debug) << "Timeframe #" << it->first << " incomplete after " << fBufferTimeoutInMs << " milliseconds, discarding";
|
||||
fDiscardedSet.insert(it->first);
|
||||
fBuffer.erase(it++);
|
||||
LOG(debug) << "Number of discarded timeframes: " << fDiscardedSet.size();
|
||||
} else {
|
||||
// LOG(info) << "Timeframe #" << it->first << " within timeout, buffering...";
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unordered_map<uint16_t, TFBuffer> fBuffer;
|
||||
unordered_set<uint16_t> fDiscardedSet;
|
||||
|
||||
int fNumSenders;
|
||||
int fBufferTimeoutInMs;
|
||||
int fMaxTimeframes;
|
||||
int fTimeframeCounter;
|
||||
};
|
||||
|
||||
void addCustomOptions(bpo::options_description& options)
|
||||
{
|
||||
options.add_options()
|
||||
("buffer-timeout", bpo::value<int>()->default_value(1000), "Buffer timeout in milliseconds")
|
||||
("num-senders", bpo::value<int>()->required(), "Number of senders")
|
||||
("max-timeframes", bpo::value<int>()->default_value(0), "Maximum number of timeframes to receive (0 - unlimited)");
|
||||
}
|
||||
|
||||
FairMQDevice* getDevice(const FairMQProgOptions& /* config */) { return new Receiver(); }
|
79
examples/n-m/runSender.cxx
Normal file
79
examples/n-m/runSender.cxx
Normal file
@@ -0,0 +1,79 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "Header.h"
|
||||
|
||||
#include <FairMQDevice.h>
|
||||
#include <runFairMQDevice.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace example_n_m;
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
class Sender : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Sender()
|
||||
: fNumReceivers(0)
|
||||
, fIndex(0)
|
||||
, fSubtimeframeSize(10000)
|
||||
{}
|
||||
|
||||
~Sender() = default;
|
||||
|
||||
protected:
|
||||
void InitTask() override
|
||||
{
|
||||
fIndex = GetConfig()->GetProperty<int>("sender-index");
|
||||
fSubtimeframeSize = GetConfig()->GetProperty<int>("subtimeframe-size");
|
||||
fNumReceivers = GetConfig()->GetProperty<int>("num-receivers");
|
||||
}
|
||||
|
||||
void Run() override
|
||||
{
|
||||
FairMQChannel& dataInChannel = fChannels.at("sync").at(0);
|
||||
|
||||
while (!NewStatePending()) {
|
||||
Header h;
|
||||
FairMQMessagePtr id(NewMessage());
|
||||
if (dataInChannel.Receive(id) > 0) {
|
||||
h.id = *(static_cast<uint16_t*>(id->GetData()));
|
||||
h.senderIndex = fIndex;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
FairMQParts parts;
|
||||
parts.AddPart(NewSimpleMessage(h));
|
||||
parts.AddPart(NewMessage(fSubtimeframeSize));
|
||||
|
||||
uint64_t currentDataId = h.id;
|
||||
int direction = currentDataId % fNumReceivers;
|
||||
|
||||
if (Send(parts, "data", direction, 0) < 0) {
|
||||
LOG(debug) << "Failed to queue Subtimeframe #" << currentDataId << " to Receiver[" << direction << "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int fNumReceivers;
|
||||
unsigned int fIndex;
|
||||
int fSubtimeframeSize;
|
||||
};
|
||||
|
||||
void addCustomOptions(bpo::options_description& options)
|
||||
{
|
||||
options.add_options()
|
||||
("sender-index", bpo::value<int>()->default_value(0), "Sender Index")
|
||||
("subtimeframe-size", bpo::value<int>()->default_value(1000), "Subtimeframe size in bytes")
|
||||
("num-receivers", bpo::value<int>()->required(), "Number of EPNs");
|
||||
}
|
||||
FairMQDevice* getDevice(const FairMQProgOptions& /* config */) { return new Sender(); }
|
46
examples/n-m/runSynchronizer.cxx
Normal file
46
examples/n-m/runSynchronizer.cxx
Normal file
@@ -0,0 +1,46 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include <FairMQDevice.h>
|
||||
#include <runFairMQDevice.h>
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
using namespace std;
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
class Synchronizer : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Synchronizer()
|
||||
: fTimeframeId(0)
|
||||
{}
|
||||
~Synchronizer() = default;
|
||||
|
||||
protected:
|
||||
bool ConditionalRun() override
|
||||
{
|
||||
FairMQMessagePtr msg(NewSimpleMessage(fTimeframeId));
|
||||
|
||||
if (Send(msg, "sync") > 0) {
|
||||
if (++fTimeframeId == UINT16_MAX - 1) {
|
||||
fTimeframeId = 0;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t fTimeframeId;
|
||||
};
|
||||
|
||||
void addCustomOptions(bpo::options_description& /* options */) {}
|
||||
FairMQDevice* getDevice(const FairMQProgOptions& /* config */) { return new Synchronizer(); }
|
71
examples/qc/CMakeLists.txt
Normal file
71
examples/qc/CMakeLists.txt
Normal file
@@ -0,0 +1,71 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
add_executable(fairmq-ex-qc-sampler runSampler.cxx)
|
||||
target_link_libraries(fairmq-ex-qc-sampler PRIVATE FairMQ)
|
||||
|
||||
add_executable(fairmq-ex-qc-dispatcher runQCDispatcher.cxx)
|
||||
target_link_libraries(fairmq-ex-qc-dispatcher PRIVATE FairMQ)
|
||||
|
||||
add_executable(fairmq-ex-qc-task runQCTask.cxx)
|
||||
target_link_libraries(fairmq-ex-qc-task PRIVATE FairMQ)
|
||||
|
||||
add_executable(fairmq-ex-qc-sink runSink.cxx)
|
||||
target_link_libraries(fairmq-ex-qc-sink PRIVATE FairMQ)
|
||||
|
||||
add_custom_target(ExampleQC DEPENDS fairmq-ex-qc-sampler fairmq-ex-qc-dispatcher fairmq-ex-qc-task fairmq-ex-qc-sink)
|
||||
|
||||
list(JOIN Boost_LIBRARY_DIRS ":" LIB_DIR)
|
||||
set(BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_BINARY_DIR}/fairmq/plugins/DDS)
|
||||
set(DATA_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-qc-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-qc-topology.xml @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-qc-env.sh ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-qc-env.sh @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-qc.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-qc.sh @ONLY)
|
||||
|
||||
# test
|
||||
if(DDS_FOUND)
|
||||
add_test(NAME Example.QC.localhost COMMAND ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-qc.sh localhost)
|
||||
set_tests_properties(Example.QC.localhost PROPERTIES TIMEOUT 15 RUN_SERIAL true PASS_REGULAR_EXPRESSION "Example successful")
|
||||
endif()
|
||||
|
||||
# install
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-qc-sampler
|
||||
fairmq-ex-qc-dispatcher
|
||||
fairmq-ex-qc-task
|
||||
fairmq-ex-qc-sink
|
||||
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
# configure run script with different executable paths for build and for install directories
|
||||
set(BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
|
||||
set(DATA_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_DATADIR})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-qc-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-qc-topology.xml_install @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-qc-env.sh ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-qc-env.sh_install @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-qc.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-qc.sh_install @ONLY)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-qc-topology.xml_install
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||
RENAME ex-qc-topology.xml
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-qc-env.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-ex-qc-env.sh
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-qc.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-qc.sh
|
||||
)
|
4
examples/qc/README.md
Normal file
4
examples/qc/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
QC
|
||||
==
|
||||
|
||||
A topology consisting of 4 devices - Sampler, QCDispatcher, QCTask and Sink. The data flows from Sampler through QCDispatcher to Sink. On demand - by setting the corresponding configuration property - the QCDispatcher device will duplicate the data to the QCTask device. The property is set by the topology controller, in this example this is the `fairmq-dds-command-ui` utility.
|
48
examples/qc/ex-qc-topology.xml
Normal file
48
examples/qc/ex-qc-topology.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<topology name="ExampleQC">
|
||||
|
||||
<property name="fmqchan_data1" />
|
||||
<property name="fmqchan_data2" />
|
||||
<property name="fmqchan_qc" />
|
||||
|
||||
<decltask name="Sampler">
|
||||
<exe>fairmq-ex-qc-sampler --color false --channel-config name=data1,type=push,method=bind -P dds --max-iterations 1000</exe>
|
||||
<env reachable="false">fairmq-ex-qc-env.sh</env>
|
||||
<properties>
|
||||
<name access="write">fmqchan_data1</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<decltask name="QCDispatcher">
|
||||
<exe>fairmq-ex-qc-dispatcher --color false --channel-config name=data1,type=pull,method=connect name=data2,type=push,method=connect name=qc,type=push,method=connect -P dds</exe>
|
||||
<env reachable="false">fairmq-ex-qc-env.sh</env>
|
||||
<properties>
|
||||
<name access="read">fmqchan_data1</name>
|
||||
<name access="read">fmqchan_data2</name>
|
||||
<name access="read">fmqchan_qc</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<decltask name="QCTask">
|
||||
<exe>fairmq-ex-qc-task --color false --channel-config name=qc,type=pull,method=bind -P dds</exe>
|
||||
<env reachable="false">fairmq-ex-qc-env.sh</env>
|
||||
<properties>
|
||||
<name access="write">fmqchan_qc</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<decltask name="Sink">
|
||||
<exe>fairmq-ex-qc-sink --color false --channel-config name=data2,type=pull,method=bind -P dds --max-iterations 1000</exe>
|
||||
<env reachable="false">fairmq-ex-qc-env.sh</env>
|
||||
<properties>
|
||||
<name access="write">fmqchan_data2</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<main name="main">
|
||||
<task>Sampler</task>
|
||||
<task>QCDispatcher</task>
|
||||
<task>QCTask</task>
|
||||
<task>Sink</task>
|
||||
</main>
|
||||
|
||||
</topology>
|
16
examples/qc/fairmq-ex-qc-env.sh
Executable file
16
examples/qc/fairmq-ex-qc-env.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
################################################################################
|
||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
export PATH=@BIN_DIR@:$PATH
|
||||
|
||||
OS=$(uname -s 2>&1)
|
||||
if [ "$OS" == "Darwin" ]; then
|
||||
export DYLD_LIBRARY_PATH=@LIB_DIR@:$DYLD_LIBRARY_PATH
|
||||
fi
|
82
examples/qc/fairmq-start-ex-qc.sh.in
Executable file
82
examples/qc/fairmq-start-ex-qc.sh.in
Executable file
@@ -0,0 +1,82 @@
|
||||
#!/bin/bash
|
||||
|
||||
################################################################################
|
||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
# fairmq-start-ex-qc.sh -> submit agents with localhost plugin
|
||||
|
||||
set -e
|
||||
|
||||
cleanup() {
|
||||
dds-session stop $1
|
||||
echo "CLEANUP PERFORMED"
|
||||
}
|
||||
|
||||
source @DDS_INSTALL_PREFIX@/DDS_env.sh
|
||||
export PATH=@BIN_DIR@:$PATH
|
||||
|
||||
exec 5>&1
|
||||
output=$(dds-session start | tee >(cat - >&5))
|
||||
export DDS_SESSION_ID=$(echo ${output} | grep "DDS session ID: " | cut -d' ' -f4)
|
||||
echo "SESSION ID: ${DDS_SESSION_ID}"
|
||||
|
||||
trap "cleanup ${DDS_SESSION_ID}" EXIT
|
||||
|
||||
requiredNofSlots=4
|
||||
dds-submit -r localhost --slots ${requiredNofSlots}
|
||||
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||
dds-info --idle-count --wait ${requiredNofSlots}
|
||||
|
||||
export FAIRMQ_DDS_TOPO_FILE=@DATA_DIR@/ex-qc-topology.xml
|
||||
echo "TOPOLOGY FILE: ${FAIRMQ_DDS_TOPO_FILE}"
|
||||
echo "TOPOLOGY NAME: $(dds-topology --disable-validation --topology-name ${FAIRMQ_DDS_TOPO_FILE})"
|
||||
|
||||
dds-info --active-topology
|
||||
dds-topology --activate ${FAIRMQ_DDS_TOPO_FILE}
|
||||
dds-info --active-topology
|
||||
echo "...waiting for ${requiredNofSlots} executing slots..."
|
||||
dds-info --executing-count --wait ${requiredNofSlots}
|
||||
|
||||
echo "------------------------"
|
||||
echo "...waiting for Topology to finish..."
|
||||
# TODO Retrieve number of devices from DDS topology API instead of having the user pass it explicitely
|
||||
fairmq-dds-command-ui -w "IDLE"
|
||||
fairmq-dds-command-ui -c i
|
||||
fairmq-dds-command-ui -c k
|
||||
fairmq-dds-command-ui -c b
|
||||
fairmq-dds-command-ui -c x
|
||||
fairmq-dds-command-ui -c j
|
||||
allexceptqctasks="main/(Sampler|QCDispatcher|Sink)"
|
||||
fairmq-dds-command-ui -c r -p $allexceptqctasks
|
||||
qctask="main/QCTask.*"
|
||||
qcdispatcher="main/QCDispatcher.*"
|
||||
fairmq-dds-command-ui -c p --property-key qc --property-value active -p $qcdispatcher
|
||||
fairmq-dds-command-ui -c r -p $qctask
|
||||
fairmq-dds-command-ui -w "RUNNING->READY" -p $qctask
|
||||
echo "...$qctask received data and transitioned to READY, sending shutdown..."
|
||||
fairmq-dds-command-ui -c s
|
||||
fairmq-dds-command-ui -c t
|
||||
fairmq-dds-command-ui -c d
|
||||
fairmq-dds-command-ui -c q
|
||||
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||
dds-info --idle-count --wait ${requiredNofSlots}
|
||||
echo "------------------------"
|
||||
|
||||
dds-info --active-topology
|
||||
dds-topology --stop
|
||||
dds-info --active-topology
|
||||
|
||||
dds-agent-cmd getlog -a
|
||||
logDir="${wrkDir}/logs"
|
||||
for file in $(find "${logDir}" -name "*.tar.gz"); do tar -xf ${file} -C "${logDir}" ; done
|
||||
echo "AGENT LOG FILES IN: ${logDir}"
|
||||
|
||||
# This string is used by ctest to detect success
|
||||
echo "Example successful :)"
|
||||
|
||||
# Cleanup function is called by EXIT trap
|
59
examples/qc/runQCDispatcher.cxx
Normal file
59
examples/qc/runQCDispatcher.cxx
Normal file
@@ -0,0 +1,59 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "runFairMQDevice.h"
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
class QCDispatcher : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
QCDispatcher()
|
||||
: fDoQC(false)
|
||||
{
|
||||
OnData("data1", &QCDispatcher::HandleData);
|
||||
}
|
||||
|
||||
void InitTask() override
|
||||
{
|
||||
GetConfig()->Subscribe<std::string>("qcdevice", [&](const std::string& key, std::string value) {
|
||||
if (key == "qc") {
|
||||
if (value == "active") {
|
||||
fDoQC.store(true);
|
||||
} else if (value == "inactive") {
|
||||
fDoQC.store(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
bool HandleData(FairMQMessagePtr& msg, int)
|
||||
{
|
||||
if (fDoQC.load() == true) {
|
||||
FairMQMessagePtr msgCopy(NewMessage());
|
||||
msgCopy->Copy(*msg);
|
||||
if (Send(msg, "qc") < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Send(msg, "data2") < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResetTask() override { GetConfig()->Unsubscribe<std::string>("qcdevice"); }
|
||||
|
||||
private:
|
||||
std::atomic<bool> fDoQC;
|
||||
};
|
||||
|
||||
void addCustomOptions(boost::program_options::options_description& /*options*/) {}
|
||||
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/) { return new QCDispatcher(); }
|
26
examples/qc/runQCTask.cxx
Normal file
26
examples/qc/runQCTask.cxx
Normal file
@@ -0,0 +1,26 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "runFairMQDevice.h"
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
class QCTask : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
QCTask()
|
||||
{
|
||||
OnData("qc", [](FairMQMessagePtr& /*msg*/, int) {
|
||||
LOG(info) << "received data";
|
||||
return false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
void addCustomOptions(bpo::options_description& /*options*/) {}
|
||||
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/) { return new QCTask(); }
|
36
examples/qc/runSampler.cxx
Normal file
36
examples/qc/runSampler.cxx
Normal file
@@ -0,0 +1,36 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "runFairMQDevice.h"
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
#include <thread> // this_thread::sleep_for
|
||||
#include <chrono>
|
||||
|
||||
class Sampler : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Sampler() {}
|
||||
|
||||
protected:
|
||||
virtual bool ConditionalRun()
|
||||
{
|
||||
FairMQMessagePtr msg(NewMessage(1000));
|
||||
|
||||
if (Send(msg, "data1") < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
void addCustomOptions(bpo::options_description&) {}
|
||||
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/) { return new Sampler(); }
|
@@ -6,30 +6,20 @@
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "FairMQUnmanagedRegionZMQ.h"
|
||||
#include "FairMQLogger.h"
|
||||
#include "runFairMQDevice.h"
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
using namespace std;
|
||||
#include <string>
|
||||
|
||||
FairMQUnmanagedRegionZMQ::FairMQUnmanagedRegionZMQ(const size_t size, FairMQRegionCallback callback, const std::string& /* path = "" */, int /* flags = 0 */)
|
||||
: fBuffer(malloc(size))
|
||||
, fSize(size)
|
||||
, fCallback(callback)
|
||||
class Sink : public FairMQDevice
|
||||
{
|
||||
}
|
||||
public:
|
||||
Sink() { OnData("data2", &Sink::HandleData); }
|
||||
|
||||
void* FairMQUnmanagedRegionZMQ::GetData() const
|
||||
{
|
||||
return fBuffer;
|
||||
}
|
||||
protected:
|
||||
bool HandleData(FairMQMessagePtr& /*msg*/, int /*index*/) { return true; }
|
||||
};
|
||||
|
||||
size_t FairMQUnmanagedRegionZMQ::GetSize() const
|
||||
{
|
||||
return fSize;
|
||||
}
|
||||
|
||||
FairMQUnmanagedRegionZMQ::~FairMQUnmanagedRegionZMQ()
|
||||
{
|
||||
LOG(debug) << "destroying region";
|
||||
free(fBuffer);
|
||||
}
|
||||
namespace bpo = boost::program_options;
|
||||
void addCustomOptions(bpo::options_description&) {}
|
||||
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/) { return new Sink(); }
|
@@ -37,10 +37,10 @@ class Readout : public FairMQDevice
|
||||
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("rb",
|
||||
0,
|
||||
10000000,
|
||||
[this](void* /*data*/, size_t /*size*/, void* /*hint*/) { // callback to be called when message buffers no longer needed by transport
|
||||
--fNumUnackedMsgs;
|
||||
[this](const std::vector<fair::mq::RegionBlock>& blocks) { // callback to be called when message buffers no longer needed by transport
|
||||
fNumUnackedMsgs -= blocks.size();
|
||||
if (fMaxIterations > 0) {
|
||||
LOG(debug) << "Received ack";
|
||||
LOG(debug) << "Received " << blocks.size() << " acks";
|
||||
}
|
||||
}
|
||||
));
|
||||
|
@@ -32,15 +32,10 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-region.sh.in ${CMAKE_
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-region.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh)
|
||||
|
||||
add_test(NAME Example.Region.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh zeromq)
|
||||
set_tests_properties(Example.Region.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.Region.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh nanomsg)
|
||||
set_tests_properties(Example.Region.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
endif()
|
||||
set_tests_properties(Example.Region.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received [0-9*] acks")
|
||||
|
||||
add_test(NAME Example.Region.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh shmem)
|
||||
set_tests_properties(Example.Region.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
set_tests_properties(Example.Region.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received [0-9*] acks")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -35,13 +35,21 @@ void Sampler::InitTask()
|
||||
fMsgSize = fConfig->GetProperty<int>("msg-size");
|
||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||
|
||||
fChannels.at("data").at(0).Transport()->SubscribeToRegionEvents([](FairMQRegionInfo info) {
|
||||
LOG(warn) << ">>>" << info.event;
|
||||
LOG(warn) << "id: " << info.id;
|
||||
LOG(warn) << "ptr: " << info.ptr;
|
||||
LOG(warn) << "size: " << info.size;
|
||||
LOG(warn) << "flags: " << info.flags;
|
||||
});
|
||||
|
||||
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("data",
|
||||
0,
|
||||
10000000,
|
||||
[this](void* /*data*/, size_t /*size*/, void* /*hint*/) { // callback to be called when message buffers no longer needed by transport
|
||||
--fNumUnackedMsgs;
|
||||
[this](const std::vector<fair::mq::RegionBlock>& blocks) { // callback to be called when message buffers no longer needed by transport
|
||||
fNumUnackedMsgs -= blocks.size();
|
||||
if (fMaxIterations > 0) {
|
||||
LOG(debug) << "Received ack";
|
||||
LOG(debug) << "Received " << blocks.size() << " acks";
|
||||
}
|
||||
}
|
||||
));
|
||||
@@ -82,6 +90,7 @@ void Sampler::ResetTask()
|
||||
LOG(debug) << "done, still unacked: " << fNumUnackedMsgs;
|
||||
}
|
||||
fRegion.reset();
|
||||
fChannels.at("data").at(0).Transport()->UnsubscribeFromRegionEvents();
|
||||
}
|
||||
|
||||
Sampler::~Sampler()
|
||||
|
@@ -29,6 +29,13 @@ void Sink::InitTask()
|
||||
{
|
||||
// Get the fMaxIterations value from the command line options (via fConfig)
|
||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||
fChannels.at("data").at(0).Transport()->SubscribeToRegionEvents([](FairMQRegionInfo info) {
|
||||
LOG(warn) << ">>>" << info.event;
|
||||
LOG(warn) << "id: " << info.id;
|
||||
LOG(warn) << "ptr: " << info.ptr;
|
||||
LOG(warn) << "size: " << info.size;
|
||||
LOG(warn) << "flags: " << info.flags;
|
||||
});
|
||||
}
|
||||
|
||||
void Sink::Run()
|
||||
@@ -50,6 +57,11 @@ void Sink::Run()
|
||||
}
|
||||
}
|
||||
|
||||
void Sink::ResetTask()
|
||||
{
|
||||
fChannels.at("data").at(0).Transport()->UnsubscribeFromRegionEvents();
|
||||
}
|
||||
|
||||
Sink::~Sink()
|
||||
{
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ class Sink : public FairMQDevice
|
||||
protected:
|
||||
virtual void Run();
|
||||
virtual void InitTask();
|
||||
virtual void ResetTask();
|
||||
|
||||
private:
|
||||
uint64_t fMaxIterations;
|
||||
|
@@ -19,6 +19,7 @@ SAMPLER+=" --id sampler1"
|
||||
SAMPLER+=" --transport $transport"
|
||||
SAMPLER+=" --severity debug"
|
||||
SAMPLER+=" --session $SESSION"
|
||||
SAMPLER+=" --verbosity veryhigh"
|
||||
SAMPLER+=" --control static --color false"
|
||||
SAMPLER+=" --max-iterations 1"
|
||||
SAMPLER+=" --msg-size $msgSize"
|
||||
|
@@ -35,11 +35,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-req-rep.sh.in ${CMAKE_CURRENT
|
||||
add_test(NAME Example.ReqRep.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh zeromq)
|
||||
set_tests_properties(Example.ReqRep.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.ReqRep.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh nanomsg)
|
||||
set_tests_properties(Example.ReqRep.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.ReqRep.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh shmem)
|
||||
set_tests_properties(Example.ReqRep.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
|
||||
|
@@ -190,23 +190,14 @@ if(BUILD_FAIRMQ)
|
||||
shmem/Common.h
|
||||
shmem/Manager.h
|
||||
shmem/Region.h
|
||||
zeromq/FairMQMessageZMQ.h
|
||||
zeromq/FairMQPollerZMQ.h
|
||||
zeromq/FairMQUnmanagedRegionZMQ.h
|
||||
zeromq/FairMQSocketZMQ.h
|
||||
zeromq/FairMQTransportFactoryZMQ.h
|
||||
zeromq/Context.h
|
||||
zeromq/Message.h
|
||||
zeromq/Poller.h
|
||||
zeromq/UnmanagedRegion.h
|
||||
zeromq/Socket.h
|
||||
zeromq/TransportFactory.h
|
||||
)
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
|
||||
nanomsg/FairMQMessageNN.h
|
||||
nanomsg/FairMQPollerNN.h
|
||||
nanomsg/FairMQUnmanagedRegionNN.h
|
||||
nanomsg/FairMQSocketNN.h
|
||||
nanomsg/FairMQTransportFactoryNN.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
|
||||
ofi/Context.h
|
||||
@@ -229,7 +220,6 @@ if(BUILD_FAIRMQ)
|
||||
FairMQPoller.cxx
|
||||
FairMQSocket.cxx
|
||||
FairMQTransportFactory.cxx
|
||||
devices/FairMQBenchmarkSampler.cxx
|
||||
devices/FairMQMerger.cxx
|
||||
devices/FairMQMultiplier.cxx
|
||||
devices/FairMQProxy.cxx
|
||||
@@ -243,31 +233,9 @@ if(BUILD_FAIRMQ)
|
||||
SuboptParser.cxx
|
||||
plugins/config/Config.cxx
|
||||
plugins/Control.cxx
|
||||
shmem/Message.cxx
|
||||
shmem/Poller.cxx
|
||||
shmem/UnmanagedRegion.cxx
|
||||
shmem/Socket.cxx
|
||||
shmem/TransportFactory.cxx
|
||||
shmem/Manager.cxx
|
||||
shmem/Region.cxx
|
||||
zeromq/FairMQMessageZMQ.cxx
|
||||
zeromq/FairMQPollerZMQ.cxx
|
||||
zeromq/FairMQUnmanagedRegionZMQ.cxx
|
||||
zeromq/FairMQSocketZMQ.cxx
|
||||
zeromq/FairMQTransportFactoryZMQ.cxx
|
||||
MemoryResources.cxx
|
||||
)
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
|
||||
nanomsg/FairMQMessageNN.cxx
|
||||
nanomsg/FairMQPollerNN.cxx
|
||||
nanomsg/FairMQUnmanagedRegionNN.cxx
|
||||
nanomsg/FairMQSocketNN.cxx
|
||||
nanomsg/FairMQTransportFactoryNN.cxx
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
|
||||
ofi/Context.cxx
|
||||
@@ -308,9 +276,6 @@ if(BUILD_FAIRMQ)
|
||||
# preprocessor definitions #
|
||||
############################
|
||||
target_compile_definitions(${_target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
target_compile_definitions(${_target} PRIVATE BUILD_NANOMSG_TRANSPORT)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
target_compile_definitions(${_target} PRIVATE BUILD_OFI_TRANSPORT)
|
||||
endif()
|
||||
@@ -331,16 +296,13 @@ if(BUILD_FAIRMQ)
|
||||
##################
|
||||
# link libraries #
|
||||
##################
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
set(NANOMSG_DEPS nanomsg msgpackc-cxx)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(OFI_DEPS
|
||||
asiofi::asiofi
|
||||
Boost::container
|
||||
)
|
||||
endif()
|
||||
set(optional_deps ${NANOMSG_DEPS} ${OFI_DEPS})
|
||||
set(optional_deps ${OFI_DEPS})
|
||||
if(optional_deps)
|
||||
list(REMOVE_DUPLICATES optional_deps)
|
||||
endif()
|
||||
@@ -363,7 +325,6 @@ if(BUILD_FAIRMQ)
|
||||
|
||||
PRIVATE # only libFairMQ links against private dependencies
|
||||
libzmq
|
||||
${NANOMSG_DEPS}
|
||||
${OFI_DEPS}
|
||||
)
|
||||
set_target_properties(${_target} PROPERTIES
|
||||
|
@@ -127,8 +127,8 @@ class FairMQChannel
|
||||
/// @return Returns socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
|
||||
std::string GetAddress() const;
|
||||
|
||||
/// Get channel transport name ("default", "zeromq", "nanomsg" or "shmem")
|
||||
/// @return Returns channel transport name (e.g. "default", "zeromq", "nanomsg" or "shmem")
|
||||
/// Get channel transport name ("default", "zeromq" or "shmem")
|
||||
/// @return Returns channel transport name (e.g. "default", "zeromq" or "shmem")
|
||||
std::string GetTransportName() const;
|
||||
|
||||
/// Get channel transport type
|
||||
@@ -184,7 +184,7 @@ class FairMQChannel
|
||||
void UpdateAddress(const std::string& address);
|
||||
|
||||
/// Set channel transport
|
||||
/// @param transport transport string ("default", "zeromq", "nanomsg" or "shmem")
|
||||
/// @param transport transport string ("default", "zeromq" or "shmem")
|
||||
void UpdateTransport(const std::string& transport);
|
||||
|
||||
/// Set socket send buffer size
|
||||
@@ -335,9 +335,10 @@ class FairMQChannel
|
||||
return Transport()->NewStaticMessage(data);
|
||||
}
|
||||
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0)
|
||||
template<typename... Args>
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegion(Args&&... args)
|
||||
{
|
||||
return Transport()->CreateUnmanagedRegion(size, callback, path, flags);
|
||||
return Transport()->CreateUnmanagedRegion(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static constexpr fair::mq::Transport DefaultTransportType = fair::mq::Transport::DEFAULT;
|
||||
|
@@ -299,10 +299,15 @@ void FairMQDevice::InitWrapper()
|
||||
// if binding address is not specified, try getting it from the configured network interface
|
||||
if (subChannel.fAddress == "unspecified" || subChannel.fAddress == "") {
|
||||
// if the configured network interface is default, get its name from the default route
|
||||
if (networkInterface == "default") {
|
||||
networkInterface = tools::getDefaultRouteNetworkInterface();
|
||||
try {
|
||||
if (networkInterface == "default") {
|
||||
networkInterface = tools::getDefaultRouteNetworkInterface();
|
||||
}
|
||||
subChannel.fAddress = "tcp://" + tools::getInterfaceIP(networkInterface) + ":1";
|
||||
} catch(const tools::DefaultRouteDetectionError& e) {
|
||||
LOG(debug) << "binding on tcp://*:1";
|
||||
subChannel.fAddress = "tcp://*:1";
|
||||
}
|
||||
subChannel.fAddress = "tcp://" + tools::getInterfaceIP(networkInterface) + ":1";
|
||||
}
|
||||
// fill the uninitialized list
|
||||
fUninitializedBindingChannels.push_back(&subChannel);
|
||||
|
@@ -217,15 +217,17 @@ class FairMQDevice
|
||||
}
|
||||
|
||||
// creates unamanaged region with the default device transport
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr)
|
||||
template<typename... Args>
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegion(Args&&... args)
|
||||
{
|
||||
return Transport()->CreateUnmanagedRegion(size, callback);
|
||||
return Transport()->CreateUnmanagedRegion(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// creates unmanaged region with the transport of the specified channel
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel, int index, const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0)
|
||||
template<typename... Args>
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel, int index, Args&&... args)
|
||||
{
|
||||
return GetChannel(channel, index).NewUnmanagedRegion(size, callback, path, flags);
|
||||
return GetChannel(channel, index).NewUnmanagedRegion(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ...Ts>
|
||||
@@ -272,7 +274,7 @@ class FairMQDevice
|
||||
}
|
||||
|
||||
/// Adds a transport to the device if it doesn't exist
|
||||
/// @param transport Transport string ("zeromq"/"nanomsg"/"shmem")
|
||||
/// @param transport Transport string ("zeromq"/"shmem")
|
||||
std::shared_ptr<FairMQTransportFactory> AddTransport(const fair::mq::Transport transport);
|
||||
|
||||
/// Assigns config to the device
|
||||
@@ -387,7 +389,7 @@ class FairMQDevice
|
||||
int GetInitTimeoutInS() const { return fConfig->GetProperty<int>("init-timeout", DefaultInitTimeout); }
|
||||
|
||||
/// Sets the default transport for the device
|
||||
/// @param transport Transport string ("zeromq"/"nanomsg"/"shmem")
|
||||
/// @param transport Transport string ("zeromq"/"shmem")
|
||||
void SetTransport(const std::string& transport) { fConfig->SetProperty("transport", transport); }
|
||||
/// Gets the default transport name
|
||||
std::string GetTransportName() const { return fConfig->GetProperty<std::string>("transport", DefaultTransportName); }
|
||||
|
@@ -17,11 +17,26 @@
|
||||
using fairmq_free_fn = void(void* data, void* hint);
|
||||
class FairMQTransportFactory;
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
|
||||
struct Alignment
|
||||
{
|
||||
size_t alignment;
|
||||
explicit operator size_t() const { return alignment; }
|
||||
};
|
||||
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
||||
|
||||
class FairMQMessage
|
||||
{
|
||||
public:
|
||||
FairMQMessage() = default;
|
||||
FairMQMessage(FairMQTransportFactory* factory):fTransport{factory} {}
|
||||
FairMQMessage(FairMQTransportFactory* factory) : fTransport(factory) {}
|
||||
|
||||
virtual void Rebuild() = 0;
|
||||
virtual void Rebuild(const size_t size) = 0;
|
||||
virtual void Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) = 0;
|
||||
@@ -33,7 +48,7 @@ class FairMQMessage
|
||||
|
||||
virtual fair::mq::Transport GetType() const = 0;
|
||||
FairMQTransportFactory* GetTransport() { return fTransport; }
|
||||
//void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
|
||||
void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
|
||||
|
||||
virtual void Copy(const FairMQMessage& msg) = 0;
|
||||
|
||||
@@ -53,6 +68,7 @@ namespace mq
|
||||
using Message = FairMQMessage;
|
||||
using MessagePtr = FairMQMessagePtr;
|
||||
struct MessageError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
struct MessageBadAlloc : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
||||
|
@@ -20,7 +20,7 @@ class FairMQSocket
|
||||
{
|
||||
public:
|
||||
FairMQSocket() {}
|
||||
FairMQSocket(FairMQTransportFactory* fac): fTransport(fac) {}
|
||||
FairMQSocket(FairMQTransportFactory* fac) : fTransport(fac) {}
|
||||
|
||||
virtual std::string GetId() const = 0;
|
||||
|
||||
@@ -54,7 +54,7 @@ class FairMQSocket
|
||||
virtual unsigned long GetMessagesRx() const = 0;
|
||||
|
||||
FairMQTransportFactory* GetTransport() { return fTransport; }
|
||||
void SetTransport(FairMQTransportFactory* transport) { fTransport=transport; }
|
||||
void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
|
||||
|
||||
virtual ~FairMQSocket() {};
|
||||
|
||||
|
@@ -7,69 +7,55 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include <FairMQTransportFactory.h>
|
||||
#include <zeromq/FairMQTransportFactoryZMQ.h>
|
||||
#include <fairmq/shmem/TransportFactory.h>
|
||||
#ifdef BUILD_NANOMSG_TRANSPORT
|
||||
#include <nanomsg/FairMQTransportFactoryNN.h>
|
||||
#endif /* BUILD_NANOMSG_TRANSPORT */
|
||||
#include <fairmq/zeromq/TransportFactory.h>
|
||||
#ifdef BUILD_OFI_TRANSPORT
|
||||
#include <fairmq/ofi/TransportFactory.h>
|
||||
#endif
|
||||
#include <FairMQLogger.h>
|
||||
#include <fairmq/tools/Unique.h>
|
||||
#include <fairmq/Tools.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
FairMQTransportFactory::FairMQTransportFactory(const std::string& id)
|
||||
using namespace std;
|
||||
|
||||
FairMQTransportFactory::FairMQTransportFactory(const string& id)
|
||||
: fkId(id)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
auto FairMQTransportFactory::CreateTransportFactory(const std::string& type, const std::string& id, const fair::mq::ProgOptions* config) -> std::shared_ptr<FairMQTransportFactory>
|
||||
auto FairMQTransportFactory::CreateTransportFactory(const string& type,
|
||||
const string& id,
|
||||
const fair::mq::ProgOptions* config)
|
||||
-> shared_ptr<FairMQTransportFactory>
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
auto finalId = id;
|
||||
|
||||
// Generate uuid if empty
|
||||
if (finalId == "")
|
||||
{
|
||||
if (finalId == "") {
|
||||
finalId = fair::mq::tools::Uuid();
|
||||
}
|
||||
|
||||
if (type == "zeromq")
|
||||
{
|
||||
return make_shared<FairMQTransportFactoryZMQ>(finalId, config);
|
||||
}
|
||||
else if (type == "shmem")
|
||||
{
|
||||
if (type == "zeromq") {
|
||||
return make_shared<fair::mq::zmq::TransportFactory>(finalId, config);
|
||||
} else if (type == "shmem") {
|
||||
return make_shared<fair::mq::shmem::TransportFactory>(finalId, config);
|
||||
}
|
||||
#ifdef BUILD_NANOMSG_TRANSPORT
|
||||
else if (type == "nanomsg")
|
||||
{
|
||||
return make_shared<FairMQTransportFactoryNN>(finalId, config);
|
||||
}
|
||||
#endif /* BUILD_NANOMSG_TRANSPORT */
|
||||
#ifdef BUILD_OFI_TRANSPORT
|
||||
else if (type == "ofi")
|
||||
{
|
||||
else if (type == "ofi") {
|
||||
return make_shared<fair::mq::ofi::TransportFactory>(finalId, config);
|
||||
}
|
||||
#endif /* BUILD_OFI_TRANSPORT */
|
||||
else
|
||||
{
|
||||
LOG(error) << "Unavailable transport requested: " << "\"" << type << "\"" << ". Available are: "
|
||||
<< "\"zeromq\""
|
||||
else {
|
||||
LOG(error) << "Unavailable transport requested: "
|
||||
<< "\"" << type << "\""
|
||||
<< ". Available are: "
|
||||
<< "\"zeromq\","
|
||||
<< "\"shmem\""
|
||||
#ifdef BUILD_NANOMSG_TRANSPORT
|
||||
<< ", \"nanomsg\""
|
||||
#endif /* BUILD_NANOMSG_TRANSPORT */
|
||||
#ifdef BUILD_OFI_TRANSPORT
|
||||
<< ", and \"ofi\""
|
||||
#endif /* BUILD_OFI_TRANSPORT */
|
||||
<< ". Exiting.";
|
||||
exit(EXIT_FAILURE);
|
||||
throw fair::mq::TransportFactoryError(fair::mq::tools::ToString("Unavailable transport requested: ", type));
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@
|
||||
#include <fairmq/Transports.h>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <memory> // shared_ptr
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <stdexcept>
|
||||
@@ -47,13 +47,22 @@ class FairMQTransportFactory
|
||||
fair::mq::ChannelResource* GetMemoryResource() { return &fMemoryResource; }
|
||||
operator fair::mq::ChannelResource*() { return &fMemoryResource; }
|
||||
|
||||
/// @brief Create empty FairMQMessage
|
||||
/// @brief Create empty FairMQMessage (for receiving)
|
||||
/// @return pointer to FairMQMessage
|
||||
virtual FairMQMessagePtr CreateMessage() = 0;
|
||||
/// @brief Create empty FairMQMessage (for receiving), align received buffer to specified alignment
|
||||
/// @param alignment alignment to align received buffer to
|
||||
/// @return pointer to FairMQMessage
|
||||
virtual FairMQMessagePtr CreateMessage(fair::mq::Alignment alignment) = 0;
|
||||
/// @brief Create new FairMQMessage of specified size
|
||||
/// @param size message size
|
||||
/// @return pointer to FairMQMessage
|
||||
virtual FairMQMessagePtr CreateMessage(const size_t size) = 0;
|
||||
/// @brief Create new FairMQMessage of specified size and alignment
|
||||
/// @param size message size
|
||||
/// @param alignment message alignment
|
||||
/// @return pointer to FairMQMessage
|
||||
virtual FairMQMessagePtr CreateMessage(const size_t size, fair::mq::Alignment alignment) = 0;
|
||||
/// @brief Create new FairMQMessage with user provided buffer and size
|
||||
/// @param data pointer to user provided buffer
|
||||
/// @param size size of the user provided buffer
|
||||
@@ -61,20 +70,51 @@ class FairMQTransportFactory
|
||||
/// @param obj optional helper pointer that can be used in the callback
|
||||
/// @return pointer to FairMQMessage
|
||||
virtual FairMQMessagePtr CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) = 0;
|
||||
|
||||
/// @brief create a message with the buffer located within the corresponding unmanaged region
|
||||
/// @param unmanagedRegion the unmanaged region that this message buffer belongs to
|
||||
/// @param data message buffer (must be within the region - checked at runtime by the transport)
|
||||
/// @param size size of the message
|
||||
/// @param hint optional parameter, returned to the user in the FairMQRegionCallback
|
||||
virtual FairMQMessagePtr CreateMessage(FairMQUnmanagedRegionPtr& unmanagedRegion, void* data, const size_t size, void* hint = 0) = 0;
|
||||
|
||||
/// Create a socket
|
||||
/// @brief Create a socket
|
||||
virtual FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name) = 0;
|
||||
|
||||
/// Create a poller for a single channel (all subchannels)
|
||||
/// @brief Create a poller for a single channel (all subchannels)
|
||||
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel>& channels) const = 0;
|
||||
/// Create a poller for specific channels
|
||||
/// @brief Create a poller for specific channels
|
||||
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel*>& channels) const = 0;
|
||||
/// Create a poller for specific channels (all subchannels)
|
||||
/// @brief Create a poller for specific channels (all subchannels)
|
||||
virtual FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const = 0;
|
||||
|
||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0) const = 0;
|
||||
/// @brief Create new UnmanagedRegion
|
||||
/// @param size size of the region
|
||||
/// @param callback callback to be called when a message belonging to this region is no longer needed by the transport
|
||||
/// @param path optional parameter to pass to the underlying transport
|
||||
/// @param flags optional parameter to pass to the underlying transport
|
||||
/// @return pointer to UnmanagedRegion
|
||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0) = 0;
|
||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0) = 0;
|
||||
/// @brief Create new UnmanagedRegion
|
||||
/// @param size size of the region
|
||||
/// @param userFlags flags to be stored with the region, have no effect on the transport, but can be retrieved from the region by the user
|
||||
/// @param callback callback to be called when a message belonging to this region is no longer needed by the transport
|
||||
/// @param path optional parameter to pass to the underlying transport
|
||||
/// @param flags optional parameter to pass to the underlying transport
|
||||
/// @return pointer to UnmanagedRegion
|
||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0) = 0;
|
||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, FairMQRegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0) = 0;
|
||||
|
||||
/// @brief Subscribe to region events (creation, destruction, ...)
|
||||
/// @param callback the callback that is called when a region event occurs
|
||||
virtual void SubscribeToRegionEvents(FairMQRegionEventCallback callback) = 0;
|
||||
/// @brief Check if there is an active subscription to region events
|
||||
/// @return true/false
|
||||
virtual bool SubscribedToRegionEvents() = 0;
|
||||
/// @brief Unsubscribe from region events
|
||||
virtual void UnsubscribeFromRegionEvents() = 0;
|
||||
|
||||
virtual std::vector<FairMQRegionInfo> GetRegionInfo() = 0;
|
||||
|
||||
/// Get transport type
|
||||
virtual fair::mq::Transport GetType() const = 0;
|
||||
|
@@ -12,26 +12,103 @@
|
||||
#include <cstddef> // size_t
|
||||
#include <memory> // std::unique_ptr
|
||||
#include <functional> // std::function
|
||||
#include <ostream> // std::ostream
|
||||
#include <vector>
|
||||
|
||||
class FairMQTransportFactory;
|
||||
|
||||
enum class FairMQRegionEvent : int
|
||||
{
|
||||
created,
|
||||
destroyed,
|
||||
local_only
|
||||
};
|
||||
|
||||
struct FairMQRegionInfo
|
||||
{
|
||||
FairMQRegionInfo()
|
||||
: id(0)
|
||||
, ptr(nullptr)
|
||||
, size(0)
|
||||
, flags(0)
|
||||
, event(FairMQRegionEvent::created)
|
||||
{}
|
||||
|
||||
FairMQRegionInfo(uint64_t _id, void* _ptr, size_t _size, int64_t _flags, FairMQRegionEvent _event)
|
||||
: id(_id)
|
||||
, ptr(_ptr)
|
||||
, size(_size)
|
||||
, flags(_flags)
|
||||
, event (_event)
|
||||
{}
|
||||
|
||||
uint64_t id; // id of the region
|
||||
void* ptr; // pointer to the start of the region
|
||||
size_t size; // region size
|
||||
int64_t flags; // custom flags set by the creator
|
||||
FairMQRegionEvent event;
|
||||
};
|
||||
|
||||
struct FairMQRegionBlock {
|
||||
void* ptr;
|
||||
size_t size;
|
||||
void* hint;
|
||||
|
||||
FairMQRegionBlock(void* p, size_t s, void* h)
|
||||
: ptr(p), size(s), hint(h)
|
||||
{}
|
||||
};
|
||||
|
||||
using FairMQRegionCallback = std::function<void(void*, size_t, void*)>;
|
||||
using FairMQRegionBulkCallback = std::function<void(const std::vector<FairMQRegionBlock>&)>;
|
||||
using FairMQRegionEventCallback = std::function<void(FairMQRegionInfo)>;
|
||||
|
||||
class FairMQUnmanagedRegion
|
||||
{
|
||||
public:
|
||||
FairMQUnmanagedRegion() {}
|
||||
FairMQUnmanagedRegion(FairMQTransportFactory* factory) : fTransport(factory) {}
|
||||
|
||||
virtual void* GetData() const = 0;
|
||||
virtual size_t GetSize() const = 0;
|
||||
virtual uint64_t GetId() const = 0;
|
||||
|
||||
FairMQTransportFactory* GetTransport() { return fTransport; }
|
||||
void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
|
||||
|
||||
virtual ~FairMQUnmanagedRegion() {};
|
||||
|
||||
private:
|
||||
FairMQTransportFactory* fTransport{nullptr};
|
||||
};
|
||||
|
||||
using FairMQUnmanagedRegionPtr = std::unique_ptr<FairMQUnmanagedRegion>;
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const FairMQRegionEvent& event)
|
||||
{
|
||||
switch (event) {
|
||||
case FairMQRegionEvent::created:
|
||||
return os << "created";
|
||||
case FairMQRegionEvent::destroyed:
|
||||
return os << "destroyed";
|
||||
case FairMQRegionEvent::local_only:
|
||||
return os << "local_only";
|
||||
default:
|
||||
return os << "unrecognized event";
|
||||
}
|
||||
}
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
|
||||
using RegionCallback = FairMQRegionCallback;
|
||||
using RegionBulkCallback = FairMQRegionBulkCallback;
|
||||
using RegionEventCallback = FairMQRegionEventCallback;
|
||||
using RegionEvent = FairMQRegionEvent;
|
||||
using RegionInfo = FairMQRegionInfo;
|
||||
using RegionBlock = FairMQRegionBlock;
|
||||
using UnmanagedRegion = FairMQUnmanagedRegion;
|
||||
using UnmanagedRegionPtr = FairMQUnmanagedRegionPtr;
|
||||
|
||||
|
@@ -60,7 +60,7 @@ FairMQMessagePtr getMessage(ContainerT &&container_, FairMQMemoryResource *targe
|
||||
container.data(),
|
||||
containerSizeBytes);
|
||||
return message;
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
||||
|
@@ -18,5 +18,5 @@
|
||||
void *fair::mq::ChannelResource::do_allocate(std::size_t bytes, std::size_t /*alignment*/)
|
||||
{
|
||||
return setMessage(factory->CreateMessage(bytes));
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -28,6 +28,8 @@ using boost::optional;
|
||||
|
||||
const std::string fair::mq::PluginManager::fgkLibPrefix = "FairMQPlugin_";
|
||||
|
||||
std::vector<boost::dll::shared_library> fair::mq::PluginManager::fgDLLKeepAlive = std::vector<boost::dll::shared_library>();
|
||||
|
||||
fair::mq::PluginManager::PluginManager()
|
||||
: fSearchPaths{}
|
||||
, fPluginFactories()
|
||||
|
@@ -80,7 +80,7 @@ class PluginManager
|
||||
auto ForEachPluginProgOptions(std::function<void (boost::program_options::options_description)> func) const -> void { for(const auto& pair : fPluginProgOptions) { func(pair.second); } }
|
||||
|
||||
template<typename... Args>
|
||||
auto EmplacePluginServices(Args&&... args) -> void { fPluginServices = fair::mq::tools::make_unique<PluginServices>(std::forward<Args>(args)...); };
|
||||
auto EmplacePluginServices(Args&&... args) -> void { fPluginServices = fair::mq::tools::make_unique<PluginServices>(std::forward<Args>(args)...); }
|
||||
|
||||
auto WaitForPluginsToReleaseDeviceControl() -> void { fPluginServices->WaitForReleaseDeviceControl(); }
|
||||
|
||||
@@ -97,6 +97,7 @@ class PluginManager
|
||||
using fair::mq::tools::ToString;
|
||||
|
||||
auto lib = shared_library{std::forward<Args>(args)...};
|
||||
fgDLLKeepAlive.push_back(lib);
|
||||
|
||||
fPluginFactories[pluginName] = import_alias<PluginFactory>(
|
||||
shared_library{lib},
|
||||
@@ -117,6 +118,7 @@ class PluginManager
|
||||
|
||||
static const std::string fgkLibPrefix;
|
||||
std::vector<boost::filesystem::path> fSearchPaths;
|
||||
static std::vector<boost::dll::shared_library> fgDLLKeepAlive;
|
||||
std::map<std::string, std::function<PluginFactory>> fPluginFactories;
|
||||
std::unique_ptr<PluginServices> fPluginServices;
|
||||
std::map<std::string, std::unique_ptr<Plugin>> fPlugins;
|
||||
|
@@ -62,7 +62,7 @@ ValInfo ConvertVarValToValInfo(const po::variable_value& v)
|
||||
} catch (out_of_range& oor) {
|
||||
return {string("[unidentified_type]"), string("[unidentified_type]"), origin};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
string ConvertVarValToString(const po::variable_value& v)
|
||||
{
|
||||
@@ -443,4 +443,4 @@ void ProgOptions::PrintOptionsRaw() const
|
||||
|
||||
|
||||
} // namespace mq
|
||||
} // namespace fair
|
||||
} // namespace fair
|
||||
|
@@ -24,7 +24,6 @@ enum class Transport
|
||||
{
|
||||
DEFAULT,
|
||||
ZMQ,
|
||||
NN,
|
||||
SHM,
|
||||
OFI
|
||||
};
|
||||
@@ -48,7 +47,6 @@ namespace mq
|
||||
static std::unordered_map<std::string, Transport> TransportTypes {
|
||||
{ "default", Transport::DEFAULT },
|
||||
{ "zeromq", Transport::ZMQ },
|
||||
{ "nanomsg", Transport::NN },
|
||||
{ "shmem", Transport::SHM },
|
||||
{ "ofi", Transport::OFI }
|
||||
};
|
||||
@@ -56,7 +54,6 @@ static std::unordered_map<std::string, Transport> TransportTypes {
|
||||
static std::unordered_map<Transport, std::string> TransportNames {
|
||||
{ Transport::DEFAULT, "default" },
|
||||
{ Transport::ZMQ, "zeromq" },
|
||||
{ Transport::NN, "nanomsg" },
|
||||
{ Transport::SHM, "shmem" },
|
||||
{ Transport::OFI, "ofi" }
|
||||
};
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2018-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -21,7 +21,7 @@
|
||||
#define FAIRMQ_GIT_DATE "@PROJECT_GIT_DATE@"
|
||||
#define FAIRMQ_REPO_URL "https://github.com/FairRootGroup/FairMQ"
|
||||
#define FAIRMQ_LICENSE "LGPL-3.0"
|
||||
#define FAIRMQ_COPYRIGHT "2012-2019 GSI"
|
||||
#define FAIRMQ_COPYRIGHT "2012-2020 GSI"
|
||||
#define FAIRMQ_BUILD_TYPE "@CMAKE_BUILD_TYPE@"
|
||||
|
||||
#endif // FAIR_MQ_VERSION_H
|
||||
|
@@ -1,100 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "FairMQBenchmarkSampler.h"
|
||||
|
||||
#include "tools/RateLimit.h"
|
||||
#include "../FairMQLogger.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using namespace std;
|
||||
|
||||
FairMQBenchmarkSampler::FairMQBenchmarkSampler()
|
||||
: fMultipart(false)
|
||||
, fNumParts(1)
|
||||
, fMsgSize(10000)
|
||||
, fMsgRate(0)
|
||||
, fNumIterations(0)
|
||||
, fMaxIterations(0)
|
||||
, fOutChannelName()
|
||||
{
|
||||
}
|
||||
|
||||
void FairMQBenchmarkSampler::InitTask()
|
||||
{
|
||||
fMultipart = fConfig->GetProperty<bool>("multipart");
|
||||
fNumParts = fConfig->GetProperty<size_t>("num-parts");
|
||||
fMsgSize = fConfig->GetProperty<size_t>("msg-size");
|
||||
fMsgRate = fConfig->GetProperty<float>("msg-rate");
|
||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||
fOutChannelName = fConfig->GetProperty<string>("out-channel");
|
||||
}
|
||||
|
||||
void FairMQBenchmarkSampler::Run()
|
||||
{
|
||||
// store the channel reference to avoid traversing the map on every loop iteration
|
||||
FairMQChannel& dataOutChannel = fChannels.at(fOutChannelName).at(0);
|
||||
|
||||
FairMQMessagePtr baseMsg(dataOutChannel.NewMessage(fMsgSize));
|
||||
|
||||
LOG(info) << "Starting the benchmark with message size of " << fMsgSize << " and " << fMaxIterations << " iterations.";
|
||||
auto tStart = chrono::high_resolution_clock::now();
|
||||
|
||||
fair::mq::tools::RateLimiter rateLimiter(fMsgRate);
|
||||
|
||||
while (!NewStatePending())
|
||||
{
|
||||
if (fMultipart)
|
||||
{
|
||||
FairMQParts parts;
|
||||
|
||||
for (size_t i = 0; i < fNumParts; ++i)
|
||||
{
|
||||
parts.AddPart(dataOutChannel.NewMessage(fMsgSize));
|
||||
}
|
||||
|
||||
if (dataOutChannel.Send(parts) >= 0)
|
||||
{
|
||||
if (fMaxIterations > 0)
|
||||
{
|
||||
if (fNumIterations >= fMaxIterations)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
++fNumIterations;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FairMQMessagePtr msg(dataOutChannel.NewMessage(fMsgSize));
|
||||
|
||||
if (dataOutChannel.Send(msg) >= 0)
|
||||
{
|
||||
if (fMaxIterations > 0)
|
||||
{
|
||||
if (fNumIterations >= fMaxIterations)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
++fNumIterations;
|
||||
}
|
||||
}
|
||||
|
||||
if (fMsgRate > 0)
|
||||
{
|
||||
rateLimiter.maybe_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
auto tEnd = chrono::high_resolution_clock::now();
|
||||
|
||||
LOG(info) << "Done " << fNumIterations << " iterations in " << chrono::duration<double, milli>(tEnd - tStart).count() << "ms.";
|
||||
}
|
@@ -9,13 +9,15 @@
|
||||
#ifndef FAIRMQBENCHMARKSAMPLER_H_
|
||||
#define FAIRMQBENCHMARKSAMPLER_H_
|
||||
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint64_t
|
||||
|
||||
|
||||
#include "../FairMQLogger.h"
|
||||
#include "FairMQDevice.h"
|
||||
#include "tools/RateLimit.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint64_t
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* Sampler to generate traffic for benchmarking.
|
||||
@@ -24,7 +26,77 @@
|
||||
class FairMQBenchmarkSampler : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
FairMQBenchmarkSampler();
|
||||
FairMQBenchmarkSampler()
|
||||
: fMultipart(false)
|
||||
, fNumParts(1)
|
||||
, fMsgSize(10000)
|
||||
, fMsgRate(0)
|
||||
, fNumIterations(0)
|
||||
, fMaxIterations(0)
|
||||
, fOutChannelName()
|
||||
{}
|
||||
|
||||
void InitTask() override
|
||||
{
|
||||
fMultipart = fConfig->GetProperty<bool>("multipart");
|
||||
fNumParts = fConfig->GetProperty<size_t>("num-parts");
|
||||
fMsgSize = fConfig->GetProperty<size_t>("msg-size");
|
||||
fMsgRate = fConfig->GetProperty<float>("msg-rate");
|
||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||
fOutChannelName = fConfig->GetProperty<std::string>("out-channel");
|
||||
}
|
||||
|
||||
void Run() override
|
||||
{
|
||||
// store the channel reference to avoid traversing the map on every loop iteration
|
||||
FairMQChannel& dataOutChannel = fChannels.at(fOutChannelName).at(0);
|
||||
|
||||
FairMQMessagePtr baseMsg(dataOutChannel.NewMessage(fMsgSize));
|
||||
|
||||
LOG(info) << "Starting the benchmark with message size of " << fMsgSize << " and " << fMaxIterations << " iterations.";
|
||||
auto tStart = std::chrono::high_resolution_clock::now();
|
||||
|
||||
fair::mq::tools::RateLimiter rateLimiter(fMsgRate);
|
||||
|
||||
while (!NewStatePending()) {
|
||||
if (fMultipart) {
|
||||
FairMQParts parts;
|
||||
|
||||
for (size_t i = 0; i < fNumParts; ++i) {
|
||||
parts.AddPart(dataOutChannel.NewMessage(fMsgSize));
|
||||
}
|
||||
|
||||
if (dataOutChannel.Send(parts) >= 0) {
|
||||
if (fMaxIterations > 0) {
|
||||
if (fNumIterations >= fMaxIterations) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
++fNumIterations;
|
||||
}
|
||||
} else {
|
||||
FairMQMessagePtr msg(dataOutChannel.NewMessage(fMsgSize));
|
||||
|
||||
if (dataOutChannel.Send(msg) >= 0) {
|
||||
if (fMaxIterations > 0) {
|
||||
if (fNumIterations >= fMaxIterations) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
++fNumIterations;
|
||||
}
|
||||
}
|
||||
|
||||
if (fMsgRate > 0) {
|
||||
rateLimiter.maybe_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
auto tEnd = std::chrono::high_resolution_clock::now();
|
||||
|
||||
LOG(info) << "Done " << fNumIterations << " iterations in " << std::chrono::duration<double, std::milli>(tEnd - tStart).count() << "ms.";
|
||||
}
|
||||
|
||||
virtual ~FairMQBenchmarkSampler() {}
|
||||
|
||||
protected:
|
||||
@@ -36,9 +108,6 @@ class FairMQBenchmarkSampler : public FairMQDevice
|
||||
uint64_t fNumIterations;
|
||||
uint64_t fMaxIterations;
|
||||
std::string fOutChannelName;
|
||||
|
||||
virtual void InitTask() override;
|
||||
virtual void Run() override;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQBENCHMARKSAMPLER_H_ */
|
||||
|
@@ -15,14 +15,14 @@
|
||||
#ifndef FAIRMQSINK_H_
|
||||
#define FAIRMQSINK_H_
|
||||
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
#include "../FairMQDevice.h"
|
||||
#include "../FairMQLogger.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
// template<typename OutputPolicy>
|
||||
class FairMQSink : public FairMQDevice//, public OutputPolicy
|
||||
class FairMQSink : public FairMQDevice //, public OutputPolicy
|
||||
{
|
||||
public:
|
||||
FairMQSink()
|
||||
@@ -32,8 +32,7 @@ class FairMQSink : public FairMQDevice//, public OutputPolicy
|
||||
, fInChannelName()
|
||||
{}
|
||||
|
||||
virtual ~FairMQSink()
|
||||
{}
|
||||
virtual ~FairMQSink() {}
|
||||
|
||||
protected:
|
||||
bool fMultipart;
|
||||
@@ -56,35 +55,25 @@ class FairMQSink : public FairMQDevice//, public OutputPolicy
|
||||
LOG(info) << "Starting the benchmark and expecting to receive " << fMaxIterations << " messages.";
|
||||
auto tStart = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while (!NewStatePending())
|
||||
{
|
||||
if (fMultipart)
|
||||
{
|
||||
while (!NewStatePending()) {
|
||||
if (fMultipart) {
|
||||
FairMQParts parts;
|
||||
|
||||
if (dataInChannel.Receive(parts) >= 0)
|
||||
{
|
||||
if (fMaxIterations > 0)
|
||||
{
|
||||
if (fNumIterations >= fMaxIterations)
|
||||
{
|
||||
if (dataInChannel.Receive(parts) >= 0) {
|
||||
if (fMaxIterations > 0) {
|
||||
if (fNumIterations >= fMaxIterations) {
|
||||
LOG(info) << "Configured maximum number of iterations reached.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
fNumIterations++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FairMQMessagePtr msg(dataInChannel.NewMessage());
|
||||
|
||||
if (dataInChannel.Receive(msg) >= 0)
|
||||
{
|
||||
if (fMaxIterations > 0)
|
||||
{
|
||||
if (fNumIterations >= fMaxIterations)
|
||||
{
|
||||
if (dataInChannel.Receive(msg) >= 0) {
|
||||
if (fMaxIterations > 0) {
|
||||
if (fNumIterations >= fMaxIterations) {
|
||||
LOG(info) << "Configured maximum number of iterations reached.";
|
||||
break;
|
||||
}
|
||||
@@ -96,7 +85,8 @@ class FairMQSink : public FairMQDevice//, public OutputPolicy
|
||||
|
||||
auto tEnd = std::chrono::high_resolution_clock::now();
|
||||
|
||||
LOG(info) << "Leaving RUNNING state. Received " << fNumIterations << " messages in " << std::chrono::duration<double, std::milli>(tEnd - tStart).count() << "ms.";
|
||||
LOG(info) << "Leaving RUNNING state. Received " << fNumIterations << " messages in "
|
||||
<< std::chrono::duration<double, std::milli>(tEnd - tStart).count() << "ms.";
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -1,227 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQMessageNN.cxx
|
||||
*
|
||||
* @since 2013-12-05
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <nanomsg/nn.h>
|
||||
|
||||
#include "FairMQMessageNN.h"
|
||||
#include "FairMQLogger.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
fair::mq::Transport FairMQMessageNN::fTransportType = fair::mq::Transport::NN;
|
||||
|
||||
FairMQMessageNN::FairMQMessageNN(FairMQTransportFactory* factory)
|
||||
: FairMQMessage{factory}
|
||||
, fMessage(nullptr)
|
||||
, fSize(0)
|
||||
, fHint(0)
|
||||
, fReceiving(false)
|
||||
, fRegionPtr(nullptr)
|
||||
{
|
||||
fMessage = nn_allocmsg(0, 0);
|
||||
if (!fMessage)
|
||||
{
|
||||
LOG(error) << "failed allocating message, reason: " << nn_strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
FairMQMessageNN::FairMQMessageNN(const size_t size, FairMQTransportFactory* factory)
|
||||
: FairMQMessage{factory}
|
||||
, fMessage(nullptr)
|
||||
, fSize(0)
|
||||
, fHint(0)
|
||||
, fReceiving(false)
|
||||
, fRegionPtr(nullptr)
|
||||
{
|
||||
fMessage = nn_allocmsg(size, 0);
|
||||
if (!fMessage)
|
||||
{
|
||||
LOG(error) << "failed allocating message, reason: " << nn_strerror(errno);
|
||||
}
|
||||
fSize = size;
|
||||
}
|
||||
|
||||
|
||||
/* nanomsg does not offer support for creating a message out of an existing buffer,
|
||||
* therefore the following method is using memcpy. For more efficient handling,
|
||||
* create FairMQMessage object only with size parameter and fill it with data.
|
||||
* possible TODO: make this zero copy (will should then be as efficient as ZeroMQ).
|
||||
*/
|
||||
FairMQMessageNN::FairMQMessageNN(void* data, const size_t size, fairmq_free_fn* ffn, void* hint, FairMQTransportFactory* factory)
|
||||
: FairMQMessage{factory}
|
||||
, fMessage(nullptr)
|
||||
, fSize(0)
|
||||
, fHint(0)
|
||||
, fReceiving(false)
|
||||
, fRegionPtr(nullptr)
|
||||
{
|
||||
fMessage = nn_allocmsg(size, 0);
|
||||
if (!fMessage)
|
||||
{
|
||||
LOG(error) << "failed allocating message, reason: " << nn_strerror(errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(fMessage, data, size);
|
||||
fSize = size;
|
||||
if (ffn)
|
||||
{
|
||||
ffn(data, hint);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FairMQMessageNN::FairMQMessageNN(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint, FairMQTransportFactory* factory)
|
||||
: FairMQMessage{factory}
|
||||
, fMessage(data)
|
||||
, fSize(size)
|
||||
, fHint(reinterpret_cast<size_t>(hint))
|
||||
, fReceiving(false)
|
||||
, fRegionPtr(region.get())
|
||||
{
|
||||
// currently nanomsg will copy the buffer (data) inside nn_sendmsg()
|
||||
}
|
||||
|
||||
void FairMQMessageNN::Rebuild()
|
||||
{
|
||||
CloseMessage();
|
||||
fReceiving = false;
|
||||
}
|
||||
|
||||
void FairMQMessageNN::Rebuild(const size_t size)
|
||||
{
|
||||
CloseMessage();
|
||||
fMessage = nn_allocmsg(size, 0);
|
||||
if (!fMessage)
|
||||
{
|
||||
LOG(error) << "failed allocating message, reason: " << nn_strerror(errno);
|
||||
}
|
||||
fSize = size;
|
||||
fReceiving = false;
|
||||
}
|
||||
|
||||
void FairMQMessageNN::Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint)
|
||||
{
|
||||
CloseMessage();
|
||||
fMessage = nn_allocmsg(size, 0);
|
||||
if (!fMessage)
|
||||
{
|
||||
LOG(error) << "failed allocating message, reason: " << nn_strerror(errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(fMessage, data, size);
|
||||
fSize = size;
|
||||
fReceiving = false;
|
||||
|
||||
if (ffn)
|
||||
{
|
||||
ffn(data, hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* FairMQMessageNN::GetMessage() const
|
||||
{
|
||||
return fMessage;
|
||||
}
|
||||
|
||||
void* FairMQMessageNN::GetData() const
|
||||
{
|
||||
return fMessage;
|
||||
}
|
||||
|
||||
size_t FairMQMessageNN::GetSize() const
|
||||
{
|
||||
return fSize;
|
||||
}
|
||||
|
||||
bool FairMQMessageNN::SetUsedSize(const size_t size)
|
||||
{
|
||||
if (size <= fSize)
|
||||
{
|
||||
// with size smaller than original nanomsg will simply "chop" the data, avoiding reallocation
|
||||
fMessage = nn_reallocmsg(fMessage, size);
|
||||
fSize = size;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(error) << "cannot set used size higher than original.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQMessageNN::SetMessage(void* data, const size_t size)
|
||||
{
|
||||
fMessage = data;
|
||||
fSize = size;
|
||||
}
|
||||
|
||||
fair::mq::Transport FairMQMessageNN::GetType() const
|
||||
{
|
||||
return fTransportType;
|
||||
}
|
||||
|
||||
void FairMQMessageNN::Copy(const FairMQMessage& msg)
|
||||
{
|
||||
if (fMessage)
|
||||
{
|
||||
if (nn_freemsg(fMessage) < 0)
|
||||
{
|
||||
LOG(error) << "failed freeing message, reason: " << nn_strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
size_t size = msg.GetSize();
|
||||
|
||||
fMessage = nn_allocmsg(size, 0);
|
||||
if (!fMessage)
|
||||
{
|
||||
LOG(error) << "failed allocating message, reason: " << nn_strerror(errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(fMessage, static_cast<const FairMQMessageNN&>(msg).GetMessage(), size);
|
||||
fSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQMessageNN::CloseMessage()
|
||||
{
|
||||
if (nn_freemsg(fMessage) < 0)
|
||||
{
|
||||
LOG(error) << "failed freeing message, reason: " << nn_strerror(errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
fMessage = nullptr;
|
||||
fSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
FairMQMessageNN::~FairMQMessageNN()
|
||||
{
|
||||
if (fReceiving)
|
||||
{
|
||||
CloseMessage();
|
||||
}
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQMessageNN.h
|
||||
*
|
||||
* @since 2013-12-05
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQMESSAGENN_H_
|
||||
#define FAIRMQMESSAGENN_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "FairMQMessage.h"
|
||||
#include "FairMQUnmanagedRegion.h"
|
||||
|
||||
class FairMQSocketNN;
|
||||
|
||||
class FairMQMessageNN final : public FairMQMessage
|
||||
{
|
||||
friend class FairMQSocketNN;
|
||||
|
||||
public:
|
||||
FairMQMessageNN(FairMQTransportFactory* factory = nullptr);
|
||||
FairMQMessageNN(const size_t size, FairMQTransportFactory* factory = nullptr);
|
||||
FairMQMessageNN(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr, FairMQTransportFactory* factory = nullptr);
|
||||
FairMQMessageNN(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0, FairMQTransportFactory* factory = nullptr);
|
||||
|
||||
FairMQMessageNN(const FairMQMessageNN&) = delete;
|
||||
FairMQMessageNN operator=(const FairMQMessageNN&) = delete;
|
||||
|
||||
void Rebuild() override;
|
||||
void Rebuild(const size_t size) override;
|
||||
void Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) override;
|
||||
|
||||
void* GetData() const override;
|
||||
size_t GetSize() const override;
|
||||
|
||||
bool SetUsedSize(const size_t size) override;
|
||||
|
||||
fair::mq::Transport GetType() const override;
|
||||
|
||||
void Copy(const FairMQMessage& msg) override;
|
||||
|
||||
~FairMQMessageNN() override;
|
||||
|
||||
private:
|
||||
void* fMessage;
|
||||
size_t fSize;
|
||||
size_t fHint;
|
||||
bool fReceiving;
|
||||
FairMQUnmanagedRegion* fRegionPtr;
|
||||
static fair::mq::Transport fTransportType;
|
||||
|
||||
void* GetMessage() const;
|
||||
void CloseMessage();
|
||||
void SetMessage(void* data, const size_t size);
|
||||
};
|
||||
|
||||
#endif /* FAIRMQMESSAGENN_H_ */
|
@@ -1,207 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQPollerNN.cxx
|
||||
*
|
||||
* @since 2014-01-23
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include <nanomsg/nn.h>
|
||||
#include <nanomsg/pipeline.h>
|
||||
#include <nanomsg/pubsub.h>
|
||||
#include <nanomsg/reqrep.h>
|
||||
#include <nanomsg/pair.h>
|
||||
|
||||
#include "FairMQPollerNN.h"
|
||||
#include "FairMQSocketNN.h"
|
||||
#include "FairMQLogger.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
FairMQPollerNN::FairMQPollerNN(const vector<FairMQChannel>& channels)
|
||||
: fItems()
|
||||
, fNumItems(0)
|
||||
, fOffsetMap()
|
||||
{
|
||||
fNumItems = channels.size();
|
||||
fItems = new nn_pollfd[fNumItems];
|
||||
|
||||
for (int i = 0; i < fNumItems; ++i)
|
||||
{
|
||||
fItems[i].fd = static_cast<const FairMQSocketNN*>(&(channels.at(i).GetSocket()))->GetSocket();
|
||||
|
||||
int type = 0;
|
||||
size_t sz = sizeof(type);
|
||||
nn_getsockopt(static_cast<const FairMQSocketNN*>(&(channels.at(i).GetSocket()))->GetSocket(), NN_SOL_SOCKET, NN_PROTOCOL, &type, &sz);
|
||||
|
||||
SetItemEvents(fItems[i], type);
|
||||
}
|
||||
}
|
||||
|
||||
FairMQPollerNN::FairMQPollerNN(const vector<FairMQChannel*>& channels)
|
||||
: fItems()
|
||||
, fNumItems(0)
|
||||
, fOffsetMap()
|
||||
{
|
||||
fNumItems = channels.size();
|
||||
fItems = new nn_pollfd[fNumItems];
|
||||
|
||||
for (int i = 0; i < fNumItems; ++i)
|
||||
{
|
||||
fItems[i].fd = static_cast<const FairMQSocketNN*>(&(channels.at(i)->GetSocket()))->GetSocket();
|
||||
|
||||
int type = 0;
|
||||
size_t sz = sizeof(type);
|
||||
nn_getsockopt(static_cast<const FairMQSocketNN*>(&(channels.at(i)->GetSocket()))->GetSocket(), NN_SOL_SOCKET, NN_PROTOCOL, &type, &sz);
|
||||
|
||||
SetItemEvents(fItems[i], type);
|
||||
}
|
||||
}
|
||||
|
||||
FairMQPollerNN::FairMQPollerNN(const unordered_map<string, vector<FairMQChannel>>& channelsMap, const vector<string>& channelList)
|
||||
: fItems()
|
||||
, fNumItems(0)
|
||||
, fOffsetMap()
|
||||
{
|
||||
try
|
||||
{
|
||||
int offset = 0;
|
||||
// calculate offsets and the total size of the poll item set
|
||||
for (string channel : channelList)
|
||||
{
|
||||
fOffsetMap[channel] = offset;
|
||||
offset += channelsMap.at(channel).size();
|
||||
fNumItems += channelsMap.at(channel).size();
|
||||
}
|
||||
|
||||
fItems = new nn_pollfd[fNumItems];
|
||||
|
||||
int index = 0;
|
||||
for (string channel : channelList)
|
||||
{
|
||||
for (unsigned int i = 0; i < channelsMap.at(channel).size(); ++i)
|
||||
{
|
||||
index = fOffsetMap[channel] + i;
|
||||
fItems[index].fd = static_cast<const FairMQSocketNN*>(&(channelsMap.at(channel).at(i).GetSocket()))->GetSocket();
|
||||
|
||||
int type = 0;
|
||||
size_t sz = sizeof(type);
|
||||
nn_getsockopt(static_cast<const FairMQSocketNN*>(&(channelsMap.at(channel).at(i).GetSocket()))->GetSocket(), NN_SOL_SOCKET, NN_PROTOCOL, &type, &sz);
|
||||
|
||||
SetItemEvents(fItems[index], type);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::out_of_range& oor)
|
||||
{
|
||||
LOG(error) << "at least one of the provided channel keys for poller initialization is invalid";
|
||||
LOG(error) << "out of range error: " << oor.what() << '\n';
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQPollerNN::SetItemEvents(nn_pollfd& item, const int type)
|
||||
{
|
||||
if (type == NN_REQ || type == NN_REP || type == NN_PAIR)
|
||||
{
|
||||
item.events = NN_POLLIN|NN_POLLOUT;
|
||||
}
|
||||
else if (type == NN_PUSH || type == NN_PUB)
|
||||
{
|
||||
item.events = NN_POLLOUT;
|
||||
}
|
||||
else if (type == NN_PULL || type == NN_SUB)
|
||||
{
|
||||
item.events = NN_POLLIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(error) << "invalid poller configuration, exiting.";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQPollerNN::Poll(const int timeout)
|
||||
{
|
||||
if (nn_poll(fItems, fNumItems, timeout) < 0)
|
||||
{
|
||||
if (errno == ETERM)
|
||||
{
|
||||
LOG(debug) << "polling exited, reason: " << nn_strerror(errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(error) << "polling failed, reason: " << nn_strerror(errno);
|
||||
throw std::runtime_error("polling failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FairMQPollerNN::CheckInput(const int index)
|
||||
{
|
||||
if (fItems[index].revents & (NN_POLLIN | NN_POLLOUT))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FairMQPollerNN::CheckOutput(const int index)
|
||||
{
|
||||
if (fItems[index].revents & NN_POLLOUT)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FairMQPollerNN::CheckInput(const string& channelKey, const int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (fItems[fOffsetMap.at(channelKey) + index].revents & (NN_POLLIN | NN_POLLOUT))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (const std::out_of_range& oor)
|
||||
{
|
||||
LOG(error) << "invalid channel key: \"" << channelKey << "\"";
|
||||
LOG(error) << "out of range error: " << oor.what() << '\n';
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
bool FairMQPollerNN::CheckOutput(const string& channelKey, const int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (fItems[fOffsetMap.at(channelKey) + index].revents & NN_POLLOUT)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (const std::out_of_range& oor)
|
||||
{
|
||||
LOG(error) << "invalid channel key: \"" << channelKey << "\"";
|
||||
LOG(error) << "out of range error: " << oor.what() << '\n';
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
FairMQPollerNN::~FairMQPollerNN()
|
||||
{
|
||||
delete[] fItems;
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQPollerNN.h
|
||||
*
|
||||
* @since 2014-01-23
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQPOLLERNN_H_
|
||||
#define FAIRMQPOLLERNN_H_
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "FairMQPoller.h"
|
||||
#include "FairMQChannel.h"
|
||||
#include "FairMQTransportFactoryNN.h"
|
||||
|
||||
class FairMQChannel;
|
||||
struct nn_pollfd;
|
||||
|
||||
class FairMQPollerNN final : public FairMQPoller
|
||||
{
|
||||
friend class FairMQChannel;
|
||||
friend class FairMQTransportFactoryNN;
|
||||
|
||||
public:
|
||||
FairMQPollerNN(const std::vector<FairMQChannel>& channels);
|
||||
FairMQPollerNN(const std::vector<FairMQChannel*>& channels);
|
||||
FairMQPollerNN(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList);
|
||||
|
||||
FairMQPollerNN(const FairMQPollerNN&) = delete;
|
||||
FairMQPollerNN operator=(const FairMQPollerNN&) = delete;
|
||||
|
||||
void SetItemEvents(nn_pollfd& item, const int type);
|
||||
|
||||
void Poll(const int timeout) override;
|
||||
bool CheckInput(const int index) override;
|
||||
bool CheckOutput(const int index) override;
|
||||
bool CheckInput(const std::string& channelKey, const int index) override;
|
||||
bool CheckOutput(const std::string& channelKey, const int index) override;
|
||||
|
||||
~FairMQPollerNN() override;
|
||||
|
||||
private:
|
||||
nn_pollfd* fItems;
|
||||
int fNumItems;
|
||||
|
||||
std::unordered_map<std::string, int> fOffsetMap;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQPOLLERNN_H_ */
|
@@ -1,628 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQSocketNN.cxx
|
||||
*
|
||||
* @since 2012-12-05
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include "FairMQSocketNN.h"
|
||||
#include "FairMQMessageNN.h"
|
||||
#include "FairMQLogger.h"
|
||||
#include "FairMQUnmanagedRegionNN.h"
|
||||
#include <fairmq/Tools.h>
|
||||
|
||||
#include <nanomsg/nn.h>
|
||||
#include <nanomsg/pipeline.h>
|
||||
#include <nanomsg/pubsub.h>
|
||||
#include <nanomsg/reqrep.h>
|
||||
#include <nanomsg/pair.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <msgpack.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace fair::mq;
|
||||
|
||||
atomic<bool> FairMQSocketNN::fInterrupted(false);
|
||||
|
||||
FairMQSocketNN::FairMQSocketNN(const string& type, const string& name, const string& id /*= ""*/, FairMQTransportFactory* fac /*=nullptr*/)
|
||||
: FairMQSocket{fac}
|
||||
, fSocket(-1)
|
||||
, fId(id + "." + name + "." + type)
|
||||
, fBytesTx(0)
|
||||
, fBytesRx(0)
|
||||
, fMessagesTx(0)
|
||||
, fMessagesRx(0)
|
||||
, fSndTimeout(100)
|
||||
, fRcvTimeout(100)
|
||||
, fLinger(500)
|
||||
{
|
||||
if (type == "router" || type == "dealer")
|
||||
{
|
||||
// Additional info about using the sockets ROUTER and DEALER with nanomsg can be found in:
|
||||
// http://250bpm.com/blog:14
|
||||
// http://www.freelists.org/post/nanomsg/a-stupid-load-balancing-question,1
|
||||
fSocket = nn_socket(AF_SP_RAW, GetConstant(type));
|
||||
if (fSocket == -1)
|
||||
{
|
||||
LOG(error) << "failed creating socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fSocket = nn_socket(AF_SP, GetConstant(type));
|
||||
if (fSocket == -1)
|
||||
{
|
||||
LOG(error) << "failed creating socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (type == "sub")
|
||||
{
|
||||
nn_setsockopt(fSocket, NN_SUB, NN_SUB_SUBSCRIBE, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (nn_setsockopt(fSocket, NN_SOL_SOCKET, NN_SNDTIMEO, &fSndTimeout, sizeof(fSndTimeout)) != 0)
|
||||
{
|
||||
LOG(error) << "Failed setting NN_SNDTIMEO socket option, reason: " << nn_strerror(errno);
|
||||
}
|
||||
|
||||
if (nn_setsockopt(fSocket, NN_SOL_SOCKET, NN_RCVTIMEO, &fRcvTimeout, sizeof(fRcvTimeout)) != 0)
|
||||
{
|
||||
LOG(error) << "Failed setting NN_RCVTIMEO socket option, reason: " << nn_strerror(errno);
|
||||
}
|
||||
|
||||
#ifdef NN_RCVMAXSIZE
|
||||
int rcvSize = -1;
|
||||
if (nn_setsockopt(fSocket, NN_SOL_SOCKET, NN_RCVMAXSIZE, &rcvSize, sizeof(rcvSize)) != 0)
|
||||
{
|
||||
LOG(error) << "Failed setting NN_RCVMAXSIZE socket option, reason: " << nn_strerror(errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG(debug) << "Created socket " << GetId();
|
||||
}
|
||||
|
||||
bool FairMQSocketNN::Bind(const string& address)
|
||||
{
|
||||
// LOG(info) << "bind socket " << fId << " on " << address;
|
||||
|
||||
if (nn_bind(fSocket, address.c_str()) < 0)
|
||||
{
|
||||
LOG(error) << "failed binding socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FairMQSocketNN::Connect(const string& address)
|
||||
{
|
||||
// LOG(info) << "connect socket " << fId << " to " << address;
|
||||
|
||||
if (nn_connect(fSocket, address.c_str()) < 0)
|
||||
{
|
||||
LOG(error) << "failed connecting socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int FairMQSocketNN::Send(FairMQMessagePtr& msg, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
flags = NN_DONTWAIT;
|
||||
}
|
||||
int nbytes = -1;
|
||||
int elapsed = 0;
|
||||
|
||||
FairMQMessageNN* msgPtr = static_cast<FairMQMessageNN*>(msg.get());
|
||||
void* bufPtr = msgPtr->GetMessage();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (msgPtr->fRegionPtr == nullptr)
|
||||
{
|
||||
nbytes = nn_send(fSocket, &bufPtr, NN_MSG, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
nbytes = nn_send(fSocket, bufPtr, msg->GetSize(), flags);
|
||||
// nn_send copies the data, safe to call region callback here
|
||||
static_cast<FairMQUnmanagedRegionNN*>(msgPtr->fRegionPtr)->fCallback(bufPtr, msg->GetSize(), reinterpret_cast<void*>(msgPtr->fHint));
|
||||
}
|
||||
|
||||
if (nbytes >= 0)
|
||||
{
|
||||
fBytesTx += nbytes;
|
||||
++fMessagesTx;
|
||||
static_cast<FairMQMessageNN*>(msg.get())->fReceiving = false;
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
else if (nn_errno() == ETIMEDOUT)
|
||||
{
|
||||
if (!fInterrupted && ((flags & NN_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
elapsed += fSndTimeout;
|
||||
if (elapsed >= timeout)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else if (nn_errno() == EAGAIN)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
else if (nn_errno() == ETERM)
|
||||
{
|
||||
LOG(info) << "terminating socket " << fId;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(error) << "Failed sending on socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
return nbytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FairMQSocketNN::Receive(FairMQMessagePtr& msg, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
flags = NN_DONTWAIT;
|
||||
}
|
||||
int elapsed = 0;
|
||||
|
||||
FairMQMessageNN* msgPtr = static_cast<FairMQMessageNN*>(msg.get());
|
||||
|
||||
while (true)
|
||||
{
|
||||
void* ptr = nullptr;
|
||||
int nbytes = nn_recv(fSocket, &ptr, NN_MSG, flags);
|
||||
if (nbytes >= 0)
|
||||
{
|
||||
fBytesRx += nbytes;
|
||||
++fMessagesRx;
|
||||
msgPtr->SetMessage(ptr, nbytes);
|
||||
msgPtr->fReceiving = true;
|
||||
return nbytes;
|
||||
}
|
||||
else if (nn_errno() == ETIMEDOUT)
|
||||
{
|
||||
if (!fInterrupted && ((flags & NN_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
elapsed += fRcvTimeout;
|
||||
if (elapsed >= timeout)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else if (nn_errno() == EAGAIN)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
else if (nn_errno() == ETERM)
|
||||
{
|
||||
LOG(info) << "terminating socket " << fId;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(error) << "Failed receiving on socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
return nbytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t FairMQSocketNN::Send(vector<FairMQMessagePtr>& msgVec, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
flags = NN_DONTWAIT;
|
||||
}
|
||||
const unsigned int vecSize = msgVec.size();
|
||||
int elapsed = 0;
|
||||
|
||||
// create msgpack simple buffer
|
||||
msgpack::sbuffer sbuf;
|
||||
// create msgpack packer
|
||||
msgpack::packer<msgpack::sbuffer> packer(&sbuf);
|
||||
|
||||
// pack all parts into a single msgpack simple buffer
|
||||
for (unsigned int i = 0; i < vecSize; ++i)
|
||||
{
|
||||
FairMQMessageNN* partPtr = static_cast<FairMQMessageNN*>(msgVec[i].get());
|
||||
|
||||
partPtr->fReceiving = false;
|
||||
packer.pack_bin(msgVec[i]->GetSize());
|
||||
packer.pack_bin_body(static_cast<char*>(msgVec[i]->GetData()), msgVec[i]->GetSize());
|
||||
// call region callback
|
||||
if (partPtr->fRegionPtr)
|
||||
{
|
||||
static_cast<FairMQUnmanagedRegionNN*>(partPtr->fRegionPtr)->fCallback(partPtr->GetMessage(), partPtr->GetSize(), reinterpret_cast<void*>(partPtr->fHint));
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
int64_t nbytes = nn_send(fSocket, sbuf.data(), sbuf.size(), flags);
|
||||
if (nbytes >= 0)
|
||||
{
|
||||
fBytesTx += nbytes;
|
||||
++fMessagesTx;
|
||||
return nbytes;
|
||||
}
|
||||
else if (nn_errno() == ETIMEDOUT)
|
||||
{
|
||||
if (!fInterrupted && ((flags & NN_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
elapsed += fSndTimeout;
|
||||
if (elapsed >= timeout)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else if (nn_errno() == EAGAIN)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
else if (nn_errno() == ETERM)
|
||||
{
|
||||
LOG(info) << "terminating socket " << fId;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(error) << "Failed sending on socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
return nbytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t FairMQSocketNN::Receive(vector<FairMQMessagePtr>& msgVec, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
flags = NN_DONTWAIT;
|
||||
}
|
||||
// Warn if the vector is filled before Receive() and empty it.
|
||||
// if (msgVec.size() > 0)
|
||||
// {
|
||||
// LOG(warn) << "Message vector contains elements before Receive(), they will be deleted!";
|
||||
// msgVec.clear();
|
||||
// }
|
||||
|
||||
int elapsed = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// pointer to point to received message buffer
|
||||
char* ptr = nullptr;
|
||||
// receive the message into a buffer allocated by nanomsg and let ptr point to it
|
||||
int nbytes = nn_recv(fSocket, &ptr, NN_MSG, flags);
|
||||
if (nbytes >= 0) // if no errors or non-blocking timeouts
|
||||
{
|
||||
// store statistics on how many bytes received
|
||||
fBytesRx += nbytes;
|
||||
// store statistics on how many messages received (count messages instead of parts)
|
||||
++fMessagesRx;
|
||||
|
||||
// offset to be used by msgpack to handle separate chunks
|
||||
size_t offset = 0;
|
||||
while (offset != static_cast<size_t>(nbytes)) // continue until all parts have been read
|
||||
{
|
||||
// vector of chars to hold blob (unlike char*/void* this type can be converted to by msgpack)
|
||||
vector<char> buf;
|
||||
|
||||
// unpack and convert chunk
|
||||
msgpack::unpacked result;
|
||||
unpack(result, ptr, nbytes, offset);
|
||||
msgpack::object object(result.get());
|
||||
object.convert(buf);
|
||||
// get the single message size
|
||||
size_t size = buf.size() * sizeof(char);
|
||||
FairMQMessagePtr part(new FairMQMessageNN(size, GetTransport()));
|
||||
static_cast<FairMQMessageNN*>(part.get())->fReceiving = true;
|
||||
memcpy(part->GetData(), buf.data(), size);
|
||||
msgVec.push_back(move(part));
|
||||
}
|
||||
|
||||
nn_freemsg(ptr);
|
||||
return nbytes;
|
||||
}
|
||||
else if (nn_errno() == ETIMEDOUT)
|
||||
{
|
||||
if (!fInterrupted && ((flags & NN_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
elapsed += fRcvTimeout;
|
||||
if (elapsed >= timeout)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else if (nn_errno() == EAGAIN)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
else if (nn_errno() == ETERM)
|
||||
{
|
||||
LOG(info) << "terminating socket " << fId;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(error) << "Failed receiving on socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
return nbytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQSocketNN::Close()
|
||||
{
|
||||
nn_close(fSocket);
|
||||
}
|
||||
|
||||
void FairMQSocketNN::Interrupt()
|
||||
{
|
||||
fInterrupted = true;
|
||||
}
|
||||
|
||||
void FairMQSocketNN::Resume()
|
||||
{
|
||||
fInterrupted = false;
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetSocket() const
|
||||
{
|
||||
return fSocket;
|
||||
}
|
||||
|
||||
void FairMQSocketNN::SetOption(const string& option, const void* value, size_t valueSize)
|
||||
{
|
||||
if (option == "snd-size" || option == "rcv-size")
|
||||
{
|
||||
int val = *(static_cast<int*>(const_cast<void*>(value)));
|
||||
if (val <= 0)
|
||||
{
|
||||
LOG(warn) << "value for sndKernelSize/rcvKernelSize should be greater than 0, leaving unchanged.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (option == "snd-hwm" || option == "rcv-hwm")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (option == "linger")
|
||||
{
|
||||
fLinger = *static_cast<int*>(const_cast<void*>(value));
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = nn_setsockopt(fSocket, NN_SOL_SOCKET, GetConstant(option), value, valueSize);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG(error) << "failed setting socket option, reason: " << nn_strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQSocketNN::GetOption(const string& option, void* value, size_t* valueSize)
|
||||
{
|
||||
if (option == "linger")
|
||||
{
|
||||
*static_cast<int*>(value) = fLinger;
|
||||
return;
|
||||
}
|
||||
|
||||
if (option == "snd-hwm" || option == "rcv-hwm")
|
||||
{
|
||||
*static_cast<int*>(value) = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int rc = nn_getsockopt(fSocket, NN_SOL_SOCKET, GetConstant(option), value, valueSize);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG(error) << "failed getting socket option, reason: " << nn_strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQSocketNN::SetLinger(const int value)
|
||||
{
|
||||
fLinger = value;
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetLinger() const
|
||||
{
|
||||
return fLinger;
|
||||
}
|
||||
|
||||
void FairMQSocketNN::SetSndBufSize(const int /* value */)
|
||||
{
|
||||
// not used in nanomsg
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetSndBufSize() const
|
||||
{
|
||||
// not used in nanomsg
|
||||
return -1;
|
||||
}
|
||||
|
||||
void FairMQSocketNN::SetRcvBufSize(const int /* value */)
|
||||
{
|
||||
// not used in nanomsg
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetRcvBufSize() const
|
||||
{
|
||||
// not used in nanomsg
|
||||
return -1;
|
||||
}
|
||||
|
||||
void FairMQSocketNN::SetSndKernelSize(const int value)
|
||||
{
|
||||
if (nn_setsockopt(fSocket, NN_SOL_SOCKET, NN_SNDBUF, &value, sizeof(value)) < 0) {
|
||||
throw SocketError(tools::ToString("failed setting NN_SNDBUF, reason: ", nn_strerror(errno)));
|
||||
}
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetSndKernelSize() const
|
||||
{
|
||||
int value = 0;
|
||||
size_t valueSize;
|
||||
if (nn_getsockopt(fSocket, NN_SOL_SOCKET, NN_SNDBUF, &value, &valueSize) < 0) {
|
||||
throw SocketError(tools::ToString("failed getting NN_SNDBUF, reason: ", nn_strerror(errno)));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void FairMQSocketNN::SetRcvKernelSize(const int value)
|
||||
{
|
||||
if (nn_setsockopt(fSocket, NN_SOL_SOCKET, NN_RCVBUF, &value, sizeof(value)) < 0) {
|
||||
throw SocketError(tools::ToString("failed setting NN_RCVBUF, reason: ", nn_strerror(errno)));
|
||||
}
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetRcvKernelSize() const
|
||||
{
|
||||
int value = 0;
|
||||
size_t valueSize;
|
||||
if (nn_getsockopt(fSocket, NN_SOL_SOCKET, NN_RCVBUF, &value, &valueSize) < 0) {
|
||||
throw SocketError(tools::ToString("failed getting NN_RCVBUF, reason: ", nn_strerror(errno)));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
unsigned long FairMQSocketNN::GetBytesTx() const
|
||||
{
|
||||
return fBytesTx;
|
||||
}
|
||||
|
||||
unsigned long FairMQSocketNN::GetBytesRx() const
|
||||
{
|
||||
return fBytesRx;
|
||||
}
|
||||
|
||||
unsigned long FairMQSocketNN::GetMessagesTx() const
|
||||
{
|
||||
return fMessagesTx;
|
||||
}
|
||||
|
||||
unsigned long FairMQSocketNN::GetMessagesRx() const
|
||||
{
|
||||
return fMessagesRx;
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetConstant(const string& constant)
|
||||
{
|
||||
if (constant == "")
|
||||
return 0;
|
||||
if (constant == "sub")
|
||||
return NN_SUB;
|
||||
if (constant == "pub")
|
||||
return NN_PUB;
|
||||
if (constant == "xsub")
|
||||
return NN_SUB;
|
||||
if (constant == "xpub")
|
||||
return NN_PUB;
|
||||
if (constant == "push")
|
||||
return NN_PUSH;
|
||||
if (constant == "pull")
|
||||
return NN_PULL;
|
||||
if (constant == "req")
|
||||
return NN_REQ;
|
||||
if (constant == "rep")
|
||||
return NN_REP;
|
||||
if (constant == "dealer")
|
||||
return NN_REQ;
|
||||
if (constant == "router")
|
||||
return NN_REP;
|
||||
if (constant == "pair")
|
||||
return NN_PAIR;
|
||||
|
||||
if (constant == "snd-hwm")
|
||||
return NN_SNDBUF;
|
||||
if (constant == "rcv-hwm")
|
||||
return NN_RCVBUF;
|
||||
if (constant == "snd-size")
|
||||
return NN_SNDBUF;
|
||||
if (constant == "rcv-size")
|
||||
return NN_RCVBUF;
|
||||
if (constant == "snd-more")
|
||||
{
|
||||
LOG(error) << "Multipart messages functionality currently not supported by nanomsg!";
|
||||
return -1;
|
||||
}
|
||||
if (constant == "rcv-more")
|
||||
{
|
||||
LOG(error) << "Multipart messages functionality currently not supported by nanomsg!";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (constant == "linger")
|
||||
return NN_LINGER;
|
||||
if (constant == "no-block")
|
||||
return NN_DONTWAIT;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
FairMQSocketNN::~FairMQSocketNN()
|
||||
{
|
||||
Close();
|
||||
}
|
@@ -1,81 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIRMQSOCKETNN_H_
|
||||
#define FAIRMQSOCKETNN_H_
|
||||
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
|
||||
#include "FairMQSocket.h"
|
||||
#include "FairMQMessage.h"
|
||||
class FairMQTransportFactory;
|
||||
|
||||
class FairMQSocketNN final : public FairMQSocket
|
||||
{
|
||||
public:
|
||||
FairMQSocketNN(const std::string& type, const std::string& name, const std::string& id = "", FairMQTransportFactory* fac = nullptr);
|
||||
FairMQSocketNN(const FairMQSocketNN&) = delete;
|
||||
FairMQSocketNN operator=(const FairMQSocketNN&) = delete;
|
||||
|
||||
std::string GetId() const override { return fId; }
|
||||
|
||||
bool Bind(const std::string& address) override;
|
||||
bool Connect(const std::string& address) override;
|
||||
|
||||
int Send(FairMQMessagePtr& msg, const int timeout = -1) override;
|
||||
int Receive(FairMQMessagePtr& msg, const int timeout = -1) override;
|
||||
int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int timeout = -1) override;
|
||||
int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int timeout = -1) override;
|
||||
|
||||
int GetSocket() const;
|
||||
|
||||
void Close() override;
|
||||
|
||||
static void Interrupt();
|
||||
static void Resume();
|
||||
|
||||
void SetOption(const std::string& option, const void* value, size_t valueSize) override;
|
||||
void GetOption(const std::string& option, void* value, size_t* valueSize) override;
|
||||
|
||||
void SetLinger(const int value) override;
|
||||
int GetLinger() const override;
|
||||
void SetSndBufSize(const int value) override;
|
||||
int GetSndBufSize() const override;
|
||||
void SetRcvBufSize(const int value) override;
|
||||
int GetRcvBufSize() const override;
|
||||
void SetSndKernelSize(const int value) override;
|
||||
int GetSndKernelSize() const override;
|
||||
void SetRcvKernelSize(const int value) override;
|
||||
int GetRcvKernelSize() const override;
|
||||
|
||||
unsigned long GetBytesTx() const override;
|
||||
unsigned long GetBytesRx() const override;
|
||||
unsigned long GetMessagesTx() const override;
|
||||
unsigned long GetMessagesRx() const override;
|
||||
|
||||
static int GetConstant(const std::string& constant);
|
||||
|
||||
~FairMQSocketNN() override;
|
||||
|
||||
private:
|
||||
int fSocket;
|
||||
std::string fId;
|
||||
std::atomic<unsigned long> fBytesTx;
|
||||
std::atomic<unsigned long> fBytesRx;
|
||||
std::atomic<unsigned long> fMessagesTx;
|
||||
std::atomic<unsigned long> fMessagesRx;
|
||||
|
||||
static std::atomic<bool> fInterrupted;
|
||||
|
||||
int fSndTimeout;
|
||||
int fRcvTimeout;
|
||||
int fLinger;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQSOCKETNN_H_ */
|
@@ -1,94 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2017 GSI Helmholtzzentrum fuer Schwerionenforschung Gmb *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "FairMQTransportFactoryNN.h"
|
||||
|
||||
#include <nanomsg/nn.h>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std;
|
||||
|
||||
fair::mq::Transport FairMQTransportFactoryNN::fTransportType = fair::mq::Transport::NN;
|
||||
|
||||
FairMQTransportFactoryNN::FairMQTransportFactoryNN(const string& id, const fair::mq::ProgOptions* /*config*/)
|
||||
: FairMQTransportFactory(id)
|
||||
{
|
||||
LOG(debug) << "Transport: Using nanomsg library";
|
||||
}
|
||||
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage()
|
||||
{
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN(this));
|
||||
}
|
||||
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage(const size_t size)
|
||||
{
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN(size, this));
|
||||
}
|
||||
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint)
|
||||
{
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN(data, size, ffn, hint, this));
|
||||
}
|
||||
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint)
|
||||
{
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN(region, data, size, hint, this));
|
||||
}
|
||||
|
||||
FairMQSocketPtr FairMQTransportFactoryNN::CreateSocket(const string& type, const string& name)
|
||||
{
|
||||
unique_ptr<FairMQSocket> socket(new FairMQSocketNN(type, name, GetId(), this));
|
||||
fSockets.push_back(socket.get());
|
||||
return socket;
|
||||
}
|
||||
|
||||
FairMQPollerPtr FairMQTransportFactoryNN::CreatePoller(const vector<FairMQChannel>& channels) const
|
||||
{
|
||||
return unique_ptr<FairMQPoller>(new FairMQPollerNN(channels));
|
||||
}
|
||||
|
||||
FairMQPollerPtr FairMQTransportFactoryNN::CreatePoller(const std::vector<FairMQChannel*>& channels) const
|
||||
{
|
||||
return unique_ptr<FairMQPoller>(new FairMQPollerNN(channels));
|
||||
}
|
||||
|
||||
FairMQPollerPtr FairMQTransportFactoryNN::CreatePoller(const unordered_map<string, vector<FairMQChannel>>& channelsMap, const vector<string>& channelList) const
|
||||
{
|
||||
return unique_ptr<FairMQPoller>(new FairMQPollerNN(channelsMap, channelList));
|
||||
}
|
||||
|
||||
FairMQUnmanagedRegionPtr FairMQTransportFactoryNN::CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback, const std::string& path /* = "" */, int flags /* = 0 */) const
|
||||
{
|
||||
return unique_ptr<FairMQUnmanagedRegion>(new FairMQUnmanagedRegionNN(size, callback, path, flags));
|
||||
}
|
||||
|
||||
fair::mq::Transport FairMQTransportFactoryNN::GetType() const
|
||||
{
|
||||
return fTransportType;
|
||||
}
|
||||
|
||||
void FairMQTransportFactoryNN::Reset()
|
||||
{
|
||||
auto it = max_element(fSockets.begin(), fSockets.end(), [](FairMQSocket* s1, FairMQSocket* s2) {
|
||||
return static_cast<FairMQSocketNN*>(s1)->GetLinger() < static_cast<FairMQSocketNN*>(s2)->GetLinger();
|
||||
});
|
||||
if (it != fSockets.end()) {
|
||||
this_thread::sleep_for(chrono::milliseconds(static_cast<FairMQSocketNN*>(*it)->GetLinger()));
|
||||
}
|
||||
fSockets.clear();
|
||||
}
|
||||
|
||||
FairMQTransportFactoryNN::~FairMQTransportFactoryNN()
|
||||
{
|
||||
LOG(debug) << "Destroying Shared Memory transport...";
|
||||
// nn_term();
|
||||
// see https://www.freelists.org/post/nanomsg/Getting-rid-of-nn-init-and-nn-term,8
|
||||
}
|
@@ -1,52 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIRMQTRANSPORTFACTORYNN_H_
|
||||
#define FAIRMQTRANSPORTFACTORYNN_H_
|
||||
|
||||
#include "FairMQTransportFactory.h"
|
||||
#include "FairMQMessageNN.h"
|
||||
#include "FairMQSocketNN.h"
|
||||
#include "FairMQPollerNN.h"
|
||||
#include "FairMQUnmanagedRegionNN.h"
|
||||
#include <fairmq/ProgOptions.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class FairMQTransportFactoryNN final : public FairMQTransportFactory
|
||||
{
|
||||
public:
|
||||
FairMQTransportFactoryNN(const std::string& id = "", const fair::mq::ProgOptions* config = nullptr);
|
||||
~FairMQTransportFactoryNN() override;
|
||||
|
||||
FairMQMessagePtr CreateMessage() override;
|
||||
FairMQMessagePtr CreateMessage(const size_t size) override;
|
||||
FairMQMessagePtr CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) override;
|
||||
FairMQMessagePtr CreateMessage(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0) override;
|
||||
|
||||
FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name) override;
|
||||
|
||||
FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel>& channels) const override;
|
||||
FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel*>& channels) const override;
|
||||
FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const override;
|
||||
|
||||
FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback, const std::string& path = "", int flags = 0) const override;
|
||||
|
||||
fair::mq::Transport GetType() const override;
|
||||
|
||||
void Interrupt() override { FairMQSocketNN::Interrupt(); }
|
||||
void Resume() override { FairMQSocketNN::Resume(); }
|
||||
void Reset() override;
|
||||
|
||||
private:
|
||||
static fair::mq::Transport fTransportType;
|
||||
mutable std::vector<FairMQSocket*> fSockets;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQTRANSPORTFACTORYNN_H_ */
|
@@ -1,37 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIRMQUNMANAGEDREGIONNN_H_
|
||||
#define FAIRMQUNMANAGEDREGIONNN_H_
|
||||
|
||||
#include "FairMQUnmanagedRegion.h"
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <string>
|
||||
|
||||
class FairMQUnmanagedRegionNN final : public FairMQUnmanagedRegion
|
||||
{
|
||||
friend class FairMQSocketNN;
|
||||
|
||||
public:
|
||||
FairMQUnmanagedRegionNN(const size_t size, FairMQRegionCallback callback, const std::string& path = "", int flags = 0);
|
||||
FairMQUnmanagedRegionNN(const FairMQUnmanagedRegionNN&) = delete;
|
||||
FairMQUnmanagedRegionNN operator=(const FairMQUnmanagedRegionNN&) = delete;
|
||||
|
||||
virtual void* GetData() const override;
|
||||
virtual size_t GetSize() const override;
|
||||
|
||||
virtual ~FairMQUnmanagedRegionNN();
|
||||
|
||||
private:
|
||||
void* fBuffer;
|
||||
size_t fSize;
|
||||
FairMQRegionCallback fCallback;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQUNMANAGEDREGIONNN_H_ */
|
@@ -34,6 +34,16 @@ Message::Message(boost::container::pmr::memory_resource* pmr)
|
||||
{
|
||||
}
|
||||
|
||||
Message::Message(boost::container::pmr::memory_resource* pmr, Alignment /* alignment */)
|
||||
: fInitialSize(0)
|
||||
, fSize(0)
|
||||
, fData(nullptr)
|
||||
, fFreeFunction(nullptr)
|
||||
, fHint(nullptr)
|
||||
, fPmr(pmr)
|
||||
{
|
||||
}
|
||||
|
||||
Message::Message(boost::container::pmr::memory_resource* pmr, const size_t size)
|
||||
: fInitialSize(size)
|
||||
, fSize(size)
|
||||
@@ -48,6 +58,20 @@ Message::Message(boost::container::pmr::memory_resource* pmr, const size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
Message::Message(boost::container::pmr::memory_resource* pmr, const size_t size, Alignment /* alignment */)
|
||||
: fInitialSize(size)
|
||||
, fSize(size)
|
||||
, fData(nullptr)
|
||||
, fFreeFunction(nullptr)
|
||||
, fHint(nullptr)
|
||||
, fPmr(pmr)
|
||||
{
|
||||
if (size) {
|
||||
fData = fPmr->allocate(size);
|
||||
assert(fData);
|
||||
}
|
||||
}
|
||||
|
||||
Message::Message(boost::container::pmr::memory_resource* pmr,
|
||||
void* data,
|
||||
const size_t size,
|
||||
|
@@ -34,7 +34,9 @@ class Message final : public fair::mq::Message
|
||||
{
|
||||
public:
|
||||
Message(boost::container::pmr::memory_resource* pmr);
|
||||
Message(boost::container::pmr::memory_resource* pmr, Alignment alignment);
|
||||
Message(boost::container::pmr::memory_resource* pmr, const size_t size);
|
||||
Message(boost::container::pmr::memory_resource* pmr, const size_t size, Alignment alignment);
|
||||
Message(boost::container::pmr::memory_resource* pmr,
|
||||
void* data,
|
||||
const size_t size,
|
||||
|
@@ -41,11 +41,23 @@ auto TransportFactory::CreateMessage() -> MessagePtr
|
||||
return MessagePtr{new Message(&fMemoryResource)};
|
||||
}
|
||||
|
||||
auto TransportFactory::CreateMessage(Alignment /* alignment */) -> MessagePtr
|
||||
{
|
||||
// TODO Do not ignore alignment
|
||||
return MessagePtr{new Message(&fMemoryResource)};
|
||||
}
|
||||
|
||||
auto TransportFactory::CreateMessage(const size_t size) -> MessagePtr
|
||||
{
|
||||
return MessagePtr{new Message(&fMemoryResource, size)};
|
||||
}
|
||||
|
||||
auto TransportFactory::CreateMessage(const size_t size, Alignment /* alignment */) -> MessagePtr
|
||||
{
|
||||
// TODO Do not ignore alignment
|
||||
return MessagePtr{new Message(&fMemoryResource, size)};
|
||||
}
|
||||
|
||||
auto TransportFactory::CreateMessage(void* data,
|
||||
const size_t size,
|
||||
fairmq_free_fn* ffn,
|
||||
@@ -85,7 +97,22 @@ auto TransportFactory::CreatePoller(const unordered_map<string, vector<FairMQCha
|
||||
// return PollerPtr{new Poller(channelsMap, channelList)};
|
||||
}
|
||||
|
||||
auto TransportFactory::CreateUnmanagedRegion(const size_t /*size*/, FairMQRegionCallback /*callback*/, const std::string& /* path = "" */, int /* flags = 0 */) const -> UnmanagedRegionPtr
|
||||
auto TransportFactory::CreateUnmanagedRegion(const size_t /*size*/, FairMQRegionCallback /*callback*/, const std::string& /* path = "" */, int /* flags = 0 */) -> UnmanagedRegionPtr
|
||||
{
|
||||
throw runtime_error{"Not yet implemented UMR."};
|
||||
}
|
||||
|
||||
auto TransportFactory::CreateUnmanagedRegion(const size_t /*size*/, FairMQRegionBulkCallback /*callback*/, const std::string& /* path = "" */, int /* flags = 0 */) -> UnmanagedRegionPtr
|
||||
{
|
||||
throw runtime_error{"Not yet implemented UMR."};
|
||||
}
|
||||
|
||||
auto TransportFactory::CreateUnmanagedRegion(const size_t /*size*/, const int64_t /*userFlags*/, FairMQRegionCallback /*callback*/, const std::string& /* path = "" */, int /* flags = 0 */) -> UnmanagedRegionPtr
|
||||
{
|
||||
throw runtime_error{"Not yet implemented UMR."};
|
||||
}
|
||||
|
||||
auto TransportFactory::CreateUnmanagedRegion(const size_t /*size*/, const int64_t /*userFlags*/, FairMQRegionBulkCallback /*callback*/, const std::string& /* path = "" */, int /* flags = 0 */) -> UnmanagedRegionPtr
|
||||
{
|
||||
throw runtime_error{"Not yet implemented UMR."};
|
||||
}
|
||||
|
@@ -36,7 +36,9 @@ class TransportFactory final : public FairMQTransportFactory
|
||||
TransportFactory operator=(const TransportFactory&) = delete;
|
||||
|
||||
auto CreateMessage() -> MessagePtr override;
|
||||
auto CreateMessage(Alignment alignment) -> MessagePtr override;
|
||||
auto CreateMessage(const std::size_t size) -> MessagePtr override;
|
||||
auto CreateMessage(const std::size_t size, Alignment alignment) -> MessagePtr override;
|
||||
auto CreateMessage(void* data, const std::size_t size, fairmq_free_fn* ffn, void* hint = nullptr) -> MessagePtr override;
|
||||
auto CreateMessage(UnmanagedRegionPtr& region, void* data, const std::size_t size, void* hint = nullptr) -> MessagePtr override;
|
||||
|
||||
@@ -46,7 +48,15 @@ class TransportFactory final : public FairMQTransportFactory
|
||||
auto CreatePoller(const std::vector<FairMQChannel*>& channels) const -> PollerPtr override;
|
||||
auto CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const -> PollerPtr override;
|
||||
|
||||
auto CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0) const -> UnmanagedRegionPtr override;
|
||||
auto CreateUnmanagedRegion(const size_t size, RegionCallback callback = nullptr, const std::string& path = "", int flags = 0) -> UnmanagedRegionPtr override;
|
||||
auto CreateUnmanagedRegion(const size_t size, RegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0) -> UnmanagedRegionPtr override;
|
||||
auto CreateUnmanagedRegion(const size_t size, int64_t userFlags, RegionCallback callback = nullptr, const std::string& path = "", int flags = 0) -> UnmanagedRegionPtr override;
|
||||
auto CreateUnmanagedRegion(const size_t size, int64_t userFlags, RegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0) -> UnmanagedRegionPtr override;
|
||||
|
||||
void SubscribeToRegionEvents(RegionEventCallback /* callback */) override { LOG(error) << "SubscribeToRegionEvents not yet implemented for OFI"; }
|
||||
bool SubscribedToRegionEvents() override { LOG(error) << "Region event subscriptions not yet implemented for OFI"; return false; }
|
||||
void UnsubscribeFromRegionEvents() override { LOG(error) << "UnsubscribeFromRegionEvents not yet implemented for OFI"; }
|
||||
std::vector<FairMQRegionInfo> GetRegionInfo() override { LOG(error) << "GetRegionInfo not yet implemented for OFI, returning empty vector"; return std::vector<FairMQRegionInfo>(); }
|
||||
|
||||
auto GetType() const -> Transport override;
|
||||
|
||||
|
@@ -24,7 +24,7 @@ namespace
|
||||
std::atomic<sig_atomic_t> gLastSignal(0);
|
||||
std::atomic<int> gSignalCount(0);
|
||||
|
||||
extern "C" auto signal_handler(int signal) -> void
|
||||
extern "C" auto sigint_handler(int signal) -> void
|
||||
{
|
||||
++gSignalCount;
|
||||
gLastSignal = signal;
|
||||
@@ -33,6 +33,11 @@ namespace
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" auto sigterm_handler(int signal) -> void
|
||||
{
|
||||
gLastSignal = signal;
|
||||
}
|
||||
}
|
||||
|
||||
namespace fair
|
||||
@@ -85,8 +90,8 @@ Control::Control(const string& name, const Plugin::Version version, const string
|
||||
if (GetProperty<int>("catch-signals") > 0) {
|
||||
LOG(debug) << "Plugin '" << name << "' is setting up signal handling for SIGINT and SIGTERM";
|
||||
fSignalHandlerThread = thread(&Control::SignalHandler, this);
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGINT, sigint_handler);
|
||||
signal(SIGTERM, sigterm_handler);
|
||||
} else {
|
||||
LOG(warn) << "Signal handling (e.g. Ctrl-C) has been deactivated.";
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ set_target_properties(${plugin} PROPERTIES
|
||||
|
||||
set(exe fairmq-dds-command-ui)
|
||||
add_executable(${exe} ${CMAKE_CURRENT_SOURCE_DIR}/runDDSCommandUI.cxx)
|
||||
target_link_libraries(${exe} FairMQ Commands StateMachine DDS::dds_intercom_lib DDS::dds_protocol_lib)
|
||||
target_link_libraries(${exe} FairMQ Commands SDK StateMachine)
|
||||
target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
install(TARGETS ${plugin} ${exe}
|
||||
|
@@ -8,8 +8,6 @@
|
||||
|
||||
#include "DDS.h"
|
||||
|
||||
#include <fairmq/sdk/commands/Commands.h>
|
||||
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
@@ -37,20 +35,18 @@ DDS::DDS(const string& name,
|
||||
const string& homepage,
|
||||
PluginServices* pluginServices)
|
||||
: Plugin(name, version, maintainer, homepage, pluginServices)
|
||||
, fDDSTaskId(dds::env_prop<dds::task_id>())
|
||||
, fCurrentState(DeviceState::Idle)
|
||||
, fLastState(DeviceState::Idle)
|
||||
, fDeviceTerminationRequested(false)
|
||||
, fLastExternalController(0)
|
||||
, fExitingAckedByLastExternalController(false)
|
||||
, fHeartbeatInterval(100)
|
||||
, fUpdatesAllowed(false)
|
||||
, fWorkGuard(fWorkerQueue.get_executor())
|
||||
{
|
||||
try {
|
||||
TakeDeviceControl();
|
||||
|
||||
fHeartbeatThread = thread(&DDS::HeartbeatSender, this);
|
||||
|
||||
string deviceId(GetProperty<string>("id"));
|
||||
if (deviceId.empty()) {
|
||||
SetProperty<string>("id", dds::env_prop<dds::task_path>());
|
||||
@@ -76,15 +72,22 @@ DDS::DDS(const string& name,
|
||||
// subscribe to device state changes, pushing new state changes into the event queue
|
||||
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
||||
switch (newState) {
|
||||
case DeviceState::Bound:
|
||||
case DeviceState::Bound: {
|
||||
// Receive addresses of connecting channels from DDS
|
||||
// and propagate addresses of bound channels to DDS.
|
||||
FillChannelContainers();
|
||||
|
||||
// allow updates from key value after channel containers are filled
|
||||
{
|
||||
lock_guard<mutex> lk(fUpdateMutex);
|
||||
fUpdatesAllowed = true;
|
||||
}
|
||||
fUpdateCondition.notify_one();
|
||||
|
||||
// publish bound addresses via DDS at keys corresponding to the channel
|
||||
// prefixes, e.g. 'data' in data[i]
|
||||
PublishBoundChannels();
|
||||
break;
|
||||
} break;
|
||||
case DeviceState::ResettingDevice: {
|
||||
{
|
||||
lock_guard<mutex> lk(fUpdateMutex);
|
||||
@@ -92,28 +95,41 @@ DDS::DDS(const string& name,
|
||||
}
|
||||
|
||||
EmptyChannelContainers();
|
||||
break;
|
||||
}
|
||||
case DeviceState::Exiting:
|
||||
} break;
|
||||
case DeviceState::Exiting: {
|
||||
if (!fControllerThread.joinable()) {
|
||||
fControllerThread = thread(&DDS::WaitForExitingAck, this);
|
||||
}
|
||||
fWorkGuard.reset();
|
||||
fDeviceTerminationRequested = true;
|
||||
UnsubscribeFromDeviceStateChange();
|
||||
ReleaseDeviceControl();
|
||||
break;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
using namespace sdk::cmd;
|
||||
auto now = chrono::steady_clock::now();
|
||||
string id = GetProperty<string>("id");
|
||||
fLastState = fCurrentState;
|
||||
fCurrentState = newState;
|
||||
using namespace sdk::cmd;
|
||||
for (auto subscriberId : fStateChangeSubscribers) {
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << newState << " to " << subscriberId;
|
||||
|
||||
Cmds cmds(make<StateChange>(id, dds::env_prop<dds::task_id>(), fLastState, fCurrentState));
|
||||
fDDS.Send(cmds.Serialize(), to_string(subscriberId));
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
for (auto it = fStateChangeSubscribers.cbegin(); it != fStateChangeSubscribers.end();) {
|
||||
// if a subscriber did not send a heartbeat in more than 3 times the promised interval,
|
||||
// remove it from the subscriber list
|
||||
if (chrono::duration<double>(now - it->second.first).count() > 3 * it->second.second) {
|
||||
LOG(warn) << "Controller '" << it->first
|
||||
<< "' did not send heartbeats since over 3 intervals ("
|
||||
<< 3 * it->second.second << " ms), removing it.";
|
||||
fStateChangeSubscribers.erase(it++);
|
||||
} else {
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState << " to " << it->first;
|
||||
Cmds cmds(make<StateChange>(id, fDDSTaskId, fLastState, fCurrentState));
|
||||
fDDS.Send(cmds.Serialize(), to_string(it->first));
|
||||
++it;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -143,10 +159,10 @@ auto DDS::StartWorkerThread() -> void
|
||||
auto DDS::WaitForExitingAck() -> void
|
||||
{
|
||||
unique_lock<mutex> lock(fStateChangeSubscriberMutex);
|
||||
fExitingAcked.wait_for(
|
||||
lock,
|
||||
chrono::milliseconds(GetProperty<unsigned int>("wait-for-exiting-ack-timeout")),
|
||||
[this]() { return fExitingAckedByLastExternalController; });
|
||||
auto timeout = GetProperty<unsigned int>("wait-for-exiting-ack-timeout");
|
||||
fExitingAcked.wait_for(lock, chrono::milliseconds(timeout), [this]() {
|
||||
return fExitingAckedByLastExternalController || fStateChangeSubscribers.empty();
|
||||
});
|
||||
}
|
||||
|
||||
auto DDS::FillChannelContainers() -> void
|
||||
@@ -165,9 +181,7 @@ auto DDS::FillChannelContainers() -> void
|
||||
} else if (GetProperty<string>(methodKey) == "connect") {
|
||||
fConnectingChans.insert(make_pair(c.first, DDSConfig()));
|
||||
LOG(debug) << "preparing to connect: " << c.first << " with " << c.second << " sub-channels.";
|
||||
for (int i = 0; i < c.second; ++i) {
|
||||
fConnectingChans.at(c.first).fSubChannelAddresses.push_back(string());
|
||||
}
|
||||
fConnectingChans.at(c.first).fNumSubChannels = c.second;
|
||||
} else {
|
||||
LOG(error) << "Cannot update address configuration. Channel method (bind/connect) not specified.";
|
||||
return;
|
||||
@@ -214,11 +228,6 @@ auto DDS::FillChannelContainers() -> void
|
||||
LOG(debug) << "dds-i-n: adding " << chanName << " -> i: " << i << " n: " << n;
|
||||
fIofN.insert(make_pair(chanName, IofN(i, n)));
|
||||
}
|
||||
{
|
||||
lock_guard<mutex> lk(fUpdateMutex);
|
||||
fUpdatesAllowed = true;
|
||||
}
|
||||
fUpdateCondition.notify_one();
|
||||
} catch (const exception& e) {
|
||||
LOG(error) << "Error filling channel containers: " << e.what();
|
||||
}
|
||||
@@ -244,6 +253,12 @@ auto DDS::SubscribeForConnectingChannels() -> void
|
||||
unique_lock<mutex> lk(fUpdateMutex);
|
||||
fUpdateCondition.wait(lk, [&]{ return fUpdatesAllowed; });
|
||||
}
|
||||
|
||||
if (fConnectingChans.find(channelName) == fConnectingChans.end()) {
|
||||
LOG(error) << "Received an update for a connecting channel, but either no channel with given channel name exists or it has already been configured: '" << channelName << "', ignoring...";
|
||||
return;
|
||||
}
|
||||
|
||||
string val = value;
|
||||
// check if it is to handle as one out of multiple values
|
||||
auto it = fIofN.find(channelName);
|
||||
@@ -273,19 +288,16 @@ auto DDS::SubscribeForConnectingChannels() -> void
|
||||
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, val.c_str()});
|
||||
}
|
||||
|
||||
// update channels and remove them from unfinished container
|
||||
for (auto mi = fConnectingChans.begin(); mi != fConnectingChans.end(); /* no increment */) {
|
||||
if (mi->second.fSubChannelAddresses.size() == mi->second.fDDSValues.size()) {
|
||||
// when multiple subChannels are used, their order on every device should be the same, irregardless of arrival order from DDS.
|
||||
sort(mi->second.fSubChannelAddresses.begin(), mi->second.fSubChannelAddresses.end());
|
||||
auto it3 = mi->second.fDDSValues.begin();
|
||||
for (unsigned int i = 0; i < mi->second.fSubChannelAddresses.size(); ++i) {
|
||||
SetProperty<string>(string{"chans." + mi->first + "." + to_string(i) + ".address"}, it3->second);
|
||||
++it3;
|
||||
for (const auto& mi : fConnectingChans) {
|
||||
if (mi.second.fNumSubChannels == mi.second.fDDSValues.size()) {
|
||||
int i = 0;
|
||||
for (const auto& e : mi.second.fDDSValues) {
|
||||
auto result = UpdateProperty<string>(string{"chans." + mi.first + "." + to_string(i) + ".address"}, e.second);
|
||||
if (!result) {
|
||||
LOG(error) << "UpdateProperty failed for: " << "chans." << mi.first << "." << to_string(i) << ".address" << " - property does not exist";
|
||||
}
|
||||
++i;
|
||||
}
|
||||
fConnectingChans.erase(mi++);
|
||||
} else {
|
||||
++mi;
|
||||
}
|
||||
}
|
||||
} catch (const exception& e) {
|
||||
@@ -304,129 +316,133 @@ auto DDS::PublishBoundChannels() -> void
|
||||
}
|
||||
}
|
||||
|
||||
auto DDS::HeartbeatSender() -> void
|
||||
{
|
||||
using namespace sdk::cmd;
|
||||
string id = GetProperty<string>("id");
|
||||
|
||||
while (!fDeviceTerminationRequested) {
|
||||
{
|
||||
lock_guard<mutex> lock{fHeartbeatSubscriberMutex};
|
||||
|
||||
for (const auto subscriberId : fHeartbeatSubscribers) {
|
||||
fDDS.Send(Cmds(make<Heartbeat>(id)).Serialize(), to_string(subscriberId));
|
||||
}
|
||||
}
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(fHeartbeatInterval));
|
||||
}
|
||||
}
|
||||
|
||||
auto DDS::SubscribeForCustomCommands() -> void
|
||||
{
|
||||
using namespace sdk::cmd;
|
||||
LOG(debug) << "Subscribing for DDS custom commands.";
|
||||
|
||||
string id = GetProperty<string>("id");
|
||||
|
||||
fDDS.SubscribeCustomCmd([id, this](const string& cmdStr, const string& cond, uint64_t senderId) {
|
||||
// LOG(info) << "Received command: '" << cmdStr << "' from " << senderId;
|
||||
|
||||
Cmds inCmds;
|
||||
sdk::cmd::Cmds inCmds;
|
||||
inCmds.Deserialize(cmdStr);
|
||||
|
||||
for (const auto& cmd : inCmds) {
|
||||
// LOG(info) << "Received command type: '" << cmd->GetType() << "' from " << senderId;
|
||||
switch (cmd->GetType()) {
|
||||
case Type::check_state: {
|
||||
fDDS.Send(Cmds(make<CurrentState>(id, GetCurrentDeviceState())).Serialize(), to_string(senderId));
|
||||
}
|
||||
break;
|
||||
case Type::change_state: {
|
||||
Transition transition = static_cast<ChangeState&>(*cmd).GetTransition();
|
||||
if (ChangeDeviceState(transition)) {
|
||||
Cmds outCmds(make<TransitionStatus>(id, Result::Ok, transition));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} else {
|
||||
Cmds outCmds(make<TransitionStatus>(id, Result::Failure, transition));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fLastExternalController = senderId;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type::dump_config: {
|
||||
stringstream ss;
|
||||
for (const auto pKey: GetPropertyKeys()) {
|
||||
ss << id << ": " << pKey << " -> " << GetPropertyAsString(pKey) << "\n";
|
||||
}
|
||||
Cmds outCmds(make<Config>(id, ss.str()));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
break;
|
||||
case Type::subscribe_to_heartbeats: {
|
||||
{
|
||||
lock_guard<mutex> lock{fHeartbeatSubscriberMutex};
|
||||
fHeartbeatSubscribers.insert(senderId);
|
||||
}
|
||||
Cmds outCmds(make<HeartbeatSubscription>(id, Result::Ok));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
break;
|
||||
case Type::unsubscribe_from_heartbeats: {
|
||||
{
|
||||
lock_guard<mutex> lock{fHeartbeatSubscriberMutex};
|
||||
fHeartbeatSubscribers.erase(senderId);
|
||||
}
|
||||
Cmds outCmds(make<HeartbeatUnsubscription>(id, Result::Ok));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
break;
|
||||
case Type::state_change_exiting_received: {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
if (fLastExternalController == senderId) {
|
||||
fExitingAckedByLastExternalController = true;
|
||||
}
|
||||
}
|
||||
fExitingAcked.notify_one();
|
||||
}
|
||||
break;
|
||||
case Type::subscribe_to_state_change: {
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.insert(senderId);
|
||||
if (!fControllerThread.joinable()) {
|
||||
fControllerThread = thread(&DDS::WaitForExitingAck, this);
|
||||
}
|
||||
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState << " to " << senderId;
|
||||
|
||||
Cmds outCmds(make<StateChangeSubscription>(id, Result::Ok), make<StateChange>(id, dds::env_prop<dds::task_id>(), fLastState, fCurrentState));
|
||||
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
break;
|
||||
case Type::unsubscribe_from_state_change: {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.erase(senderId);
|
||||
}
|
||||
Cmds outCmds(make<StateChangeUnsubscription>(id, Result::Ok));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG(warn) << "Unexpected/unknown command received: " << cmdStr;
|
||||
LOG(warn) << "Origin: " << senderId;
|
||||
LOG(warn) << "Destination: " << cond;
|
||||
break;
|
||||
}
|
||||
HandleCmd(id, *cmd, cond, senderId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto DDS::HandleCmd(const string& id, sdk::cmd::Cmd& cmd, const string& cond, uint64_t senderId) -> void
|
||||
{
|
||||
using namespace fair::mq::sdk;
|
||||
using namespace fair::mq::sdk::cmd;
|
||||
// LOG(info) << "Received command type: '" << cmd.GetType() << "' from " << senderId;
|
||||
switch (cmd.GetType()) {
|
||||
case Type::check_state: {
|
||||
fDDS.Send(Cmds(make<CurrentState>(id, GetCurrentDeviceState())).Serialize(), to_string(senderId));
|
||||
} break;
|
||||
case Type::change_state: {
|
||||
Transition transition = static_cast<ChangeState&>(cmd).GetTransition();
|
||||
if (ChangeDeviceState(transition)) {
|
||||
Cmds outCmds(make<TransitionStatus>(id, fDDSTaskId, Result::Ok, transition));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} else {
|
||||
Cmds outCmds(make<TransitionStatus>(id, fDDSTaskId, Result::Failure, transition));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fLastExternalController = senderId;
|
||||
}
|
||||
} break;
|
||||
case Type::dump_config: {
|
||||
stringstream ss;
|
||||
for (const auto pKey : GetPropertyKeys()) {
|
||||
ss << id << ": " << pKey << " -> " << GetPropertyAsString(pKey) << "\n";
|
||||
}
|
||||
Cmds outCmds(make<Config>(id, ss.str()));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} break;
|
||||
case Type::state_change_exiting_received: {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
if (fLastExternalController == senderId) {
|
||||
fExitingAckedByLastExternalController = true;
|
||||
}
|
||||
}
|
||||
fExitingAcked.notify_one();
|
||||
} break;
|
||||
case Type::subscribe_to_state_change: {
|
||||
auto _cmd = static_cast<cmd::SubscribeToStateChange&>(cmd);
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.emplace(senderId, make_pair(chrono::steady_clock::now(), _cmd.GetInterval()));
|
||||
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState << " to " << senderId;
|
||||
|
||||
Cmds outCmds(make<StateChangeSubscription>(id, fDDSTaskId, Result::Ok),
|
||||
make<StateChange>(id, fDDSTaskId, fLastState, fCurrentState));
|
||||
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} break;
|
||||
case Type::subscription_heartbeat: {
|
||||
try {
|
||||
auto _cmd = static_cast<cmd::SubscriptionHeartbeat&>(cmd);
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.at(senderId) = make_pair(chrono::steady_clock::now(), _cmd.GetInterval());
|
||||
} catch(out_of_range& oor) {
|
||||
LOG(warn) << "Received subscription heartbeat from an unknown controller with id '" << senderId << "'";
|
||||
}
|
||||
} break;
|
||||
case Type::unsubscribe_from_state_change: {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.erase(senderId);
|
||||
}
|
||||
Cmds outCmds(make<StateChangeUnsubscription>(id, fDDSTaskId, Result::Ok));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} break;
|
||||
case Type::get_properties: {
|
||||
auto _cmd = static_cast<cmd::GetProperties&>(cmd);
|
||||
auto const request_id(_cmd.GetRequestId());
|
||||
auto result(Result::Ok);
|
||||
vector<pair<string, string>> props;
|
||||
try {
|
||||
for (auto const& prop : GetPropertiesAsString(_cmd.GetQuery())) {
|
||||
props.push_back({prop.first, prop.second});
|
||||
}
|
||||
} catch (exception const& e) {
|
||||
LOG(warn) << "Getting properties (request id: " << request_id << ") failed: " << e.what();
|
||||
result = Result::Failure;
|
||||
}
|
||||
Cmds const outCmds(make<cmd::Properties>(id, request_id, result, props));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} break;
|
||||
case Type::set_properties: {
|
||||
auto _cmd(static_cast<cmd::SetProperties&>(cmd));
|
||||
auto const request_id(_cmd.GetRequestId());
|
||||
auto result(Result::Ok);
|
||||
try {
|
||||
fair::mq::Properties props;
|
||||
for (auto const& prop : _cmd.GetProps()) {
|
||||
props.insert({prop.first, fair::mq::Property(prop.second)});
|
||||
}
|
||||
// TODO Handle builtin keys with different value type than string
|
||||
SetProperties(props);
|
||||
} catch (exception const& e) {
|
||||
LOG(warn) << "Setting properties (request id: " << request_id << ") failed: " << e.what();
|
||||
result = Result::Failure;
|
||||
}
|
||||
Cmds const outCmds(make<PropertiesSet>(id, request_id, result));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} break;
|
||||
default:
|
||||
LOG(warn) << "Unexpected/unknown command received: " << cmd.GetType();
|
||||
LOG(warn) << "Origin: " << senderId;
|
||||
LOG(warn) << "Destination: " << cond;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DDS::~DDS()
|
||||
{
|
||||
UnsubscribeFromDeviceStateChange();
|
||||
@@ -436,10 +452,6 @@ DDS::~DDS()
|
||||
fControllerThread.join();
|
||||
}
|
||||
|
||||
if (fHeartbeatThread.joinable()) {
|
||||
fHeartbeatThread.join();
|
||||
}
|
||||
|
||||
fWorkGuard.reset();
|
||||
if (fWorkerThread.joinable()) {
|
||||
fWorkerThread.join();
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <fairmq/Plugin.h>
|
||||
#include <fairmq/StateQueue.h>
|
||||
#include <fairmq/Version.h>
|
||||
#include <fairmq/sdk/commands/Commands.h>
|
||||
|
||||
#include <dds/dds.h>
|
||||
|
||||
@@ -23,11 +24,12 @@
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <utility> // pair
|
||||
#include <vector>
|
||||
|
||||
namespace fair
|
||||
@@ -40,16 +42,16 @@ namespace plugins
|
||||
struct DDSConfig
|
||||
{
|
||||
// container of sub channel addresses
|
||||
std::vector<std::string> fSubChannelAddresses;
|
||||
unsigned int fNumSubChannels;
|
||||
// dds values for the channel
|
||||
std::unordered_map<uint64_t, std::string> fDDSValues;
|
||||
std::map<uint64_t, std::string> fDDSValues;
|
||||
};
|
||||
|
||||
struct DDSSubscription
|
||||
{
|
||||
DDSSubscription()
|
||||
: fDDSCustomCmd(fService)
|
||||
, fDDSKeyValue(fService)
|
||||
: fDDSCustomCmd(fService)
|
||||
, fDDSKeyValue(fService)
|
||||
{
|
||||
LOG(debug) << "$DDS_TASK_PATH: " << dds::env_prop<dds::task_path>();
|
||||
LOG(debug) << "$DDS_GROUP_NAME: " << dds::env_prop<dds::group_name>();
|
||||
@@ -141,10 +143,10 @@ class DDS : public Plugin
|
||||
auto SubscribeForConnectingChannels() -> void;
|
||||
auto PublishBoundChannels() -> void;
|
||||
auto SubscribeForCustomCommands() -> void;
|
||||
|
||||
auto HeartbeatSender() -> void;
|
||||
auto HandleCmd(const std::string& id, sdk::cmd::Cmd& cmd, const std::string& cond, uint64_t senderId) -> void;
|
||||
|
||||
DDSSubscription fDDS;
|
||||
size_t fDDSTaskId;
|
||||
|
||||
std::unordered_map<std::string, std::vector<std::string>> fBindingChans;
|
||||
std::unordered_map<std::string, DDSConfig> fConnectingChans;
|
||||
@@ -157,18 +159,12 @@ class DDS : public Plugin
|
||||
|
||||
std::atomic<bool> fDeviceTerminationRequested;
|
||||
|
||||
std::set<uint64_t> fHeartbeatSubscribers;
|
||||
std::mutex fHeartbeatSubscriberMutex;
|
||||
|
||||
std::set<uint64_t> fStateChangeSubscribers;
|
||||
std::unordered_map<uint64_t, std::pair<std::chrono::steady_clock::time_point, int64_t>> fStateChangeSubscribers;
|
||||
uint64_t fLastExternalController;
|
||||
bool fExitingAckedByLastExternalController;
|
||||
std::condition_variable fExitingAcked;
|
||||
std::mutex fStateChangeSubscriberMutex;
|
||||
|
||||
std::thread fHeartbeatThread;
|
||||
std::chrono::milliseconds fHeartbeatInterval;
|
||||
|
||||
bool fUpdatesAllowed;
|
||||
std::mutex fUpdateMutex;
|
||||
std::condition_variable fUpdateCondition;
|
||||
|
@@ -8,23 +8,23 @@
|
||||
|
||||
#include <fairmq/sdk/commands/Commands.h>
|
||||
#include <fairmq/States.h>
|
||||
|
||||
#include <dds/dds.h>
|
||||
#include <fairmq/SDK.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <termios.h> // raw mode console input
|
||||
#include <unistd.h>
|
||||
#include <condition_variable>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <termios.h> // raw mode console input
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dds::intercom_api;
|
||||
using namespace fair::mq;
|
||||
using namespace fair::mq::sdk;
|
||||
using namespace fair::mq::sdk::cmd;
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
@@ -49,279 +49,176 @@ struct TerminalConfig
|
||||
}
|
||||
};
|
||||
|
||||
struct StateSubscription
|
||||
{
|
||||
const string& fTopologyPath;
|
||||
CCustomCmd& fDdsCustomCmd;
|
||||
|
||||
explicit StateSubscription(const string& topologyPath, CCustomCmd& ddsCustomCmd)
|
||||
: fTopologyPath(topologyPath)
|
||||
, fDdsCustomCmd(ddsCustomCmd)
|
||||
{
|
||||
fDdsCustomCmd.send(Cmds(make<SubscribeToStateChange>()).Serialize(), fTopologyPath);
|
||||
}
|
||||
|
||||
~StateSubscription() {
|
||||
fDdsCustomCmd.send(Cmds(make<UnsubscribeFromStateChange>()).Serialize(), fTopologyPath);
|
||||
this_thread::sleep_for(chrono::milliseconds(100)); // give dds a chance to complete request
|
||||
}
|
||||
};
|
||||
|
||||
void printControlsHelp()
|
||||
{
|
||||
cout << "Use keys to control the devices:" << endl;
|
||||
cout << "[c] check states, [o] dump config, [h] help, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device, [k] complete init, [b] bind, [x] connect" << endl;
|
||||
cout << "[c] check states, [o] dump config, [h] help, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device, [k] complete init, [b] bind, [x] connect, [p] set property" << endl;
|
||||
cout << "To quit press Ctrl+C" << endl;
|
||||
}
|
||||
|
||||
void sendCommand(const string& commandIn, const string& topologyPath, CCustomCmd& ddsCustomCmd)
|
||||
void handleCommand(const string& command, const string& path, unsigned int timeout, Topology& topo, const string& pKey, const string& pVal)
|
||||
{
|
||||
if (command == "c") {
|
||||
cout << "> checking state of the devices" << endl;
|
||||
auto const result = topo.GetCurrentState();
|
||||
for (const auto& d : result) {
|
||||
cout << d.taskId << " : " << d.state << endl;
|
||||
}
|
||||
} else if (command == "o") {
|
||||
cout << "> dumping config of the devices (" << path << ")" << endl;
|
||||
// TODO: extend this regex to return all properties, once command size limitation is removed.
|
||||
auto const result = topo.GetProperties("^(session|id)$", path, std::chrono::milliseconds(timeout));
|
||||
for (const auto& d : result.second.devices) {
|
||||
for (auto const& p : d.second.props) {
|
||||
cout << d.first << ": " << p.first << " : " << p.second << endl;
|
||||
}
|
||||
}
|
||||
} else if (command == "p") {
|
||||
if (pKey == "" || pVal == "") {
|
||||
cout << "cannot send property with empty key and/or value! given key: '" << pKey << "', value: '" << pVal << "'." << endl;
|
||||
return;
|
||||
}
|
||||
const DeviceProperties props{{pKey, pVal}};
|
||||
cout << "> sending property (" << path << ")" << endl;
|
||||
topo.SetProperties(props, path);
|
||||
// give dds time to complete request
|
||||
this_thread::sleep_for(chrono::milliseconds(100));
|
||||
} else if (command == "i") {
|
||||
cout << "> init devices (" << path << ")" << endl;
|
||||
topo.ChangeState(TopologyTransition::InitDevice, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "k") {
|
||||
cout << "> complete init (" << path << ")" << endl;
|
||||
topo.ChangeState(TopologyTransition::CompleteInit, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "b") {
|
||||
cout << "> bind devices (" << path << ")" << endl;
|
||||
topo.ChangeState(TopologyTransition::Bind, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "x") {
|
||||
cout << "> connect devices (" << path << ")" << endl;
|
||||
topo.ChangeState(TopologyTransition::Connect, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "j") {
|
||||
cout << "> init tasks (" << path << ")" << endl;
|
||||
topo.ChangeState(TopologyTransition::InitTask, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "r") {
|
||||
cout << "> run tasks (" << path << ")" << endl;
|
||||
topo.ChangeState(TopologyTransition::Run, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "s") {
|
||||
cout << "> stop devices (" << path << ")" << endl;
|
||||
topo.ChangeState(TopologyTransition::Stop, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "t") {
|
||||
cout << "> reset tasks (" << path << ")" << endl;
|
||||
topo.ChangeState(TopologyTransition::ResetTask, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "d") {
|
||||
cout << "> reset devices (" << path << ")" << endl;
|
||||
topo.ChangeState(TopologyTransition::ResetDevice, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "q") {
|
||||
cout << "> end (" << path << ")" << endl;
|
||||
topo.ChangeState(TopologyTransition::End, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "h") {
|
||||
cout << "> help" << endl;
|
||||
printControlsHelp();
|
||||
} else {
|
||||
cout << "\033[01;32mInvalid input: [" << command << "]\033[0m" << endl;
|
||||
printControlsHelp();
|
||||
}
|
||||
}
|
||||
|
||||
void sendCommand(const string& commandIn, const string& path, unsigned int timeout, Topology& topo, const string& pKey, const string& pVal)
|
||||
{
|
||||
if (commandIn != "") {
|
||||
handleCommand(commandIn, path, timeout, topo, pKey, pVal);
|
||||
return;
|
||||
}
|
||||
|
||||
char c;
|
||||
string command(commandIn);
|
||||
string command;
|
||||
TerminalConfig tconfig;
|
||||
|
||||
if (command == "") {
|
||||
printControlsHelp();
|
||||
printControlsHelp();
|
||||
cin >> c;
|
||||
command = c;
|
||||
|
||||
while (true) {
|
||||
handleCommand(command, path, timeout, topo, pKey, pVal);
|
||||
cin >> c;
|
||||
command = c;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (command == "c") {
|
||||
cout << "> checking state of the devices" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<CheckState>()).Serialize(), topologyPath);
|
||||
} else if (command == "o") {
|
||||
cout << "> dumping config of the devices" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<DumpConfig>()).Serialize(), topologyPath);
|
||||
} else if (command == "i") {
|
||||
cout << "> init devices" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::InitDevice)).Serialize(), topologyPath);
|
||||
} else if (command == "k") {
|
||||
cout << "> complete init" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::CompleteInit)).Serialize(), topologyPath);
|
||||
} else if (command == "b") {
|
||||
cout << "> bind devices" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Bind)).Serialize(), topologyPath);
|
||||
} else if (command == "x") {
|
||||
cout << "> connect devices" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Connect)).Serialize(), topologyPath);
|
||||
} else if (command == "j") {
|
||||
cout << "> init tasks" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::InitTask)).Serialize(), topologyPath);
|
||||
} else if (command == "r") {
|
||||
cout << "> run tasks" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Run)).Serialize(), topologyPath);
|
||||
} else if (command == "s") {
|
||||
cout << "> stop devices" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Stop)).Serialize(), topologyPath);
|
||||
} else if (command == "t") {
|
||||
cout << "> reset tasks" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::ResetTask)).Serialize(), topologyPath);
|
||||
} else if (command == "d") {
|
||||
cout << "> reset devices" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::ResetDevice)).Serialize(), topologyPath);
|
||||
} else if (command == "h") {
|
||||
cout << "> help" << endl;
|
||||
printControlsHelp();
|
||||
} else if (command == "q") {
|
||||
cout << "> end" << endl;
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::End)).Serialize(), topologyPath);
|
||||
} else {
|
||||
cout << "\033[01;32mInvalid input: [" << c << "]\033[0m" << endl;
|
||||
printControlsHelp();
|
||||
}
|
||||
|
||||
if (commandIn != "") {
|
||||
this_thread::sleep_for(chrono::milliseconds(100)); // give dds a chance to complete request
|
||||
break;
|
||||
} else {
|
||||
cin >> c;
|
||||
command = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WaitMode
|
||||
{
|
||||
explicit WaitMode(const string& targetState)
|
||||
: fTransitionedCount(0)
|
||||
{
|
||||
if (targetState != "") {
|
||||
size_t n = targetState.find("->");
|
||||
if (n == string::npos) {
|
||||
fTargetStatePair.first = fair::mq::State::Ok;
|
||||
fTargetStatePair.second = fair::mq::GetState(targetState);
|
||||
} else {
|
||||
fTargetStatePair.first = fair::mq::GetState(targetState.substr(0, n));
|
||||
fTargetStatePair.second = fair::mq::GetState(targetState.substr(n + 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Run(const chrono::milliseconds& timeout, const string& topologyPath, CCustomCmd& ddsCustomCmd, unsigned int numDevices, const string& command = "")
|
||||
{
|
||||
if (command != "") {
|
||||
sendCommand(command, topologyPath, ddsCustomCmd);
|
||||
}
|
||||
|
||||
// TODO once DDS provides an API to retrieve actual number of tasks, use it here
|
||||
auto condition = [&] {
|
||||
bool res = fTransitionedCount == numDevices;
|
||||
if (fTargetStatePair.first == fair::mq::State::Ok) {
|
||||
cout << "Waiting for " << numDevices << " devices to reach " << fTargetStatePair.second << ", condition check: " << res << endl;
|
||||
} else {
|
||||
cout << "Waiting for " << numDevices << " devices to reach " << fTargetStatePair.first << "->" << fTargetStatePair.second << ", condition check: " << res << endl;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
unique_lock<mutex> lock(fMtx);
|
||||
|
||||
if (timeout > chrono::milliseconds(0)) {
|
||||
if (!fCV.wait_for(lock, timeout, condition)) {
|
||||
throw runtime_error("timeout");
|
||||
}
|
||||
} else {
|
||||
fCV.wait(lock, condition);
|
||||
}
|
||||
|
||||
// cout << "WaitMode.Run() finished" << endl;
|
||||
}
|
||||
|
||||
void CountStates(fair::mq::State lastState, fair::mq::State currentState)
|
||||
{
|
||||
{
|
||||
unique_lock<mutex> lock(fMtx);
|
||||
if (fTargetStatePair.first == fair::mq::State::Ok) {
|
||||
if (fTargetStatePair.second == currentState) {
|
||||
fTransitionedCount++;
|
||||
// cout << "fTransitionedCount = " << fTransitionedCount << " for single value" << endl;
|
||||
}
|
||||
} else {
|
||||
if (fTargetStatePair.first == lastState && fTargetStatePair.second == currentState) {
|
||||
fTransitionedCount++;
|
||||
// cout << "fTransitionedCount = " << fTransitionedCount << " for double value" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
fCV.notify_one();
|
||||
}
|
||||
|
||||
mutex fMtx;
|
||||
condition_variable fCV;
|
||||
pair<fair::mq::State, fair::mq::State> fTargetStatePair;
|
||||
unsigned int fTransitionedCount;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
try {
|
||||
string sessionID;
|
||||
string command;
|
||||
string topologyPath;
|
||||
string targetState;
|
||||
unsigned int timeout;
|
||||
unsigned int numDevices(0);
|
||||
try {
|
||||
string sessionID;
|
||||
string topoFile;
|
||||
|
||||
bpo::options_description options("Common options");
|
||||
string command;
|
||||
string path;
|
||||
string targetState;
|
||||
string pKey;
|
||||
string pVal;
|
||||
unsigned int timeout;
|
||||
|
||||
auto envSessionId = getenv("DDS_SESSION_ID");
|
||||
if (envSessionId) {
|
||||
options.add_options()("session,s", bpo::value<string>(&sessionID)->default_value(envSessionId), "DDS Session ID (overrides any value in env var $DDS_SESSION_ID)");
|
||||
} else {
|
||||
options.add_options()("session,s", bpo::value<string>(&sessionID)->required(), "DDS Session ID (overrides any value in env var $DDS_SESSION_ID)");
|
||||
}
|
||||
fair::Logger::SetConsoleSeverity("debug");
|
||||
fair::Logger::SetConsoleColor(true);
|
||||
|
||||
options.add_options()
|
||||
("command,c", bpo::value<string> (&command)->default_value(""), "Command character")
|
||||
("path,p", bpo::value<string> (&topologyPath)->default_value(""), "DDS Topology path to send command to (empty - send to all tasks)")
|
||||
("wait-for-state,w", bpo::value<string> (&targetState)->default_value(""), "Wait until targeted FairMQ devices reach the given state")
|
||||
("timeout,t", bpo::value<unsigned int> (&timeout)->default_value(0), "Timeout in milliseconds when waiting for a device state (0 - wait infinitely)")
|
||||
("number-devices,n", bpo::value<unsigned int> (&numDevices)->default_value(0), "Number of devices (will be removed in the future)")
|
||||
("help,h", "Produce help message");
|
||||
bpo::options_description options("Common options");
|
||||
|
||||
bpo::variables_map vm;
|
||||
bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
|
||||
|
||||
if (vm.count("help")) {
|
||||
cout << "FairMQ DDS Command UI" << endl << options << endl;
|
||||
cout << "Commands: [c] check state, [o] dump config, [h] help, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device, [k] complete init, [b] bind, [x] connect" << endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
bpo::notify(vm);
|
||||
|
||||
WaitMode waitMode(targetState);
|
||||
|
||||
CIntercomService service;
|
||||
CCustomCmd ddsCustomCmd(service);
|
||||
|
||||
service.subscribeOnError([](const EErrorCode errorCode, const string& errorMsg) {
|
||||
cerr << "DDS error received: error code: " << errorCode << ", error message: " << errorMsg << endl;
|
||||
});
|
||||
|
||||
// subscribe to receive messages from DDS
|
||||
ddsCustomCmd.subscribe([&](const string& msg, const string& /*condition*/, uint64_t senderId) {
|
||||
Cmds cmds;
|
||||
cmds.Deserialize(msg);
|
||||
// cout << "Received " << cmds.Size() << " command(s) with total size of " << msg.length() << " bytes: " << endl;
|
||||
for (const auto& cmd : cmds) {
|
||||
// cout << " > " << cmd->GetType() << endl;
|
||||
switch (cmd->GetType()) {
|
||||
case Type::state_change: {
|
||||
cout << "Received state_change from " << static_cast<StateChange&>(*cmd).GetDeviceId() << ": " << static_cast<StateChange&>(*cmd).GetLastState() << "->" << static_cast<StateChange&>(*cmd).GetCurrentState() << endl;
|
||||
if (static_cast<StateChange&>(*cmd).GetCurrentState() == fair::mq::State::Exiting) {
|
||||
ddsCustomCmd.send(Cmds(make<StateChangeExitingReceived>()).Serialize(), to_string(senderId));
|
||||
}
|
||||
waitMode.CountStates(static_cast<StateChange&>(*cmd).GetLastState(), static_cast<StateChange&>(*cmd).GetCurrentState());
|
||||
}
|
||||
break;
|
||||
case Type::state_change_subscription:
|
||||
if (static_cast<StateChangeSubscription&>(*cmd).GetResult() != Result::Ok) {
|
||||
cout << "State change subscription failed for " << static_cast<StateChangeSubscription&>(*cmd).GetDeviceId() << endl;
|
||||
}
|
||||
break;
|
||||
case Type::state_change_unsubscription:
|
||||
if (static_cast<StateChangeUnsubscription&>(*cmd).GetResult() != Result::Ok) {
|
||||
cout << "State change unsubscription failed for " << static_cast<StateChangeUnsubscription&>(*cmd).GetDeviceId() << endl;
|
||||
}
|
||||
break;
|
||||
case Type::transition_status: {
|
||||
if (static_cast<TransitionStatus&>(*cmd).GetResult() == Result::Ok) {
|
||||
cout << "Device " << static_cast<TransitionStatus&>(*cmd).GetDeviceId() << " started to transition with " << static_cast<TransitionStatus&>(*cmd).GetTransition() << endl;
|
||||
} else {
|
||||
cout << "Device " << static_cast<TransitionStatus&>(*cmd).GetDeviceId() << " cannot transition with " << static_cast<TransitionStatus&>(*cmd).GetTransition() << endl;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type::current_state:
|
||||
cout << "Device " << static_cast<CurrentState&>(*cmd).GetDeviceId() << " is in " << static_cast<CurrentState&>(*cmd).GetCurrentState() << " state" << endl;
|
||||
break;
|
||||
case Type::config:
|
||||
cout << "Received config for device " << static_cast<Config&>(*cmd).GetDeviceId() << ":\n" << static_cast<Config&>(*cmd).GetConfig() << endl;
|
||||
break;
|
||||
default:
|
||||
cout << "Unexpected/unknown command received: " << cmd->GetType() << endl;
|
||||
cout << "Origin: " << senderId << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
service.start(sessionID);
|
||||
|
||||
StateSubscription stateSubscription(topologyPath, ddsCustomCmd);
|
||||
|
||||
if (targetState == "") {
|
||||
sendCommand(command, topologyPath, ddsCustomCmd);
|
||||
} else {
|
||||
waitMode.Run(chrono::milliseconds(timeout), topologyPath, ddsCustomCmd, numDevices, command);
|
||||
}
|
||||
|
||||
ddsCustomCmd.unsubscribe();
|
||||
} catch (exception& e) {
|
||||
cerr << "Error: " << e.what() << endl;
|
||||
return EXIT_FAILURE;
|
||||
auto envSessionId = getenv("DDS_SESSION_ID");
|
||||
if (envSessionId) {
|
||||
options.add_options()("session,s", bpo::value<string>(&sessionID)->default_value(envSessionId), "DDS Session ID (overrides any value in env var $DDS_SESSION_ID)");
|
||||
} else {
|
||||
options.add_options()("session,s", bpo::value<string>(&sessionID)->required(), "DDS Session ID (overrides any value in env var $DDS_SESSION_ID)");
|
||||
}
|
||||
|
||||
auto envTopoFile = getenv("FAIRMQ_DDS_TOPO_FILE");
|
||||
if (envTopoFile) {
|
||||
options.add_options()("topology-file,f", bpo::value<string>(&topoFile)->default_value(envTopoFile), "DDS topology file path");
|
||||
} else {
|
||||
options.add_options()("topology-file,f", bpo::value<string>(&topoFile)->required(), "DDS topology file path");
|
||||
}
|
||||
|
||||
options.add_options()
|
||||
("command,c", bpo::value<string>(&command)->default_value(""), "Command character")
|
||||
("path,p", bpo::value<string>(&path)->default_value(""), "DDS Topology path to send command to (empty - send to all tasks)")
|
||||
("property-key", bpo::value<string>(&pKey)->default_value(""), "property key to be used with 'p' command")
|
||||
("property-value", bpo::value<string>(&pVal)->default_value(""), "property value to be used with 'p' command")
|
||||
("wait-for-state,w", bpo::value<string>(&targetState)->default_value(""), "Wait until targeted FairMQ devices reach the given state")
|
||||
("timeout,t", bpo::value<unsigned int>(&timeout)->default_value(0), "Timeout in milliseconds when waiting for a device state (0 - wait infinitely)")
|
||||
("help,h", "Produce help message");
|
||||
|
||||
bpo::variables_map vm;
|
||||
bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
|
||||
|
||||
if (vm.count("help")) {
|
||||
cout << "FairMQ DDS Command UI" << endl << options << endl;
|
||||
cout << "Commands: [c] check state, [o] dump config, [h] help, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device, [k] complete init, [b] bind, [x] connect, [p] set property" << endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
bpo::notify(vm);
|
||||
|
||||
DDSEnvironment env;
|
||||
DDSSession session(sessionID, env);
|
||||
DDSTopology ddsTopo(DDSTopology::Path(topoFile), env);
|
||||
|
||||
Topology topo(ddsTopo, session);
|
||||
|
||||
if (targetState != "") {
|
||||
if (command != "") {
|
||||
sendCommand(command, path, timeout, topo, pKey, pVal);
|
||||
}
|
||||
size_t pos = targetState.find("->");
|
||||
if (pos == string::npos) {
|
||||
/* auto ec = */topo.WaitForState(GetState(targetState), path, std::chrono::milliseconds(timeout));
|
||||
// cout << "WaitForState(" << targetState << ") result: " << ec.message() << endl;
|
||||
} else {
|
||||
/* auto ec = */topo.WaitForState(GetState(targetState.substr(0, pos)), GetState(targetState.substr(pos + 2)), path, std::chrono::milliseconds(timeout));
|
||||
// cout << "WaitForState(" << targetState << ") result: " << ec.message() << endl;
|
||||
}
|
||||
} else {
|
||||
sendCommand(command, path, timeout, topo, pKey, pVal);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
} catch (exception& e) {
|
||||
cerr << "Error: " << e.what() << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@@ -148,12 +148,12 @@ auto PMIxPlugin::SubscribeForCommands() -> void
|
||||
Transition transition = static_cast<ChangeState&>(*cmd).GetTransition();
|
||||
if (ChangeDeviceState(transition)) {
|
||||
fCommands.Send(
|
||||
Cmds(make<TransitionStatus>(fDeviceId, Result::Ok, transition))
|
||||
Cmds(make<TransitionStatus>(fDeviceId, 0, Result::Ok, transition))
|
||||
.Serialize(Format::JSON),
|
||||
{sender});
|
||||
} else {
|
||||
fCommands.Send(
|
||||
Cmds(make<TransitionStatus>(fDeviceId, Result::Failure, transition))
|
||||
Cmds(make<TransitionStatus>(fDeviceId, 0, Result::Failure, transition))
|
||||
.Serialize(Format::JSON),
|
||||
{sender});
|
||||
}
|
||||
@@ -171,7 +171,7 @@ auto PMIxPlugin::SubscribeForCommands() -> void
|
||||
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState
|
||||
<< " to " << sender;
|
||||
Cmds outCmds(make<StateChangeSubscription>(fDeviceId, Result::Ok),
|
||||
Cmds outCmds(make<StateChangeSubscription>(fDeviceId, fProcess.rank, Result::Ok),
|
||||
make<StateChange>(fDeviceId, 0, fLastState, fCurrentState));
|
||||
fCommands.Send(outCmds.Serialize(Format::JSON), {sender});
|
||||
}
|
||||
@@ -181,7 +181,7 @@ auto PMIxPlugin::SubscribeForCommands() -> void
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.erase(sender.rank);
|
||||
}
|
||||
fCommands.Send(Cmds(make<StateChangeUnsubscription>(fDeviceId, Result::Ok))
|
||||
fCommands.Send(Cmds(make<StateChangeUnsubscription>(fDeviceId, fProcess.rank, Result::Ok))
|
||||
.Serialize(Format::JSON),
|
||||
{sender});
|
||||
}
|
||||
|
@@ -53,7 +53,7 @@ struct StateSubscription
|
||||
explicit StateSubscription(pmix::Commands& commands)
|
||||
: fCommands(commands)
|
||||
{
|
||||
fCommands.Send(Cmds(make<SubscribeToStateChange>()).Serialize(Format::JSON));
|
||||
fCommands.Send(Cmds(make<SubscribeToStateChange>(600000)).Serialize(Format::JSON));
|
||||
}
|
||||
|
||||
~StateSubscription()
|
||||
|
@@ -61,21 +61,22 @@ Plugin::ProgOptions ConfigPluginProgramOptions()
|
||||
namespace po = boost::program_options;
|
||||
auto pluginOptions = po::options_description{"FairMQ device options"};
|
||||
pluginOptions.add_options()
|
||||
("id", po::value<string >()->default_value(""), "Device ID.")
|
||||
("io-threads", po::value<int >()->default_value(1), "Number of I/O threads.")
|
||||
("transport", po::value<string >()->default_value("zeromq"), "Transport ('zeromq'/'nanomsg'/'shmem').")
|
||||
("network-interface", po::value<string >()->default_value("default"), "Network interface to bind on (e.g. eth0, ib0..., default will try to detect the interface of the default route).")
|
||||
("init-timeout", po::value<int >()->default_value(120), "Timeout for the initialization in seconds (when expecting dynamic initialization).")
|
||||
("max-run-time", po::value<uint64_t >()->default_value(0), "Maximum runtime for the Running state handler, after which state will change to Ready (in seconds, 0 for no limit).")
|
||||
("print-channels", po::value<bool >()->implicit_value(true), "Print registered channel endpoints in a machine-readable format (<channel name>:<min num subchannels>:<max num subchannels>)")
|
||||
("shm-segment-size", po::value<size_t >()->default_value(2000000000), "Shared memory: size of the shared memory segment (in bytes).")
|
||||
("shm-monitor", po::value<bool >()->default_value(true), "Shared memory: run monitor daemon.")
|
||||
("ofi-size-hint", po::value<size_t >()->default_value(0), "EXPERIMENTAL: OFI size hint for the allocator.")
|
||||
("rate", po::value<float >()->default_value(0.), "Rate for conditional run loop (Hz).")
|
||||
("session", po::value<string >()->default_value("default"), "Session name.")
|
||||
("config-key", po::value<string >(), "Use provided value instead of device id for fetching the configuration from JSON file.")
|
||||
("mq-config", po::value<string >(), "JSON input as file.")
|
||||
("channel-config", po::value<vector<string>>()->multitoken()->composing(), "Configuration of single or multiple channel(s) by comma separated key=value list");
|
||||
("id", po::value<string >()->default_value(""), "Device ID.")
|
||||
("io-threads", po::value<int >()->default_value(1), "Number of I/O threads.")
|
||||
("transport", po::value<string >()->default_value("zeromq"), "Transport ('zeromq'/'shmem').")
|
||||
("network-interface", po::value<string >()->default_value("default"), "Network interface to bind on (e.g. eth0, ib0..., default will try to detect the interface of the default route).")
|
||||
("init-timeout", po::value<int >()->default_value(120), "Timeout for the initialization in seconds (when expecting dynamic initialization).")
|
||||
("max-run-time", po::value<uint64_t >()->default_value(0), "Maximum runtime for the Running state handler, after which state will change to Ready (in seconds, 0 for no limit).")
|
||||
("print-channels", po::value<bool >()->implicit_value(true), "Print registered channel endpoints in a machine-readable format (<channel name>:<min num subchannels>:<max num subchannels>)")
|
||||
("shm-segment-size", po::value<size_t >()->default_value(2000000000), "Shared memory: size of the shared memory segment (in bytes).")
|
||||
("shm-throw-bad-alloc", po::value<bool >()->default_value(true), "Throw a fair::mq::MessageBadAlloc if cannot allocate a message (retry if false).")
|
||||
("shm-monitor", po::value<bool >()->default_value(true), "Shared memory: run monitor daemon.")
|
||||
("ofi-size-hint", po::value<size_t >()->default_value(0), "EXPERIMENTAL: OFI size hint for the allocator.")
|
||||
("rate", po::value<float >()->default_value(0.), "Rate for conditional run loop (Hz).")
|
||||
("session", po::value<string >()->default_value("default"), "Session name.")
|
||||
("config-key", po::value<string >(), "Use provided value instead of device id for fetching the configuration from JSON file.")
|
||||
("mq-config", po::value<string >(), "JSON input as file.")
|
||||
("channel-config", po::value<vector<string>>()->multitoken()->composing(), "Configuration of single or multiple channel(s) by comma separated key=value list");
|
||||
return pluginOptions;
|
||||
}
|
||||
|
||||
|
@@ -59,7 +59,7 @@ else
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Usage: startBenchmark [message size=1000000] [number of iterations=0] [transport=zeromq/nanomsg/shmem] [affinity=false]"
|
||||
echo "Usage: startBenchmark [message size=1000000] [number of iterations=0] [transport=zeromq/shmem] [affinity=false]"
|
||||
|
||||
SAMPLER="fairmq-bsampler"
|
||||
SAMPLER+=" --id bsampler1"
|
||||
@@ -70,6 +70,7 @@ SAMPLER+=" --severity debug"
|
||||
SAMPLER+=" --msg-size $msgSize"
|
||||
SAMPLER+=" --multipart $multipart"
|
||||
SAMPLER+=" --num-parts $numParts"
|
||||
SAMPLER+=" --shm-throw-bad-alloc false"
|
||||
# SAMPLER+=" --msg-rate 1000"
|
||||
SAMPLER+=" --max-iterations $maxIterations"
|
||||
SAMPLER+=" --channel-config name=data,type=pair,method=bind,address=tcp://127.0.0.1:5555"
|
||||
|
@@ -15,7 +15,6 @@
|
||||
#include <asio/system_executor.hpp>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <fairlogger/Logger.h>
|
||||
#include <fairmq/sdk/Error.h>
|
||||
#include <fairmq/sdk/Traits.h>
|
||||
#include <functional>
|
||||
@@ -24,6 +23,11 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <fairlogger/Logger.h>
|
||||
#ifndef FAIR_LOG
|
||||
#define FAIR_LOG LOG
|
||||
#endif /* ifndef FAIR_LOG */
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
namespace sdk {
|
||||
@@ -49,7 +53,7 @@ struct AsioAsyncOpImpl : AsioAsyncOpImplBase<SignatureArgTypes...>
|
||||
using Executor2 = typename asio::associated_executor<Handler, Executor1>::type;
|
||||
|
||||
/// Ctor
|
||||
AsioAsyncOpImpl(const Executor1& ex1, Allocator1&& alloc1, Handler&& handler)
|
||||
AsioAsyncOpImpl(const Executor1& ex1, Allocator1 alloc1, Handler&& handler)
|
||||
: fWork1(ex1)
|
||||
, fWork2(asio::get_associated_executor(handler, ex1))
|
||||
, fHandler(std::move(handler))
|
||||
@@ -70,9 +74,9 @@ struct AsioAsyncOpImpl : AsioAsyncOpImplBase<SignatureArgTypes...>
|
||||
try {
|
||||
handler(ec, args...);
|
||||
} catch (const std::exception& e) {
|
||||
LOG(error) << "Uncaught exception in AsioAsyncOp completion handler: " << e.what();
|
||||
FAIR_LOG(error) << "Uncaught exception in AsioAsyncOp completion handler: " << e.what();
|
||||
} catch (...) {
|
||||
LOG(error) << "Unknown uncaught exception in AsioAsyncOp completion handler.";
|
||||
FAIR_LOG(error) << "Unknown uncaught exception in AsioAsyncOp completion handler.";
|
||||
}
|
||||
},
|
||||
GetAlloc2());
|
||||
@@ -149,7 +153,7 @@ struct AsioAsyncOp<Executor,
|
||||
|
||||
/// Ctor with handler
|
||||
template<typename Handler>
|
||||
AsioAsyncOp(Executor&& ex1, Allocator&& alloc1, Handler&& handler)
|
||||
AsioAsyncOp(Executor ex1, Allocator alloc1, Handler&& handler)
|
||||
: AsioAsyncOp()
|
||||
{
|
||||
// Async operation type to be allocated and constructed
|
||||
@@ -165,8 +169,8 @@ struct AsioAsyncOp<Executor,
|
||||
auto mem(std::allocator_traits<OpAllocator>::allocate(opAlloc, 1));
|
||||
|
||||
// Construct object
|
||||
auto ptr(new (mem) Op(std::forward<Executor>(ex1),
|
||||
std::forward<Allocator>(alloc1),
|
||||
auto ptr(new (mem) Op(std::move(ex1),
|
||||
std::move(alloc1),
|
||||
std::forward<Handler>(handler)));
|
||||
|
||||
// Assign ownership to this object
|
||||
@@ -177,8 +181,8 @@ struct AsioAsyncOp<Executor,
|
||||
|
||||
/// Ctor with handler #2
|
||||
template<typename Handler>
|
||||
AsioAsyncOp(Executor&& ex1, Handler&& handler)
|
||||
: AsioAsyncOp(std::forward<Executor>(ex1), Allocator(), std::forward<Handler>(handler))
|
||||
AsioAsyncOp(Executor ex1, Handler&& handler)
|
||||
: AsioAsyncOp(std::move(ex1), Allocator(), std::forward<Handler>(handler))
|
||||
{}
|
||||
|
||||
/// Ctor with handler #3
|
||||
|
@@ -55,12 +55,17 @@ struct DDSEnvironment::Impl
|
||||
setenv("HOME", fConfigHome.c_str(), 1);
|
||||
}
|
||||
|
||||
std::istringstream cmd;
|
||||
cmd.str("DDS_CFG=`dds-user-defaults --ignore-default-sid -p`\n"
|
||||
"if [ -z \"$DDS_CFG\" ]; then\n"
|
||||
" mkdir -p \"$HOME/.DDS\"\n"
|
||||
" dds-user-defaults --ignore-default-sid -d -c \"$HOME/.DDS/DDS.cfg\"\n"
|
||||
"fi");
|
||||
std::stringstream cmd;
|
||||
#ifdef __APPLE__
|
||||
// On macOS System Integrity Protection might filter out the DYLD_LIBRARY_PATH, so we pass it
|
||||
// through explicitely here.
|
||||
cmd << "export " << fgLdVar << "=" << GetEnv(fgLdVar) << "\n";
|
||||
#endif
|
||||
cmd << "DDS_CFG=`dds-user-defaults --ignore-default-sid -p`\n"
|
||||
"if [ -z \"$DDS_CFG\" ]; then\n"
|
||||
" mkdir -p \"$HOME/.DDS\"\n"
|
||||
" dds-user-defaults --ignore-default-sid -d -c \"$HOME/.DDS/DDS.cfg\"\n"
|
||||
"fi\n";
|
||||
std::system(cmd.str().c_str());
|
||||
}
|
||||
|
||||
@@ -72,20 +77,23 @@ struct DDSEnvironment::Impl
|
||||
setenv("PATH", path.c_str(), 1);
|
||||
}
|
||||
|
||||
auto SetupDynamicLoader() -> void
|
||||
auto GenerateDDSLibDir() const -> Path
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
std::string ldVar("DYLD_LIBRARY_PATH");
|
||||
#else
|
||||
std::string ldVar("LD_LIBRARY_PATH");
|
||||
#endif
|
||||
std::string ld(GetEnv(ldVar));
|
||||
Path ddsLibDir = (fLocation == DDSInstallPrefix) ? DDSLibraryDir : fLocation / Path("lib");
|
||||
ld = ddsLibDir.string() + std::string(":") + ld;
|
||||
setenv(ldVar.c_str(), ld.c_str(), 1);
|
||||
return {(fLocation == DDSInstallPrefix) ? DDSLibraryDir : fLocation / Path("lib")};
|
||||
}
|
||||
|
||||
auto GetEnv(const std::string& key) -> std::string
|
||||
auto SetupDynamicLoader() -> void
|
||||
{
|
||||
std::string ld(GetEnv(fgLdVar));
|
||||
if (ld.empty()) {
|
||||
ld = GenerateDDSLibDir().string();
|
||||
} else {
|
||||
ld = GenerateDDSLibDir().string() + std::string(":") + ld;
|
||||
}
|
||||
setenv(fgLdVar.c_str(), ld.c_str(), 1);
|
||||
}
|
||||
|
||||
auto GetEnv(const std::string& key) const -> std::string
|
||||
{
|
||||
auto value = std::getenv(key.c_str());
|
||||
if (value) {
|
||||
@@ -100,6 +108,11 @@ struct DDSEnvironment::Impl
|
||||
|
||||
Path fLocation;
|
||||
Path fConfigHome;
|
||||
#ifdef __APPLE__
|
||||
std::string const fgLdVar = "DYLD_LIBRARY_PATH";
|
||||
#else
|
||||
std::string const fgLdVar = "LD_LIBRARY_PATH";
|
||||
#endif
|
||||
};
|
||||
|
||||
DDSEnvironment::DDSEnvironment()
|
||||
|
@@ -135,8 +135,6 @@ struct DDSSession::Impl
|
||||
dds::intercom_api::CCustomCmd fDDSCustomCmd;
|
||||
Id fId;
|
||||
bool fStopOnDestruction;
|
||||
mutable std::mutex fMtx;
|
||||
std::unordered_map<DDSChannel::Id, DDSTask::Id> fTaskIdByChannelIdMap;
|
||||
};
|
||||
|
||||
DDSSession::DDSSession(DDSEnvironment env)
|
||||
@@ -355,25 +353,13 @@ void DDSSession::UnsubscribeFromCommands()
|
||||
fImpl->fDDSCustomCmd.unsubscribe();
|
||||
}
|
||||
|
||||
void DDSSession::SendCommand(const std::string& cmd) { fImpl->fDDSCustomCmd.send(cmd, ""); }
|
||||
void DDSSession::SendCommand(const std::string& cmd, const std::string& path /* = "" */) { fImpl->fDDSCustomCmd.send(cmd, path); }
|
||||
|
||||
void DDSSession::SendCommand(const std::string& cmd, DDSChannel::Id recipient)
|
||||
{
|
||||
fImpl->fDDSCustomCmd.send(cmd, std::to_string(recipient));
|
||||
}
|
||||
|
||||
auto DDSSession::UpdateChannelToTaskAssociation(DDSChannel::Id channelId, DDSTask::Id taskId) -> void
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(fImpl->fMtx);
|
||||
fImpl->fTaskIdByChannelIdMap[channelId] = taskId;
|
||||
}
|
||||
|
||||
auto DDSSession::GetTaskId(DDSChannel::Id channelId) const -> DDSTask::Id
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(fImpl->fMtx);
|
||||
return fImpl->fTaskIdByChannelIdMap.at(channelId);
|
||||
}
|
||||
|
||||
auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&
|
||||
{
|
||||
return os << "$DDS_SESSION_ID: " << session.GetId();
|
||||
|
@@ -101,9 +101,8 @@ class DDSSession
|
||||
void StartDDSService();
|
||||
void SubscribeToCommands(std::function<void(const std::string& msg, const std::string& condition, uint64_t senderId)>);
|
||||
void UnsubscribeFromCommands();
|
||||
void SendCommand(const std::string&);
|
||||
void SendCommand(const std::string&, const std::string& = "");
|
||||
void SendCommand(const std::string&, DDSChannel::Id);
|
||||
auto UpdateChannelToTaskAssociation(DDSChannel::Id, DDSTask::Id) -> void;
|
||||
auto GetTaskId(DDSChannel::Id) const -> DDSTask::Id;
|
||||
|
||||
friend auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&;
|
||||
|
@@ -64,22 +64,23 @@ auto DDSTopology::GetNumRequiredAgents() const -> int
|
||||
return fImpl->fTopo.getRequiredNofAgents();
|
||||
}
|
||||
|
||||
auto DDSTopology::GetTasks() const -> std::vector<DDSTask>
|
||||
auto DDSTopology::GetTasks(const std::string& path /* = "" */) const -> std::vector<DDSTask>
|
||||
{
|
||||
std::vector<DDSTask> list;
|
||||
list.reserve(GetNumRequiredAgents());
|
||||
|
||||
auto itPair = fImpl->fTopo.getRuntimeTaskIterator(
|
||||
[](const dds::topology_api::STopoRuntimeTask::FilterIterator_t::value_type&) -> bool {
|
||||
return true;
|
||||
});
|
||||
dds::topology_api::STopoRuntimeTask::FilterIteratorPair_t itPair;
|
||||
if (path == "") {
|
||||
itPair = fImpl->fTopo.getRuntimeTaskIterator(nullptr); // passing nullptr will get all tasks
|
||||
} else {
|
||||
itPair = fImpl->fTopo.getRuntimeTaskIteratorMatchingPath(path);
|
||||
}
|
||||
auto tasks = boost::make_iterator_range(itPair.first, itPair.second);
|
||||
|
||||
for (const auto& task : tasks) {
|
||||
LOG(debug) << "Found task with id: " << task.first << ", "
|
||||
<< "Path: " << task.second.m_taskPath << ", "
|
||||
<< "Collection id: " << task.second.m_taskCollectionId << ", "
|
||||
<< "Name: " << task.second.m_task->getName() << "_" << task.second.m_taskIndex;
|
||||
// LOG(debug) << "Found task with id: " << task.first << ", "
|
||||
// << "Path: " << task.second.m_taskPath << ", "
|
||||
// << "Collection id: " << task.second.m_taskCollectionId << ", "
|
||||
// << "Name: " << task.second.m_task->getName() << "_" << task.second.m_taskIndex;
|
||||
list.emplace_back(task.first, task.second.m_taskCollectionId);
|
||||
}
|
||||
|
||||
@@ -90,10 +91,7 @@ auto DDSTopology::GetCollections() const -> std::vector<DDSCollection>
|
||||
{
|
||||
std::vector<DDSCollection> list;
|
||||
|
||||
auto itPair = fImpl->fTopo.getRuntimeCollectionIterator(
|
||||
[](const dds::topology_api::STopoRuntimeCollection::FilterIterator_t::value_type&) -> bool {
|
||||
return true;
|
||||
});
|
||||
auto itPair = fImpl->fTopo.getRuntimeCollectionIterator(nullptr); // passing nullptr will get all collections
|
||||
auto collections = boost::make_iterator_range(itPair.first, itPair.second);
|
||||
|
||||
for (const auto& c : collections) {
|
||||
|
@@ -53,8 +53,8 @@ class DDSTopology
|
||||
/// @brief Get number of required agents for this topology
|
||||
auto GetNumRequiredAgents() const -> int;
|
||||
|
||||
/// @brief Get list of tasks in this topology
|
||||
auto GetTasks() const -> std::vector<DDSTask>;
|
||||
/// @brief Get list of tasks in this topology, optionally matching provided path
|
||||
auto GetTasks(const std::string& = "") const -> std::vector<DDSTask>;
|
||||
|
||||
/// @brief Get list of tasks in this topology
|
||||
auto GetCollections() const -> std::vector<DDSCollection>;
|
||||
|
@@ -27,6 +27,10 @@ std::string ErrorCategory::message(int ev) const
|
||||
return "async operation canceled";
|
||||
case ErrorCode::DeviceChangeStateFailed:
|
||||
return "failed to change state of a fairmq device";
|
||||
case ErrorCode::DeviceGetPropertiesFailed:
|
||||
return "failed to get fairmq device properties";
|
||||
case ErrorCode::DeviceSetPropertiesFailed:
|
||||
return "failed to set fairmq device properties";
|
||||
default:
|
||||
return "(unrecognized error)";
|
||||
}
|
||||
|
@@ -37,7 +37,9 @@ enum class ErrorCode
|
||||
OperationInProgress = 10,
|
||||
OperationTimeout,
|
||||
OperationCanceled,
|
||||
DeviceChangeStateFailed
|
||||
DeviceChangeStateFailed,
|
||||
DeviceGetPropertiesFailed,
|
||||
DeviceSetPropertiesFailed
|
||||
};
|
||||
|
||||
std::error_code MakeErrorCode(ErrorCode);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user