mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-15 17:41:45 +00:00
Compare commits
66 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e6f67b3658 | ||
|
091d0824d1 | ||
|
857aa84fa3 | ||
|
c85d6e079c | ||
|
4e466514d2 | ||
|
8b4056e408 | ||
|
b67b80e0ad | ||
|
2c89b24857 | ||
|
c6a6a5f21b | ||
|
9defa71622 | ||
|
ed2dcedf03 | ||
|
a3d56b9aeb | ||
|
8a2641d842 | ||
|
2ca62d06db | ||
|
87e0ca5450 | ||
|
ef5b3c782e | ||
|
f7ba3052aa | ||
|
a90dbf64de | ||
|
9724f184f4 | ||
|
057ba03776 | ||
|
6dfea32aee | ||
|
868fe02ee9 | ||
|
a2016a9361 | ||
|
ea9aede652 | ||
|
77bf12c8e8 | ||
|
f3bc9e05a8 | ||
|
5facc441b8 | ||
|
2602f53585 | ||
|
0976465338 | ||
|
9144258b89 | ||
|
be55565617 | ||
|
d7e2fbecea | ||
|
72175e5757 | ||
|
effba534f0 | ||
|
efd42075a9 | ||
|
5228407932 | ||
|
30e81d58f8 | ||
|
2c7c46f2fd | ||
|
0a5122bb24 | ||
|
fc49687879 | ||
|
66a4df0667 | ||
|
978191fa6c | ||
|
cef6d0afcd | ||
|
47ec550792 | ||
|
b4aeb320e5 | ||
|
107248be0a | ||
|
68ceaba501 | ||
|
4b6cf8b181 | ||
|
21d6cf9830 | ||
|
bffe74c5cf | ||
|
72f319e276 | ||
|
62438bd99e | ||
|
c8ad684b18 | ||
|
a5ec83208d | ||
|
fc2241ece7 | ||
|
1f26883b75 | ||
|
edbdc57332 | ||
|
0fd2fcadc2 | ||
|
9b48b31a75 | ||
|
cb4335e59f | ||
|
ce4584b3d8 | ||
|
bbc1dd4600 | ||
|
8327810942 | ||
|
c37742e3b4 | ||
|
93dff3c5a7 | ||
|
2b3e38d9a4 |
@@ -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,-modernize-use-trailing-return-type,-readability-redundant-member-init'
|
||||
Checks: 'cppcoreguidelines-*,misc-unused-alias-decls,misc-unused-parameters,modernize-deprecated-headers,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-use-bool-literals,modernize-use-default-member-init,modernize-use-emplace,modernize-use-equals-default,modernize-use-equals-delete,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-using,performance-faster-string-find,performance-for-range-copy,performance-unnecessary-copy-initialization,readability-avoid-const-params-in-decls,readability-braces-around-statements,readability-container-size-empty,readability-delete-null-pointer,readability-redundant-member-init,readability-redundant-string-init,readability-static-accessed-through-instance,readability-string-compare'
|
||||
HeaderFilterRegex: '/(fairmq/)'
|
||||
|
125
FairMQTest.cmake
125
FairMQTest.cmake
@@ -1,88 +1,69 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# Copyright (C) 2021 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(CTEST_SOURCE_DIRECTORY $ENV{SOURCEDIR})
|
||||
Set(CTEST_BINARY_DIRECTORY $ENV{BUILDDIR})
|
||||
Set(CTEST_SITE $ENV{SITE})
|
||||
Set(CTEST_BUILD_NAME $ENV{LABEL})
|
||||
Set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
|
||||
Set(CTEST_PROJECT_NAME "FairMQ")
|
||||
|
||||
Find_Program(CTEST_GIT_COMMAND NAMES git)
|
||||
Set(CTEST_UPDATE_COMMAND "${CTEST_GIT_COMMAND}")
|
||||
cmake_host_system_information(RESULT fqdn QUERY FQDN)
|
||||
|
||||
Set(BUILD_COMMAND "make")
|
||||
Set(CTEST_BUILD_COMMAND "${BUILD_COMMAND} -j$ENV{number_of_processors}")
|
||||
set(CTEST_SOURCE_DIRECTORY .)
|
||||
set(CTEST_BINARY_DIRECTORY build)
|
||||
set(CTEST_CMAKE_GENERATOR "Ninja")
|
||||
set(CTEST_USE_LAUNCHERS ON)
|
||||
set(CTEST_CONFIGURATION_TYPE "RelWithDebInfo")
|
||||
|
||||
String(TOUPPER $ENV{ctest_model} _Model)
|
||||
Set(configure_options "-DCMAKE_BUILD_TYPE=$ENV{ctest_model}")
|
||||
|
||||
Set(CTEST_USE_LAUNCHERS 1)
|
||||
Set(configure_options "${configure_options};-DCTEST_USE_LAUNCHERS=${CTEST_USE_LAUNCHERS}")
|
||||
|
||||
Set(configure_options "${configure_options};-DDISABLE_COLOR=ON")
|
||||
Set(configure_options "${configure_options};-DCMAKE_PREFIX_PATH=$ENV{SIMPATH}")
|
||||
# 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")
|
||||
Set(configure_options "${configure_options};-DBUILD_SDK_COMMANDS=ON")
|
||||
|
||||
Set(EXTRA_FLAGS $ENV{EXTRA_FLAGS})
|
||||
If(EXTRA_FLAGS)
|
||||
Set(configure_options "${configure_options};${EXTRA_FLAGS}")
|
||||
EndIf()
|
||||
|
||||
If($ENV{ctest_model} MATCHES Profile)
|
||||
Find_Program(GCOV_COMMAND gcov)
|
||||
If(GCOV_COMMAND)
|
||||
Message("Found GCOV: ${GCOV_COMMAND}")
|
||||
Set(CTEST_COVERAGE_COMMAND ${GCOV_COMMAND})
|
||||
set(CTEST_COVERAGE_EXTRA_FLAGS "-p")
|
||||
EndIf(GCOV_COMMAND)
|
||||
EndIf()
|
||||
|
||||
If($ENV{ctest_model} MATCHES Nightly OR $ENV{ctest_model} MATCHES Profile)
|
||||
Ctest_Empty_Binary_Directory(${CTEST_BINARY_DIRECTORY})
|
||||
EndIf()
|
||||
|
||||
Ctest_Start($ENV{ctest_model})
|
||||
|
||||
Ctest_Configure(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
OPTIONS "${configure_options}"
|
||||
)
|
||||
|
||||
Ctest_Build(BUILD "${CTEST_BINARY_DIRECTORY}")
|
||||
|
||||
unset(exclude_tests)
|
||||
if($ENV{EXCLUDE_UNSTABLE_DDS_TESTS})
|
||||
set(exclude_tests EXCLUDE ".*\\.localhost$")
|
||||
if(NOT NCPUS)
|
||||
if(ENV{SLURM_CPUS_PER_TASK})
|
||||
set(NCPUS $ENV{SLURM_CPUS_PER_TASK})
|
||||
else()
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(NCPUS)
|
||||
if(NCPUS EQUAL 0)
|
||||
set(NCPUS 1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
# PARALLEL_LEVEL $ENV{number_of_processors}
|
||||
${exclude_tests}
|
||||
PARALLEL_LEVEL $ENV{number_of_processors}
|
||||
RETURN_VALUE _ctest_test_ret_val
|
||||
)
|
||||
|
||||
If(GCOV_COMMAND)
|
||||
Ctest_Coverage(BUILD "${CTEST_BINARY_DIRECTORY}" LABELS coverage)
|
||||
EndIf()
|
||||
if ("$ENV{CTEST_SITE}" STREQUAL "")
|
||||
set(CTEST_SITE "${fqdn}")
|
||||
else()
|
||||
set(CTEST_SITE $ENV{CTEST_SITE})
|
||||
endif()
|
||||
|
||||
If("$ENV{do_codecov_upload}")
|
||||
Execute_Process(COMMAND curl https://codecov.io/bash -o codecov_uploader.sh
|
||||
WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY}
|
||||
TIMEOUT 60)
|
||||
Execute_Process(COMMAND bash ./codecov_uploader.sh -X gcov
|
||||
WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY}
|
||||
TIMEOUT 60)
|
||||
EndIf()
|
||||
if ("$ENV{LABEL}" STREQUAL "")
|
||||
set(CTEST_BUILD_NAME "build")
|
||||
else()
|
||||
set(CTEST_BUILD_NAME $ENV{LABEL})
|
||||
endif()
|
||||
|
||||
Ctest_Submit()
|
||||
ctest_start(Continuous)
|
||||
|
||||
if (_ctest_test_ret_val)
|
||||
list(APPEND options
|
||||
"-DDISABLE_COLOR=ON"
|
||||
"-DBUILD_SDK_COMMANDS=ON"
|
||||
"-DBUILD_SDK=ON"
|
||||
"-DBUILD_DDS_PLUGIN=ON")
|
||||
if(RUN_STATIC_ANALYSIS)
|
||||
list(APPEND options "-DRUN_STATIC_ANALYSIS=ON")
|
||||
endif()
|
||||
list(JOIN options ";" optionsstr)
|
||||
ctest_configure(OPTIONS "${optionsstr}")
|
||||
|
||||
ctest_submit()
|
||||
|
||||
ctest_build(FLAGS "-j${NCPUS}")
|
||||
|
||||
ctest_submit()
|
||||
|
||||
ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
PARALLEL_LEVEL 1
|
||||
SCHEDULE_RANDOM ON
|
||||
RETURN_VALUE _ctest_test_ret_val)
|
||||
|
||||
ctest_submit()
|
||||
|
||||
if(_ctest_test_ret_val)
|
||||
Message(FATAL_ERROR "Some tests failed.")
|
||||
endif()
|
||||
|
120
Jenkinsfile
vendored
120
Jenkinsfile
vendored
@@ -1,69 +1,69 @@
|
||||
#!groovy
|
||||
|
||||
def specToLabel(Map spec) {
|
||||
return "${spec.os}-${spec.arch}-${spec.compiler}-FairSoft_${spec.fairsoft}"
|
||||
}
|
||||
|
||||
def jobMatrix(String prefix, List specs, Closure callback) {
|
||||
def jobMatrix(String type, List specs) {
|
||||
def nodes = [:]
|
||||
for (spec in specs) {
|
||||
def label = specToLabel(spec)
|
||||
def node_tag = label
|
||||
if (spec.os =~ /macOS/) {
|
||||
node_tag = spec.os
|
||||
}
|
||||
def fairsoft = spec.fairsoft
|
||||
job = "${spec.os}-${spec.ver}-${spec.arch}-${spec.compiler}"
|
||||
def label = "${type}/${job}"
|
||||
def selector = "${spec.os}-${spec.ver}-${spec.arch}"
|
||||
def os = spec.os
|
||||
def compiler = spec.compiler
|
||||
nodes["${prefix}/${label}"] = {
|
||||
node(node_tag) {
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Building ...', status: 'PENDING')
|
||||
def ver = spec.ver
|
||||
def check = spec.check
|
||||
|
||||
nodes[label] = {
|
||||
node(selector) {
|
||||
githubNotify(context: "${label}", description: 'Building ...', status: 'PENDING')
|
||||
try {
|
||||
deleteDir()
|
||||
checkout scm
|
||||
|
||||
sh """\
|
||||
echo "export SIMPATH=\${SIMPATH_PREFIX}${fairsoft}" >> Dart.cfg
|
||||
echo "export FAIRSOFT_VERSION=${fairsoft}" >> Dart.cfg
|
||||
"""
|
||||
if (os =~ /Debian/ && compiler =~ /gcc9/) {
|
||||
sh '''\
|
||||
echo "source /etc/profile.d/modules.sh" >> Dart.cfg
|
||||
echo "module use /cvmfs/it.gsi.de/modulefiles" >> Dart.cfg
|
||||
echo "module load compiler/gcc/9.1.0" >> Dart.cfg
|
||||
'''
|
||||
}
|
||||
if (os =~ /[Mm]acOS/) {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=clang++'\" >> Dart.cfg"
|
||||
def jobscript = 'job.sh'
|
||||
def ctestcmd = "ctest -S FairMQTest.cmake -V --output-on-failure"
|
||||
sh "echo \"set -e\" >> ${jobscript}"
|
||||
sh "echo \"export LABEL=\\\"\${JOB_BASE_NAME} ${label}\\\"\" >> ${jobscript}"
|
||||
if (selector =~ /^macos/) {
|
||||
sh """\
|
||||
echo \"export DDS_ROOT=\\\"\\\$(brew --prefix dds)\\\"\" >> ${jobscript}
|
||||
echo \"${ctestcmd}\" >> ${jobscript}
|
||||
"""
|
||||
sh "cat ${jobscript}"
|
||||
sh "bash ${jobscript}"
|
||||
} else {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=g++'\" >> Dart.cfg"
|
||||
def static_analysis = "OFF"
|
||||
if (selector =~ /^fedora/) {
|
||||
static_analysis = "ON"
|
||||
}
|
||||
def containercmd = "singularity exec -B/shared ${env.SINGULARITY_CONTAINER_ROOT}/fairmq/${os}.${ver}.sif bash -l -c \\\"${ctestcmd} -DRUN_STATIC_ANALYSIS=${static_analysis}\\\""
|
||||
sh """\
|
||||
echo \"echo \\\"*** Job started at .......: \\\$(date -R)\\\"\" >> ${jobscript}
|
||||
echo \"echo \\\"*** Job ID ...............: \\\${SLURM_JOB_ID}\\\"\" >> ${jobscript}
|
||||
echo \"echo \\\"*** Compute node .........: \\\$(hostname -f)\\\"\" >> ${jobscript}
|
||||
echo \"unset http_proxy\" >> ${jobscript}
|
||||
echo \"unset HTTP_PROXY\" >> ${jobscript}
|
||||
echo \"${containercmd}\" >> ${jobscript}
|
||||
"""
|
||||
sh "cat ${jobscript}"
|
||||
sh "test/ci/slurm-submit.sh \"FairMQ \${JOB_BASE_NAME} ${label}\" ${jobscript}"
|
||||
|
||||
withChecks('Static Analysis') {
|
||||
if (static_analysis == "ON") {
|
||||
recordIssues(enabledForFailure: true,
|
||||
tools: [gcc(pattern: 'build/Testing/Temporary/*.log')],
|
||||
filters: [excludeFile('extern/*'), excludeFile('usr/*')],
|
||||
skipBlames: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sh '''\
|
||||
echo "export BUILDDIR=$PWD/build" >> Dart.cfg
|
||||
echo "export SOURCEDIR=$PWD" >> Dart.cfg
|
||||
echo "export PATH=\\\$SIMPATH/bin:\\\$PATH" >> Dart.cfg
|
||||
echo "export GIT_BRANCH=$JOB_BASE_NAME" >> Dart.cfg
|
||||
echo "echo \\\$PATH" >> Dart.cfg
|
||||
'''
|
||||
|
||||
if (os =~ /macOS10.14/) {
|
||||
sh "echo \"export EXCLUDE_UNSTABLE_DDS_TESTS=1\" >> Dart.cfg"
|
||||
}
|
||||
|
||||
sh 'cat Dart.cfg'
|
||||
|
||||
callback.call(spec, label)
|
||||
|
||||
deleteDir()
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Success', status: 'SUCCESS')
|
||||
githubNotify(context: "${label}", description: 'Success', status: 'SUCCESS')
|
||||
} catch (e) {
|
||||
def tarball = "${prefix}_${label}_dds_logs.tar.gz"
|
||||
sh "tar czvf ${tarball} -C \${WORKSPACE}/build/test/ .DDS/"
|
||||
sh "tar czvf ${tarball} -C \${WORKSPACE}/build/test .DDS/"
|
||||
archiveArtifacts tarball
|
||||
|
||||
deleteDir()
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Error', status: 'ERROR')
|
||||
githubNotify(context: "${label}", description: 'Error', status: 'ERROR')
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -75,26 +75,16 @@ def jobMatrix(String prefix, List specs, Closure callback) {
|
||||
pipeline{
|
||||
agent none
|
||||
stages {
|
||||
stage("Run CI Matrix") {
|
||||
stage("CI") {
|
||||
steps{
|
||||
script {
|
||||
def build_jobs = jobMatrix('build', [
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc9.1.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'macOS10.14', arch: 'x86_64', compiler: 'AppleClang11.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'macOS10.15', arch: 'x86_64', compiler: 'AppleClang12.0', fairsoft: 'fairmq_dev'],
|
||||
]) { spec, label ->
|
||||
sh './Dart.sh alfa_ci Dart.cfg'
|
||||
}
|
||||
def builds = jobMatrix('build', [
|
||||
[os: 'alice-centos', ver: '7', arch: 'x86_64', compiler: 'gcc-7'],
|
||||
[os: 'fedora', ver: '32', arch: 'x86_64', compiler: 'gcc-10'],
|
||||
[os: 'macos', ver: '11', arch: 'x86_64', compiler: 'apple-clang-12'],
|
||||
])
|
||||
|
||||
def profile_jobs = jobMatrix('codecov', [
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc9.1.0', fairsoft: 'fairmq_dev'],
|
||||
]) { spec, label ->
|
||||
withCredentials([string(credentialsId: 'fairmq_codecov_token', variable: 'CODECOV_TOKEN')]) {
|
||||
sh './Dart.sh codecov Dart.cfg'
|
||||
}
|
||||
}
|
||||
|
||||
parallel(build_jobs + profile_jobs)
|
||||
parallel(builds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,81 +0,0 @@
|
||||
#!groovy
|
||||
|
||||
def specToLabel(Map spec) {
|
||||
return "${spec.os}-${spec.arch}-${spec.compiler}-FairSoft_${spec.fairsoft}"
|
||||
}
|
||||
|
||||
def buildMatrix(List specs, Closure callback) {
|
||||
def nodes = [:]
|
||||
for (spec in specs) {
|
||||
def label = specToLabel(spec)
|
||||
def fairsoft = spec.fairsoft
|
||||
def os = spec.os
|
||||
def compiler = spec.compiler
|
||||
nodes[label] = {
|
||||
node(label) {
|
||||
try {
|
||||
deleteDir()
|
||||
checkout scm
|
||||
|
||||
sh """\
|
||||
echo "export SIMPATH=\${SIMPATH_PREFIX}${fairsoft}" >> Dart.cfg
|
||||
echo "export FAIRSOFT_VERSION=${fairsoft}" >> Dart.cfg
|
||||
"""
|
||||
if (os =~ /Debian/ && compiler =~ /gcc9/) {
|
||||
sh '''\
|
||||
echo "source /etc/profile.d/modules.sh" >> Dart.cfg
|
||||
echo "module use /cvmfs/it.gsi.de/modulefiles" >> Dart.cfg
|
||||
echo "module load compiler/gcc/9.1.0" >> Dart.cfg
|
||||
'''
|
||||
}
|
||||
if (os =~ /MacOS/) {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=clang++'\" >> Dart.cfg"
|
||||
} else {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=g++'\" >> Dart.cfg"
|
||||
}
|
||||
sh '''\
|
||||
echo "export BUILDDIR=$PWD/build" >> Dart.cfg
|
||||
echo "export SOURCEDIR=$PWD" >> Dart.cfg
|
||||
echo "export PATH=\\\$SIMPATH/bin:\\\$PATH" >> Dart.cfg
|
||||
echo "export GIT_BRANCH=dev" >> Dart.cfg
|
||||
echo "echo \\\$PATH" >> Dart.cfg
|
||||
'''
|
||||
sh 'cat Dart.cfg'
|
||||
|
||||
callback.call(spec, label)
|
||||
|
||||
deleteDir()
|
||||
} catch (e) {
|
||||
def tarball = "${label}_dds_logs.tar.gz"
|
||||
sh "tar czvf ${tarball} -C \${WORKSPACE}/build/test/ .DDS/"
|
||||
archiveArtifacts tarball
|
||||
|
||||
deleteDir()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
pipeline{
|
||||
agent none
|
||||
triggers { cron('H 2 * * *') }
|
||||
stages {
|
||||
stage("Run Nightly Build/Test Matrix") {
|
||||
steps{
|
||||
script {
|
||||
parallel(buildMatrix([
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc9.1.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.14', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
]) { spec, label ->
|
||||
sh './Dart.sh Nightly Dart.cfg'
|
||||
sh './Dart.sh Profile Dart.cfg'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
<!-- {#mainpage} -->
|
||||
# FairMQ [](COPYRIGHT) [](https://alfa-ci.gsi.de/blue/organizations/jenkins/FairRootGroup%2FFairMQ/branches) [](https://codecov.io/gh/FairRootGroup/FairMQ/branch/master) [](https://scan.coverity.com/projects/fairrootgroup-fairmq) [](https://www.codacy.com/app/dennisklein/FairMQ?utm_source=github.com&utm_medium=referral&utm_content=FairRootGroup/FairMQ&utm_campaign=Badge_Grade)
|
||||
# FairMQ [](COPYRIGHT) [](https://alfa-ci.gsi.de/blue/organizations/jenkins/FairRootGroup%2FFairMQ/branches) [](https://scan.coverity.com/projects/fairrootgroup-fairmq)
|
||||
|
||||
C++ Message Queuing Library and Framework
|
||||
|
||||
|
@@ -203,6 +203,13 @@ macro(set_fairmq_defaults)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
|
||||
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)
|
||||
set(FAIRMQ_HAS_STD_FILESYSTEM 0)
|
||||
else()
|
||||
set(FAIRMQ_HAS_STD_FILESYSTEM 1)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(join VALUES GLUE OUTPUT)
|
||||
|
@@ -7,10 +7,10 @@
|
||||
################################################################################
|
||||
|
||||
add_library(Example11Lib STATIC
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
)
|
||||
|
||||
target_link_libraries(Example11Lib PUBLIC FairMQ)
|
||||
@@ -40,12 +40,12 @@ set_tests_properties(Example.1-1.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true P
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-1-1-sampler
|
||||
fairmq-ex-1-1-sink
|
||||
TARGETS
|
||||
fairmq-ex-1-1-sampler
|
||||
fairmq-ex-1-1-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
|
||||
@@ -54,7 +54,7 @@ set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-1-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-1.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-1.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-1-1.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-1.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-1-1.sh
|
||||
)
|
||||
|
@@ -7,12 +7,12 @@
|
||||
################################################################################
|
||||
|
||||
add_library(Example1N1Lib 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(Example1N1Lib PUBLIC FairMQ)
|
||||
@@ -48,13 +48,13 @@ set_tests_properties(Example.1-n-1.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-1-n-1-sampler
|
||||
fairmq-ex-1-n-1-processor
|
||||
fairmq-ex-1-n-1-sink
|
||||
TARGETS
|
||||
fairmq-ex-1-n-1-sampler
|
||||
fairmq-ex-1-n-1-processor
|
||||
fairmq-ex-1-n-1-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
|
||||
@@ -64,12 +64,12 @@ set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-1-n-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-n-1.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-n-1.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-1-n-1.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-n-1.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-1-n-1.sh
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-1-n-1.json
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-1-n-1.json
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||
)
|
||||
|
@@ -34,7 +34,7 @@ set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-builtin-devices.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-builtin-devices.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-builtin-devices.sh
|
||||
)
|
||||
|
@@ -7,10 +7,10 @@
|
||||
################################################################################
|
||||
|
||||
add_library(ExampleCopyPushLib STATIC
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
)
|
||||
|
||||
target_link_libraries(ExampleCopyPushLib PUBLIC FairMQ)
|
||||
@@ -41,12 +41,12 @@ set_tests_properties(Example.CopyPush.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL t
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-copypush-sampler
|
||||
fairmq-ex-copypush-sink
|
||||
TARGETS
|
||||
fairmq-ex-copypush-sampler
|
||||
fairmq-ex-copypush-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
|
||||
@@ -55,7 +55,7 @@ set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-copypush.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-copypush.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-copypush.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-copypush.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-copypush.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-copypush.sh
|
||||
)
|
||||
|
@@ -7,10 +7,10 @@
|
||||
################################################################################
|
||||
|
||||
add_library(ExampleMultipartLib STATIC
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
)
|
||||
|
||||
target_link_libraries(ExampleMultipartLib PUBLIC FairMQ)
|
||||
@@ -45,12 +45,12 @@ endif()
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-multipart-sampler
|
||||
fairmq-ex-multipart-sink
|
||||
TARGETS
|
||||
fairmq-ex-multipart-sampler
|
||||
fairmq-ex-multipart-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
|
||||
@@ -59,7 +59,7 @@ set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multipart.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multipart.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multipart.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-multipart.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multipart.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-multipart.sh
|
||||
)
|
||||
|
@@ -7,12 +7,12 @@
|
||||
################################################################################
|
||||
|
||||
add_library(ExampleMultipleChannelsLib STATIC
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Broadcaster.cxx"
|
||||
"Broadcaster.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Broadcaster.cxx"
|
||||
"Broadcaster.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
)
|
||||
|
||||
target_link_libraries(ExampleMultipleChannelsLib PUBLIC FairMQ)
|
||||
@@ -42,13 +42,13 @@ set_tests_properties(Example.MultipleChannels.zeromq PROPERTIES TIMEOUT "30" RUN
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-multiple-channels-sampler
|
||||
fairmq-ex-multiple-channels-broadcaster
|
||||
fairmq-ex-multiple-channels-sink
|
||||
TARGETS
|
||||
fairmq-ex-multiple-channels-sampler
|
||||
fairmq-ex-multiple-channels-broadcaster
|
||||
fairmq-ex-multiple-channels-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
|
||||
@@ -57,7 +57,7 @@ set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multiple-channels.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-channels.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-channels.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-multiple-channels.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-channels.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-multiple-channels.sh
|
||||
)
|
||||
|
@@ -7,12 +7,12 @@
|
||||
################################################################################
|
||||
|
||||
add_library(ExampleMultipleTransportsLib STATIC
|
||||
"Sampler1.cxx"
|
||||
"Sampler1.h"
|
||||
"Sampler2.cxx"
|
||||
"Sampler2.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
"Sampler1.cxx"
|
||||
"Sampler1.h"
|
||||
"Sampler2.cxx"
|
||||
"Sampler2.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
)
|
||||
|
||||
target_link_libraries(ExampleMultipleTransportsLib PUBLIC FairMQ)
|
||||
@@ -41,13 +41,13 @@ set_tests_properties(Example.MultipleTransports PROPERTIES TIMEOUT "30" RUN_SERI
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-multiple-transports-sampler1
|
||||
fairmq-ex-multiple-transports-sampler2
|
||||
fairmq-ex-multiple-transports-sink
|
||||
TARGETS
|
||||
fairmq-ex-multiple-transports-sampler1
|
||||
fairmq-ex-multiple-transports-sampler2
|
||||
fairmq-ex-multiple-transports-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 install directories
|
||||
@@ -56,7 +56,7 @@ set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multiple-transports.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-transports.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-transports.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-multiple-transports.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-transports.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-multiple-transports.sh
|
||||
)
|
||||
|
@@ -29,15 +29,15 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout-processing.sh
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-readout-readout
|
||||
fairmq-ex-readout-builder
|
||||
fairmq-ex-readout-processor
|
||||
fairmq-ex-readout-sender
|
||||
fairmq-ex-readout-receiver
|
||||
TARGETS
|
||||
fairmq-ex-readout-readout
|
||||
fairmq-ex-readout-builder
|
||||
fairmq-ex-readout-processor
|
||||
fairmq-ex-readout-sender
|
||||
fairmq-ex-readout-receiver
|
||||
|
||||
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
|
||||
@@ -47,13 +47,13 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout.sh.in ${CMAKE
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout-processing.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-readout.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-readout.sh
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-readout-processing.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-readout-processing.sh
|
||||
)
|
||||
|
@@ -7,10 +7,10 @@
|
||||
################################################################################
|
||||
|
||||
add_library(ExampleRegionLib STATIC
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
)
|
||||
|
||||
target_link_libraries(ExampleRegionLib PUBLIC FairMQ)
|
||||
@@ -40,12 +40,12 @@ set_tests_properties(Example.Region.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL tru
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-region-sampler
|
||||
fairmq-ex-region-sink
|
||||
TARGETS
|
||||
fairmq-ex-region-sampler
|
||||
fairmq-ex-region-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
|
||||
@@ -54,7 +54,7 @@ set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-region.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-region.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-region.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-region.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-region.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-region.sh
|
||||
)
|
||||
|
@@ -5,12 +5,6 @@
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* Sampler.cpp
|
||||
*
|
||||
* @since 2014-10-10
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include "Sampler.h"
|
||||
|
||||
@@ -37,17 +31,17 @@ void Sampler::InitTask()
|
||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||
|
||||
fChannels.at("data").at(0).Transport()->SubscribeToRegionEvents([](FairMQRegionInfo info) {
|
||||
LOG(info) << "Region event: " << info.event
|
||||
<< ", managed: " << info.managed
|
||||
LOG(info) << "Region event: " << info.event << ": "
|
||||
<< (info.managed ? "managed" : "unmanaged")
|
||||
<< ", id: " << info.id
|
||||
<< ", ptr: " << info.ptr
|
||||
<< ", size: " << info.size
|
||||
<< ", flags: " << info.flags;
|
||||
});
|
||||
|
||||
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("data",
|
||||
0,
|
||||
10000000,
|
||||
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("data", // region is created using the transport of this channel...
|
||||
0, // ... and this sub-channel
|
||||
10000000, // region size
|
||||
[this](const std::vector<fair::mq::RegionBlock>& blocks) { // callback to be called when message buffers no longer needed by transport
|
||||
lock_guard<mutex> lock(fMtx);
|
||||
fNumUnackedMsgs -= blocks.size();
|
||||
@@ -55,7 +49,10 @@ void Sampler::InitTask()
|
||||
if (fMaxIterations > 0) {
|
||||
LOG(info) << "Received " << blocks.size() << " acks";
|
||||
}
|
||||
}
|
||||
},
|
||||
"", // path, if a region is backed by a file
|
||||
0, // flags that are passed for region creation
|
||||
fair::mq::RegionConfig{true, true} // additional config: { call mlock on the region, zero the region memory }
|
||||
));
|
||||
fRegion->SetLinger(fLinger);
|
||||
}
|
||||
@@ -75,20 +72,19 @@ bool Sampler::ConditionalRun()
|
||||
// std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
lock_guard<mutex> lock(fMtx);
|
||||
++fNumUnackedMsgs;
|
||||
if (Send(msg, "data", 0) > 0) {
|
||||
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
|
||||
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++fNumUnackedMsgs;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sampler::ResetTask()
|
||||
{
|
||||
// On destruction UnmanagedRegion will try to TODO
|
||||
fRegion.reset();
|
||||
{
|
||||
lock_guard<mutex> lock(fMtx);
|
||||
|
@@ -30,8 +30,8 @@ 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(info) << "Region event: " << info.event
|
||||
<< ", managed: " << info.managed
|
||||
LOG(info) << "Region event: " << info.event << ": "
|
||||
<< (info.managed ? "managed" : "unmanaged")
|
||||
<< ", id: " << info.id
|
||||
<< ", ptr: " << info.ptr
|
||||
<< ", size: " << info.size
|
||||
|
@@ -2,9 +2,14 @@
|
||||
|
||||
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||
|
||||
transport="shmem"
|
||||
msgSize="1000000"
|
||||
|
||||
if [[ $1 =~ ^[0-9]+$ ]]; then
|
||||
if [[ $1 =~ ^[a-z]+$ ]]; then
|
||||
transport=$1
|
||||
fi
|
||||
|
||||
if [[ $2 =~ ^[0-9]+$ ]]; then
|
||||
msgSize=$1
|
||||
fi
|
||||
|
||||
@@ -13,13 +18,13 @@ SAMPLER+=" --id sampler1"
|
||||
SAMPLER+=" --severity debug"
|
||||
SAMPLER+=" --msg-size $msgSize"
|
||||
# SAMPLER+=" --rate 10"
|
||||
SAMPLER+=" --transport shmem"
|
||||
SAMPLER+=" --transport $transport"
|
||||
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://127.0.0.1:7777,sndKernelSize=212992"
|
||||
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
|
||||
xterm -geometry 120x60+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
|
||||
|
||||
SINK="fairmq-ex-region-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --severity debug"
|
||||
SINK+=" --transport shmem"
|
||||
SINK+=" --transport $transport"
|
||||
SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://127.0.0.1:7777,rcvKernelSize=212992"
|
||||
xterm -geometry 80x23+500+0 -hold -e @EX_BIN_DIR@/$SINK &
|
||||
xterm -geometry 120x60+750+0 -hold -e @EX_BIN_DIR@/$SINK &
|
||||
|
@@ -31,6 +31,7 @@ SAMPLER_PID=$!
|
||||
SINK="fairmq-ex-region-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --transport $transport"
|
||||
SINK+=" --severity debug"
|
||||
SINK+=" --session $SESSION"
|
||||
SINK+=" --verbosity veryhigh"
|
||||
SINK+=" --control static --color false"
|
||||
|
@@ -7,10 +7,10 @@
|
||||
################################################################################
|
||||
|
||||
add_library(ExampleReqRepLib STATIC
|
||||
"Client.cxx"
|
||||
"Client.h"
|
||||
"Server.cxx"
|
||||
"Server.h"
|
||||
"Client.cxx"
|
||||
"Client.h"
|
||||
"Server.cxx"
|
||||
"Server.h"
|
||||
)
|
||||
|
||||
target_link_libraries(ExampleReqRepLib PUBLIC FairMQ)
|
||||
@@ -41,12 +41,12 @@ set_tests_properties(Example.ReqRep.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL tru
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-req-rep-client
|
||||
fairmq-ex-req-rep-server
|
||||
TARGETS
|
||||
fairmq-ex-req-rep-client
|
||||
fairmq-ex-req-rep-server
|
||||
|
||||
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
|
||||
@@ -55,7 +55,7 @@ set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-req-rep.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-req-rep.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-req-rep.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-req-rep.sh
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-req-rep.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-req-rep.sh
|
||||
)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2012-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# Copyright (C) 2012-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
@@ -62,6 +62,7 @@ if(BUILD_FAIRMQ OR BUILD_SDK)
|
||||
target_link_libraries(${target}
|
||||
PRIVATE
|
||||
FairLogger::FairLogger
|
||||
Threads::Threads
|
||||
PUBLIC
|
||||
Boost::boost
|
||||
)
|
||||
@@ -145,6 +146,7 @@ if(BUILD_FAIRMQ)
|
||||
# libFairMQ header files #
|
||||
##########################
|
||||
set(FAIRMQ_PUBLIC_HEADER_FILES
|
||||
Device.h
|
||||
DeviceRunner.h
|
||||
EventManager.h
|
||||
FairMQChannel.h
|
||||
@@ -169,14 +171,21 @@ if(BUILD_FAIRMQ)
|
||||
Plugin.h
|
||||
PluginManager.h
|
||||
PluginServices.h
|
||||
runDevice.h
|
||||
runFairMQDevice.h
|
||||
shmem/Monitor.h
|
||||
)
|
||||
|
||||
set(FAIRMQ_PRIVATE_HEADER_FILES
|
||||
devices/BenchmarkSampler.h
|
||||
devices/Merger.h
|
||||
devices/Multiplier.h
|
||||
devices/Proxy.h
|
||||
devices/Sink.h
|
||||
devices/Splitter.h
|
||||
plugins/Builtin.h
|
||||
plugins/config/Config.h
|
||||
plugins/Control.h
|
||||
plugins/control/Control.h
|
||||
shmem/Message.h
|
||||
shmem/Poller.h
|
||||
shmem/UnmanagedRegion.h
|
||||
@@ -223,7 +232,7 @@ if(BUILD_FAIRMQ)
|
||||
Properties.cxx
|
||||
SuboptParser.cxx
|
||||
plugins/config/Config.cxx
|
||||
plugins/Control.cxx
|
||||
plugins/control/Control.cxx
|
||||
MemoryResources.cxx
|
||||
shmem/Monitor.cxx
|
||||
)
|
||||
@@ -243,7 +252,7 @@ if(BUILD_FAIRMQ)
|
||||
# configure files #
|
||||
###################
|
||||
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run/startMQBenchmark.sh.in ${CMAKE_CURRENT_BINARY_DIR}/startMQBenchmark.sh)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/devices/startMQBenchmark.sh.in ${CMAKE_CURRENT_BINARY_DIR}/startMQBenchmark.sh)
|
||||
|
||||
#################################
|
||||
# define libFairMQ build target #
|
||||
@@ -274,6 +283,7 @@ if(BUILD_FAIRMQ)
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
target_compile_definitions(${_target} PRIVATE BUILD_OFI_TRANSPORT)
|
||||
endif()
|
||||
target_compile_definitions(${_target} PUBLIC FAIRMQ_HAS_STD_FILESYSTEM=${FAIRMQ_HAS_STD_FILESYSTEM})
|
||||
|
||||
|
||||
#######################
|
||||
@@ -347,22 +357,22 @@ if(BUILD_FAIRMQ)
|
||||
###############
|
||||
# executables #
|
||||
###############
|
||||
add_executable(fairmq-bsampler run/runBenchmarkSampler.cxx)
|
||||
add_executable(fairmq-bsampler devices/runBenchmarkSampler.cxx)
|
||||
target_link_libraries(fairmq-bsampler FairMQ)
|
||||
|
||||
add_executable(fairmq-merger run/runMerger.cxx)
|
||||
add_executable(fairmq-merger devices/runMerger.cxx)
|
||||
target_link_libraries(fairmq-merger FairMQ)
|
||||
|
||||
add_executable(fairmq-multiplier run/runMultiplier.cxx)
|
||||
add_executable(fairmq-multiplier devices/runMultiplier.cxx)
|
||||
target_link_libraries(fairmq-multiplier FairMQ)
|
||||
|
||||
add_executable(fairmq-proxy run/runProxy.cxx)
|
||||
add_executable(fairmq-proxy devices/runProxy.cxx)
|
||||
target_link_libraries(fairmq-proxy FairMQ)
|
||||
|
||||
add_executable(fairmq-sink run/runSink.cxx)
|
||||
add_executable(fairmq-sink devices/runSink.cxx)
|
||||
target_link_libraries(fairmq-sink FairMQ)
|
||||
|
||||
add_executable(fairmq-splitter run/runSplitter.cxx)
|
||||
add_executable(fairmq-splitter devices/runSplitter.cxx)
|
||||
target_link_libraries(fairmq-splitter FairMQ)
|
||||
|
||||
add_executable(fairmq-shmmonitor shmem/Monitor.cxx shmem/Monitor.h shmem/runMonitor.cxx)
|
||||
@@ -375,6 +385,7 @@ if(BUILD_FAIRMQ)
|
||||
$<$<PLATFORM_ID:Linux>:rt>
|
||||
Boost::boost
|
||||
Boost::date_time
|
||||
$<$<NOT:${FAIRMQ_HAS_STD_FILESYSTEM}>:Boost::filesystem>
|
||||
Boost::program_options
|
||||
FairLogger::FairLogger
|
||||
PicoSHA2
|
||||
@@ -382,9 +393,13 @@ if(BUILD_FAIRMQ)
|
||||
target_include_directories(fairmq-shmmonitor PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
|
||||
)
|
||||
target_compile_definitions(fairmq-shmmonitor PUBLIC FAIRMQ_HAS_STD_FILESYSTEM=${FAIRMQ_HAS_STD_FILESYSTEM})
|
||||
|
||||
add_executable(fairmq-uuid-gen run/runUuidGenerator.cxx)
|
||||
target_link_libraries(fairmq-uuid-gen FairMQ)
|
||||
add_executable(fairmq-uuid-gen tools/runUuidGenerator.cxx)
|
||||
target_link_libraries(fairmq-uuid-gen PUBLIC
|
||||
Boost::program_options
|
||||
Tools
|
||||
)
|
||||
|
||||
|
||||
###########
|
||||
|
21
fairmq/Device.h
Normal file
21
fairmq/Device.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2021 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 FAIR_MQ_DEVICE_H
|
||||
#define FAIR_MQ_DEVICE_H
|
||||
|
||||
#include <FairMQDevice.h>
|
||||
|
||||
namespace fair::mq
|
||||
{
|
||||
|
||||
using Device = ::FairMQDevice;
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
#endif /* FAIR_MQ_DEVICE_H */
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,10 +9,10 @@
|
||||
#ifndef FAIR_MQ_DEVICERUNNER_H
|
||||
#define FAIR_MQ_DEVICERUNNER_H
|
||||
|
||||
#include <fairmq/Device.h>
|
||||
#include <fairmq/EventManager.h>
|
||||
#include <fairmq/PluginManager.h>
|
||||
#include <fairmq/ProgOptions.h>
|
||||
#include <FairMQDevice.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@@ -73,7 +73,7 @@ class DeviceRunner
|
||||
|
||||
std::vector<std::string> fRawCmdLineArgs;
|
||||
fair::mq::ProgOptions fConfig;
|
||||
std::unique_ptr<FairMQDevice> fDevice;
|
||||
std::unique_ptr<Device> fDevice;
|
||||
PluginManager fPluginManager;
|
||||
const bool fPrintLogo;
|
||||
|
||||
|
@@ -486,7 +486,6 @@ void FairMQDevice::RunWrapper()
|
||||
}
|
||||
|
||||
PostRun();
|
||||
|
||||
} catch (const out_of_range& oor) {
|
||||
LOG(error) << "out of range: " << oor.what();
|
||||
LOG(error) << "incorrect/incomplete channel configuration?";
|
||||
@@ -504,17 +503,12 @@ void FairMQDevice::HandleSingleChannelInput()
|
||||
{
|
||||
bool proceed = true;
|
||||
|
||||
if (fMsgInputs.size() > 0)
|
||||
{
|
||||
while (!NewStatePending() && proceed)
|
||||
{
|
||||
if (fMsgInputs.size() > 0) {
|
||||
while (!NewStatePending() && proceed) {
|
||||
proceed = HandleMsgInput(fInputChannelKeys.at(0), fMsgInputs.begin()->second, 0);
|
||||
}
|
||||
}
|
||||
else if (fMultipartInputs.size() > 0)
|
||||
{
|
||||
while (!NewStatePending() && proceed)
|
||||
{
|
||||
} else if (fMultipartInputs.size() > 0) {
|
||||
while (!NewStatePending() && proceed) {
|
||||
proceed = HandleMultipartInput(fInputChannelKeys.at(0), fMultipartInputs.begin()->second, 0);
|
||||
}
|
||||
}
|
||||
@@ -524,75 +518,55 @@ void FairMQDevice::HandleMultipleChannelInput()
|
||||
{
|
||||
// check if more than one transport is used
|
||||
fMultitransportInputs.clear();
|
||||
for (const auto& k : fInputChannelKeys)
|
||||
{
|
||||
for (const auto& k : fInputChannelKeys) {
|
||||
fair::mq::Transport t = fChannels.at(k).at(0).fTransportType;
|
||||
if (fMultitransportInputs.find(t) == fMultitransportInputs.end())
|
||||
{
|
||||
if (fMultitransportInputs.find(t) == fMultitransportInputs.end()) {
|
||||
fMultitransportInputs.insert(pair<fair::mq::Transport, vector<string>>(t, vector<string>()));
|
||||
fMultitransportInputs.at(t).push_back(k);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
fMultitransportInputs.at(t).push_back(k);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& mi : fMsgInputs)
|
||||
{
|
||||
for (auto& i : fChannels.at(mi.first))
|
||||
{
|
||||
for (const auto& mi : fMsgInputs) {
|
||||
for (auto& i : fChannels.at(mi.first)) {
|
||||
i.fMultipart = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& mi : fMultipartInputs)
|
||||
{
|
||||
for (auto& i : fChannels.at(mi.first))
|
||||
{
|
||||
for (const auto& mi : fMultipartInputs) {
|
||||
for (auto& i : fChannels.at(mi.first)) {
|
||||
i.fMultipart = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if more than one transport is used, handle poll of each in a separate thread
|
||||
if (fMultitransportInputs.size() > 1)
|
||||
{
|
||||
if (fMultitransportInputs.size() > 1) {
|
||||
HandleMultipleTransportInput();
|
||||
}
|
||||
else // otherwise poll directly
|
||||
{
|
||||
} else { // otherwise poll directly
|
||||
bool proceed = true;
|
||||
|
||||
FairMQPollerPtr poller(fChannels.at(fInputChannelKeys.at(0)).at(0).fTransportFactory->CreatePoller(fChannels, fInputChannelKeys));
|
||||
|
||||
while (!NewStatePending() && proceed)
|
||||
{
|
||||
while (!NewStatePending() && proceed) {
|
||||
poller->Poll(200);
|
||||
|
||||
// check which inputs are ready and call their data handlers if they are.
|
||||
for (const auto& ch : fInputChannelKeys)
|
||||
{
|
||||
for (unsigned int i = 0; i < fChannels.at(ch).size(); ++i)
|
||||
{
|
||||
if (poller->CheckInput(ch, i))
|
||||
{
|
||||
if (fChannels.at(ch).at(i).fMultipart)
|
||||
{
|
||||
for (const auto& ch : fInputChannelKeys) {
|
||||
for (unsigned int i = 0; i < fChannels.at(ch).size(); ++i) {
|
||||
if (poller->CheckInput(ch, i)) {
|
||||
if (fChannels.at(ch).at(i).fMultipart) {
|
||||
proceed = HandleMultipartInput(ch, fMultipartInputs.at(ch), i);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
proceed = HandleMsgInput(ch, fMsgInputs.at(ch), i);
|
||||
}
|
||||
|
||||
if (!proceed)
|
||||
{
|
||||
if (!proceed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!proceed)
|
||||
{
|
||||
if (!proceed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -606,64 +580,49 @@ void FairMQDevice::HandleMultipleTransportInput()
|
||||
|
||||
fMultitransportProceed = true;
|
||||
|
||||
for (const auto& i : fMultitransportInputs)
|
||||
{
|
||||
for (const auto& i : fMultitransportInputs) {
|
||||
threads.emplace_back(thread(&FairMQDevice::PollForTransport, this, fTransports.at(i.first).get(), i.second));
|
||||
}
|
||||
|
||||
for (thread& t : threads)
|
||||
{
|
||||
for (thread& t : threads) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQDevice::PollForTransport(const FairMQTransportFactory* factory, const vector<string>& channelKeys)
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
FairMQPollerPtr poller(factory->CreatePoller(fChannels, channelKeys));
|
||||
|
||||
while (!NewStatePending() && fMultitransportProceed)
|
||||
{
|
||||
while (!NewStatePending() && fMultitransportProceed) {
|
||||
poller->Poll(500);
|
||||
|
||||
for (const auto& ch : channelKeys)
|
||||
{
|
||||
for (unsigned int i = 0; i < fChannels.at(ch).size(); ++i)
|
||||
{
|
||||
if (poller->CheckInput(ch, i))
|
||||
{
|
||||
for (const auto& ch : channelKeys) {
|
||||
for (unsigned int i = 0; i < fChannels.at(ch).size(); ++i) {
|
||||
if (poller->CheckInput(ch, i)) {
|
||||
lock_guard<mutex> lock(fMultitransportMutex);
|
||||
|
||||
if (!fMultitransportProceed)
|
||||
{
|
||||
if (!fMultitransportProceed) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (fChannels.at(ch).at(i).fMultipart)
|
||||
{
|
||||
if (fChannels.at(ch).at(i).fMultipart) {
|
||||
fMultitransportProceed = HandleMultipartInput(ch, fMultipartInputs.at(ch), i);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
fMultitransportProceed = HandleMsgInput(ch, fMsgInputs.at(ch), i);
|
||||
}
|
||||
|
||||
if (!fMultitransportProceed)
|
||||
{
|
||||
if (!fMultitransportProceed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!fMultitransportProceed)
|
||||
{
|
||||
if (!fMultitransportProceed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
} catch (exception& e) {
|
||||
LOG(error) << "FairMQDevice::PollForTransport() failed: " << e.what() << ", going to ERROR state.";
|
||||
throw runtime_error(tools::ToString("FairMQDevice::PollForTransport() failed: ", e.what(), ", going to ERROR state."));
|
||||
}
|
||||
@@ -673,12 +632,9 @@ bool FairMQDevice::HandleMsgInput(const string& chName, const InputMsgCallback&
|
||||
{
|
||||
unique_ptr<FairMQMessage> input(fChannels.at(chName).at(i).fTransportFactory->CreateMessage());
|
||||
|
||||
if (Receive(input, chName, i) >= 0)
|
||||
{
|
||||
if (Receive(input, chName, i) >= 0) {
|
||||
return callback(input, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -687,12 +643,9 @@ bool FairMQDevice::HandleMultipartInput(const string& chName, const InputMultipa
|
||||
{
|
||||
FairMQParts input;
|
||||
|
||||
if (Receive(input, chName, i) >= 0)
|
||||
{
|
||||
return callback(input, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Receive(input, chName, i) >= 0) {
|
||||
return callback(input, i);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -9,17 +9,17 @@
|
||||
#ifndef FAIRMQDEVICE_H_
|
||||
#define FAIRMQDEVICE_H_
|
||||
|
||||
#include <StateMachine.h>
|
||||
#include <FairMQTransportFactory.h>
|
||||
#include <fairmq/Transports.h>
|
||||
#include <fairmq/StateQueue.h>
|
||||
|
||||
#include <FairMQChannel.h>
|
||||
#include <FairMQLogger.h>
|
||||
#include <FairMQMessage.h>
|
||||
#include <FairMQParts.h>
|
||||
#include <FairMQTransportFactory.h>
|
||||
#include <FairMQUnmanagedRegion.h>
|
||||
#include <FairMQLogger.h>
|
||||
#include <fairmq/ProgOptions.h>
|
||||
#include <fairmq/StateMachine.h>
|
||||
#include <fairmq/StateQueue.h>
|
||||
#include <fairmq/Transports.h>
|
||||
#include <fairmq/tools/Version.h>
|
||||
|
||||
#include <vector>
|
||||
#include <memory> // unique_ptr
|
||||
@@ -34,8 +34,6 @@
|
||||
#include <cstddef>
|
||||
#include <utility> // pair
|
||||
|
||||
#include <fairmq/tools/Version.h>
|
||||
|
||||
using FairMQChannelMap = std::unordered_map<std::string, std::vector<FairMQChannel>>;
|
||||
|
||||
using InputMsgCallback = std::function<bool(FairMQMessagePtr&, int)>;
|
||||
@@ -421,28 +419,64 @@ class FairMQDevice
|
||||
virtual void Reset() {}
|
||||
|
||||
public:
|
||||
/// @brief Request a device state transition
|
||||
/// @param transition state transition
|
||||
///
|
||||
/// The state transition may not happen immediately, but when the current state evaluates the
|
||||
/// pending transition event and terminates. In other words, the device states are scheduled cooperatively.
|
||||
bool ChangeState(const fair::mq::Transition transition) { return fStateMachine.ChangeState(transition); }
|
||||
/// @brief Request a device state transition
|
||||
/// @param transition state transition
|
||||
///
|
||||
/// The state transition may not happen immediately, but when the current state evaluates the
|
||||
/// pending transition event and terminates. In other words, the device states are scheduled cooperatively.
|
||||
bool ChangeState(const std::string& transition) { return fStateMachine.ChangeState(fair::mq::GetTransition(transition)); }
|
||||
|
||||
/// @brief waits for the next state (any) to occur
|
||||
fair::mq::State WaitForNextState() { return fStateQueue.WaitForNext(); }
|
||||
/// @brief waits for the specified state to occur
|
||||
/// @param state state to wait for
|
||||
void WaitForState(fair::mq::State state) { fStateQueue.WaitForState(state); }
|
||||
/// @brief waits for the specified state to occur
|
||||
/// @param state state to wait for
|
||||
void WaitForState(const std::string& state) { WaitForState(fair::mq::GetState(state)); }
|
||||
|
||||
void TransitionTo(const fair::mq::State state);
|
||||
|
||||
/// @brief Subscribe with a callback to state changes
|
||||
/// @param key id to identify your subscription
|
||||
/// @param callback callback (called with the new state as the parameter)
|
||||
///
|
||||
/// The callback is called at the beginning of a new state.
|
||||
/// The callback is called from the thread the state is running in.
|
||||
void SubscribeToStateChange(const std::string& key, std::function<void(const fair::mq::State)> callback) { fStateMachine.SubscribeToStateChange(key, callback); }
|
||||
/// @brief Unsubscribe from state changes
|
||||
/// @param key id (that was used when subscribing)
|
||||
void UnsubscribeFromStateChange(const std::string& key) { fStateMachine.UnsubscribeFromStateChange(key); }
|
||||
|
||||
/// @brief Subscribe with a callback to incoming state transitions
|
||||
/// @param key id to identify your subscription
|
||||
/// @param callback callback (called with the incoming transition as the parameter)
|
||||
/// The callback is called when new transition is initiated.
|
||||
/// The callback is called from the thread that initiates the transition (via ChangeState).
|
||||
void SubscribeToNewTransition(const std::string& key, std::function<void(const fair::mq::Transition)> callback) { fStateMachine.SubscribeToNewTransition(key, callback); }
|
||||
/// @brief Unsubscribe from state transitions
|
||||
/// @param key id (that was used when subscribing)
|
||||
void UnsubscribeFromNewTransition(const std::string& key) { fStateMachine.UnsubscribeFromNewTransition(key); }
|
||||
|
||||
/// Returns true is a new state has been requested, signaling the current handler to stop.
|
||||
/// @brief Returns true if a new state has been requested, signaling the current handler to stop.
|
||||
bool NewStatePending() const { return fStateMachine.NewStatePending(); }
|
||||
|
||||
/// @brief Returns the current state
|
||||
fair::mq::State GetCurrentState() const { return fStateMachine.GetCurrentState(); }
|
||||
/// @brief Returns the name of the current state as a string
|
||||
std::string GetCurrentStateName() const { return fStateMachine.GetCurrentStateName(); }
|
||||
|
||||
/// @brief Returns name of the given state as a string
|
||||
/// @param state state
|
||||
static std::string GetStateName(const fair::mq::State state) { return fair::mq::GetStateName(state); }
|
||||
/// @brief Returns name of the given transition as a string
|
||||
/// @param transition transition
|
||||
static std::string GetTransitionName(const fair::mq::Transition transition) { return fair::mq::GetTransitionName(transition); }
|
||||
|
||||
static constexpr const char* DefaultId = "";
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,8 +9,9 @@
|
||||
#ifndef FAIRMQPOLLER_H_
|
||||
#define FAIRMQPOLLER_H_
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
class FairMQPoller
|
||||
{
|
||||
|
@@ -56,7 +56,7 @@ class FairMQSocket
|
||||
/// If the backend supports it, fills the unsigned integer @a events with the ZMQ_EVENTS value
|
||||
/// DISCLAIMER: this API is experimental and unsupported and might be dropped / refactored in
|
||||
/// the future.
|
||||
virtual void Events(uint32_t* events) = 0;
|
||||
virtual int Events(uint32_t* events) = 0;
|
||||
virtual void SetLinger(const int value) = 0;
|
||||
virtual int GetLinger() const = 0;
|
||||
virtual void SetSndBufSize(const int value) = 0;
|
||||
|
@@ -92,8 +92,8 @@ class FairMQTransportFactory
|
||||
/// @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;
|
||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 0;
|
||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 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
|
||||
@@ -101,8 +101,8 @@ class FairMQTransportFactory
|
||||
/// @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;
|
||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 0;
|
||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, FairMQRegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 0;
|
||||
|
||||
/// @brief Subscribe to region events (creation, destruction, ...)
|
||||
/// @param callback the callback that is called when a region event occurs
|
||||
|
@@ -79,6 +79,7 @@ class FairMQUnmanagedRegion
|
||||
virtual void SetLinger(uint32_t linger) = 0;
|
||||
virtual uint32_t GetLinger() const = 0;
|
||||
|
||||
virtual fair::mq::Transport GetType() const = 0;
|
||||
FairMQTransportFactory* GetTransport() { return fTransport; }
|
||||
void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
|
||||
|
||||
@@ -107,6 +108,19 @@ inline std::ostream& operator<<(std::ostream& os, const FairMQRegionEvent& event
|
||||
namespace fair::mq
|
||||
{
|
||||
|
||||
struct RegionConfig {
|
||||
bool lock;
|
||||
bool zero;
|
||||
|
||||
RegionConfig()
|
||||
: lock(false), zero(false)
|
||||
{}
|
||||
|
||||
RegionConfig(bool l, bool z)
|
||||
: lock(l), zero(z)
|
||||
{}
|
||||
};
|
||||
|
||||
using RegionCallback = FairMQRegionCallback;
|
||||
using RegionBulkCallback = FairMQRegionBulkCallback;
|
||||
using RegionEventCallback = FairMQRegionEventCallback;
|
||||
|
@@ -15,7 +15,7 @@
|
||||
#ifndef FAIR_MQ_MEMORY_RESOURCES_H
|
||||
#define FAIR_MQ_MEMORY_RESOURCES_H
|
||||
|
||||
#include <fairmq/FairMQMessage.h>
|
||||
#include <FairMQMessage.h>
|
||||
class FairMQTransportFactory;
|
||||
|
||||
#include <boost/container/container_fwd.hpp>
|
||||
|
@@ -200,7 +200,19 @@ auto fair::mq::PluginManager::LoadPluginStatic(const string& pluginName) -> void
|
||||
// Load symbol
|
||||
if (fPluginFactories.find(pluginName) == fPluginFactories.end()) {
|
||||
try {
|
||||
LoadSymbols(pluginName, dll::program_location());
|
||||
if ("control" == pluginName) {
|
||||
try {
|
||||
fPluginProgOptions.insert({pluginName, plugins::ControlPluginProgramOptions().value()});
|
||||
}
|
||||
catch (const boost::bad_optional_access& e) { /* just ignore, if no prog options are declared */ }
|
||||
} else if ("config" == pluginName) {
|
||||
try {
|
||||
fPluginProgOptions.insert({pluginName, plugins::ConfigPluginProgramOptions().value()});
|
||||
}
|
||||
catch (const boost::bad_optional_access& e) { /* just ignore, if no prog options are declared */ }
|
||||
} else {
|
||||
LoadSymbols(pluginName, dll::program_location());
|
||||
}
|
||||
fPluginOrder.push_back(pluginName);
|
||||
} catch (boost::system::system_error& e) {
|
||||
throw PluginLoadError(ToString("An error occurred while loading static plugin ", pluginName, ": ", e.what()));
|
||||
@@ -211,7 +223,13 @@ auto fair::mq::PluginManager::LoadPluginStatic(const string& pluginName) -> void
|
||||
auto fair::mq::PluginManager::InstantiatePlugin(const string& pluginName) -> void
|
||||
{
|
||||
if (fPlugins.find(pluginName) == fPlugins.end()) {
|
||||
fPlugins[pluginName] = fPluginFactories[pluginName](*fPluginServices);
|
||||
if ("control" == pluginName) {
|
||||
fPlugins[pluginName] = plugins::Make_control_Plugin(fPluginServices.get());
|
||||
} else if ("config" == pluginName) {
|
||||
fPlugins[pluginName] = plugins::Make_config_Plugin(fPluginServices.get());
|
||||
} else {
|
||||
fPlugins[pluginName] = fPluginFactories[pluginName](*fPluginServices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public License (LGPL) version 3, *
|
||||
@@ -17,8 +17,9 @@
|
||||
#include <fairlogger/Logger.h>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <utility> // make_pair
|
||||
#include <string_view>
|
||||
#include <utility> // make_pair
|
||||
#include <cstring>
|
||||
|
||||
using boost::property_tree::ptree;
|
||||
using namespace std;
|
||||
@@ -83,7 +84,16 @@ Properties SuboptParser(const vector<string>& channelConfig, const string& devic
|
||||
string argString(token);
|
||||
char* subopts = &argString[0];
|
||||
char* value = nullptr;
|
||||
// Find either a : or a =. If we find the former first, we consider what is before it
|
||||
// the channel name
|
||||
char* firstSep = strpbrk(subopts, ":=");
|
||||
if (firstSep && *firstSep == ':') {
|
||||
channelName = std::string_view(subopts, firstSep - subopts);
|
||||
channelProperties.put("name", channelName);
|
||||
subopts = firstSep + 1;
|
||||
}
|
||||
while (subopts && *subopts != 0 && *subopts != ' ') {
|
||||
char* cur = subopts;
|
||||
int subopt = getsubopt(&subopts, (char**)channelOptionKeys, &value);
|
||||
if (subopt == NAME) {
|
||||
channelName = value;
|
||||
@@ -94,6 +104,8 @@ Properties SuboptParser(const vector<string>& channelConfig, const string& devic
|
||||
socketsArray.push_back(make_pair("", socketProperties));
|
||||
} else if (subopt >= 0 && value != nullptr) {
|
||||
channelProperties.put(channelOptionKeys[subopt], value);
|
||||
} else if (subopt == -1) {
|
||||
LOG(warn) << "Ignoring unknown argument in --channel-config: " << cur;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
@@ -60,6 +61,11 @@ try {
|
||||
throw TransportError(tools::ToString("Unknown transport provided: ", transport));
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Transport& transport)
|
||||
{
|
||||
return os << TransportName(transport);
|
||||
}
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
#endif /* FAIR_MQ_TRANSPORTS_H */
|
||||
|
@@ -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-2020 GSI"
|
||||
#define FAIRMQ_COPYRIGHT "2012-2021 GSI"
|
||||
#define FAIRMQ_BUILD_TYPE "@CMAKE_BUILD_TYPE@"
|
||||
|
||||
#endif // FAIR_MQ_VERSION_H
|
||||
|
@@ -1,32 +1,35 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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 FAIRMQBENCHMARKSAMPLER_H_
|
||||
#define FAIRMQBENCHMARKSAMPLER_H_
|
||||
#ifndef FAIR_MQ_BENCHMARKSAMPLER_H
|
||||
#define FAIR_MQ_BENCHMARKSAMPLER_H
|
||||
|
||||
#include "../FairMQLogger.h"
|
||||
#include "FairMQDevice.h"
|
||||
#include "tools/RateLimit.h"
|
||||
#include <fairmq/Device.h>
|
||||
#include <fairmq/tools/RateLimit.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint64_t
|
||||
#include <cstring> // memset
|
||||
#include <fairlogger/Logger.h>
|
||||
#include <string>
|
||||
|
||||
namespace fair::mq
|
||||
{
|
||||
|
||||
/**
|
||||
* Sampler to generate traffic for benchmarking.
|
||||
*/
|
||||
|
||||
class FairMQBenchmarkSampler : public FairMQDevice
|
||||
class BenchmarkSampler : public Device
|
||||
{
|
||||
public:
|
||||
FairMQBenchmarkSampler()
|
||||
BenchmarkSampler()
|
||||
: fMultipart(false)
|
||||
, fMemSet(false)
|
||||
, fNumParts(1)
|
||||
@@ -117,4 +120,6 @@ class FairMQBenchmarkSampler : public FairMQDevice
|
||||
std::string fOutChannelName;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQBENCHMARKSAMPLER_H_ */
|
||||
} // namespace fair::mq
|
||||
|
||||
#endif /* FAIR_MQ_BENCHMARKSAMPLER_H */
|
@@ -1,93 +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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQSink.h
|
||||
*
|
||||
* @since 2013-01-09
|
||||
* @author D. Klein, A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQSINK_H_
|
||||
#define FAIRMQSINK_H_
|
||||
|
||||
#include "../FairMQDevice.h"
|
||||
#include "../FairMQLogger.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
// template<typename OutputPolicy>
|
||||
class FairMQSink : public FairMQDevice //, public OutputPolicy
|
||||
{
|
||||
public:
|
||||
FairMQSink()
|
||||
: fMultipart(false)
|
||||
, fMaxIterations(0)
|
||||
, fNumIterations(0)
|
||||
, fInChannelName()
|
||||
{}
|
||||
|
||||
~FairMQSink() {}
|
||||
|
||||
protected:
|
||||
bool fMultipart;
|
||||
uint64_t fMaxIterations;
|
||||
uint64_t fNumIterations;
|
||||
std::string fInChannelName;
|
||||
|
||||
void InitTask() override
|
||||
{
|
||||
fMultipart = fConfig->GetProperty<bool>("multipart");
|
||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||
fInChannelName = fConfig->GetProperty<std::string>("in-channel");
|
||||
}
|
||||
|
||||
void Run() override
|
||||
{
|
||||
// store the channel reference to avoid traversing the map on every loop iteration
|
||||
FairMQChannel& dataInChannel = fChannels.at(fInChannelName).at(0);
|
||||
|
||||
LOG(info) << "Starting the benchmark and expecting to receive " << fMaxIterations << " messages.";
|
||||
auto tStart = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while (!NewStatePending()) {
|
||||
if (fMultipart) {
|
||||
FairMQParts parts;
|
||||
|
||||
if (dataInChannel.Receive(parts) >= 0) {
|
||||
if (fMaxIterations > 0) {
|
||||
if (fNumIterations >= fMaxIterations) {
|
||||
LOG(info) << "Configured maximum number of iterations reached.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
fNumIterations++;
|
||||
}
|
||||
} else {
|
||||
FairMQMessagePtr msg(dataInChannel.NewMessage());
|
||||
|
||||
if (dataInChannel.Receive(msg) >= 0) {
|
||||
if (fMaxIterations > 0) {
|
||||
if (fNumIterations >= fMaxIterations) {
|
||||
LOG(info) << "Configured maximum number of iterations reached.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
fNumIterations++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.";
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FAIRMQSINK_H_ */
|
@@ -1,36 +1,32 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQMerger.h
|
||||
*
|
||||
* @since 2012-12-06
|
||||
* @author D. Klein, A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQMERGER_H_
|
||||
#define FAIRMQMERGER_H_
|
||||
#ifndef FAIR_MQ_MERGER_H
|
||||
#define FAIR_MQ_MERGER_H
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
#include "../FairMQPoller.h"
|
||||
#include "../FairMQLogger.h"
|
||||
#include <FairMQPoller.h>
|
||||
#include <fairmq/Device.h>
|
||||
|
||||
#include <fairlogger/Logger.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class FairMQMerger : public FairMQDevice
|
||||
namespace fair::mq
|
||||
{
|
||||
|
||||
class Merger : public Device
|
||||
{
|
||||
public:
|
||||
FairMQMerger()
|
||||
Merger()
|
||||
: fMultipart(true)
|
||||
, fInChannelName("data-in")
|
||||
, fOutChannelName("data-out")
|
||||
{}
|
||||
~FairMQMerger() {}
|
||||
|
||||
protected:
|
||||
bool fMultipart;
|
||||
@@ -112,4 +108,6 @@ class FairMQMerger : public FairMQDevice
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FAIRMQMERGER_H_ */
|
||||
} // namespace fair::mq
|
||||
|
||||
#endif /* FAIR_MQ_MERGER_H */
|
@@ -1,29 +1,31 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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 FAIRMQMULTIPLIER_H_
|
||||
#define FAIRMQMULTIPLIER_H_
|
||||
#ifndef FAIR_MQ_MULTIPLIER_H
|
||||
#define FAIR_MQ_MULTIPLIER_H
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
#include <fairmq/Device.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class FairMQMultiplier : public FairMQDevice
|
||||
namespace fair::mq
|
||||
{
|
||||
|
||||
class Multiplier : public Device
|
||||
{
|
||||
public:
|
||||
FairMQMultiplier()
|
||||
Multiplier()
|
||||
: fMultipart(true)
|
||||
, fNumOutputs(0)
|
||||
, fInChannelName()
|
||||
, fOutChannelNames()
|
||||
{}
|
||||
~FairMQMultiplier() {}
|
||||
|
||||
protected:
|
||||
bool fMultipart;
|
||||
@@ -39,9 +41,9 @@ class FairMQMultiplier : public FairMQDevice
|
||||
fNumOutputs = fChannels.at(fOutChannelNames.at(0)).size();
|
||||
|
||||
if (fMultipart) {
|
||||
OnData(fInChannelName, &FairMQMultiplier::HandleMultipartData);
|
||||
OnData(fInChannelName, &Multiplier::HandleMultipartData);
|
||||
} else {
|
||||
OnData(fInChannelName, &FairMQMultiplier::HandleSingleData);
|
||||
OnData(fInChannelName, &Multiplier::HandleSingleData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,4 +109,6 @@ class FairMQMultiplier : public FairMQDevice
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FAIRMQMULTIPLIER_H_ */
|
||||
} // namespace fair::mq
|
||||
|
||||
#endif /* FAIR_MQ_MULTIPLIER_H */
|
@@ -1,33 +1,29 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQProxy.h
|
||||
*
|
||||
* @since 2013-10-02
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQPROXY_H_
|
||||
#define FAIRMQPROXY_H_
|
||||
#ifndef FAIR_MQ_PROXY_H
|
||||
#define FAIR_MQ_PROXY_H
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
#include <fairmq/Device.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
class FairMQProxy : public FairMQDevice
|
||||
namespace fair::mq
|
||||
{
|
||||
|
||||
class Proxy : public Device
|
||||
{
|
||||
public:
|
||||
FairMQProxy()
|
||||
Proxy()
|
||||
: fMultipart(true)
|
||||
, fInChannelName()
|
||||
, fOutChannelName()
|
||||
{}
|
||||
~FairMQProxy() {}
|
||||
|
||||
protected:
|
||||
bool fMultipart;
|
||||
@@ -73,4 +69,6 @@ class FairMQProxy : public FairMQDevice
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FAIRMQPROXY_H_ */
|
||||
} // namespace fair::mq
|
||||
|
||||
#endif /* FAIR_MQ_PROXY_H */
|
@@ -2,9 +2,9 @@
|
||||
|
||||
With FairMQ several generic devices are provided:
|
||||
|
||||
- **FairMQBenchmarkSampler**: generates random data of configurable size and at configurable rate and sends it out on an output channel.
|
||||
- **FairMQSink**: receives messages on the input channel and simply discards them.
|
||||
- **FairMQMerger**: receives data from multiple input channels and forwards it to a single output channel.
|
||||
- **FairMQSplitter**: receives messages on a single input channels and round-robins them among multiple output channels (which can have different socket types).
|
||||
- **FairMQMultiplier**: receives data from a single input channel and multiplies (copies) it to two or more output channels.
|
||||
- **FairMQProxy**: connects input channel to output channel, where both can have different socket types and multiple peers.
|
||||
- **BenchmarkSampler**: generates random data of configurable size and at configurable rate and sends it out on an output channel.
|
||||
- **Sink**: receives messages on the input channel and simply discards them.
|
||||
- **Merger**: receives data from multiple input channels and forwards it to a single output channel.
|
||||
- **Splitter**: receives messages on a single input channels and round-robins them among multiple output channels (which can have different socket types).
|
||||
- **Multiplier**: receives data from a single input channel and multiplies (copies) it to two or more output channels.
|
||||
- **Proxy**: connects input channel to output channel, where both can have different socket types and multiple peers.
|
||||
|
146
fairmq/devices/Sink.h
Normal file
146
fairmq/devices/Sink.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2021 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 FAIR_MQ_SINK_H
|
||||
#define FAIR_MQ_SINK_H
|
||||
|
||||
#include <FairMQPoller.h>
|
||||
#include <fairmq/Device.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <fairlogger/Logger.h>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace fair::mq
|
||||
{
|
||||
|
||||
class Sink : public Device
|
||||
{
|
||||
public:
|
||||
Sink()
|
||||
: fMultipart(false)
|
||||
, fMaxIterations(0)
|
||||
, fNumIterations(0)
|
||||
, fMaxFileSize(0)
|
||||
, fBytesWritten(0)
|
||||
, fInChannelName()
|
||||
, fOutFilename()
|
||||
{}
|
||||
|
||||
protected:
|
||||
bool fMultipart;
|
||||
uint64_t fMaxIterations;
|
||||
uint64_t fNumIterations;
|
||||
uint64_t fMaxFileSize;
|
||||
uint64_t fBytesWritten;
|
||||
std::string fInChannelName;
|
||||
std::string fOutFilename;
|
||||
std::fstream fOutputFile;
|
||||
|
||||
void InitTask() override
|
||||
{
|
||||
fMultipart = fConfig->GetProperty<bool>("multipart");
|
||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||
fMaxFileSize = fConfig->GetProperty<uint64_t>("max-file-size");
|
||||
fInChannelName = fConfig->GetProperty<std::string>("in-channel");
|
||||
fOutFilename = fConfig->GetProperty<std::string>("out-filename");
|
||||
|
||||
fBytesWritten = 0;
|
||||
}
|
||||
|
||||
void Run() override
|
||||
{
|
||||
// store the channel reference to avoid traversing the map on every loop iteration
|
||||
FairMQChannel& dataInChannel = fChannels.at(fInChannelName).at(0);
|
||||
|
||||
LOG(info) << "Starting sink and expecting to receive " << fMaxIterations << " messages.";
|
||||
auto tStart = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (!fOutFilename.empty()) {
|
||||
LOG(debug) << "Incoming messages will be written to file: " << fOutFilename;
|
||||
if (fMaxFileSize != 0) {
|
||||
LOG(debug) << "File output will stop after " << fMaxFileSize << " bytes";
|
||||
} else {
|
||||
LOG(debug) << "ATTENTION: --max-file-size is 0 - output file will continue to grow until sink is stopped";
|
||||
}
|
||||
|
||||
fOutputFile.open(fOutFilename, std::ios::out | std::ios::binary);
|
||||
if (!fOutputFile) {
|
||||
LOG(error) << "Could not open '" << fOutFilename;
|
||||
throw std::runtime_error(fair::mq::tools::ToString("Could not open '", fOutFilename));
|
||||
}
|
||||
}
|
||||
|
||||
while (!NewStatePending()) {
|
||||
if (fMultipart) {
|
||||
FairMQParts parts;
|
||||
if (dataInChannel.Receive(parts) < 0) {
|
||||
continue;
|
||||
}
|
||||
if (fOutputFile.is_open()) {
|
||||
for (const auto& part : parts) {
|
||||
WriteToFile(static_cast<const char*>(part->GetData()), part->GetSize());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FairMQMessagePtr msg(dataInChannel.NewMessage());
|
||||
if (dataInChannel.Receive(msg) < 0) {
|
||||
continue;
|
||||
}
|
||||
if (fOutputFile.is_open()) {
|
||||
WriteToFile(static_cast<const char*>(msg->GetData()), msg->GetSize());
|
||||
}
|
||||
}
|
||||
|
||||
if (fMaxFileSize > 0 && fBytesWritten >= fMaxFileSize) {
|
||||
LOG(info) << "Written " << fBytesWritten << " bytes, stopping...";
|
||||
break;
|
||||
}
|
||||
if (fMaxIterations > 0) {
|
||||
if (fNumIterations >= fMaxIterations) {
|
||||
LOG(info) << "Configured maximum number of iterations reached.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
fNumIterations++;
|
||||
}
|
||||
|
||||
if (fOutputFile.is_open()) {
|
||||
fOutputFile.flush();
|
||||
fOutputFile.close();
|
||||
}
|
||||
|
||||
auto tEnd = std::chrono::high_resolution_clock::now();
|
||||
auto ms = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
|
||||
LOG(info) << "Received " << fNumIterations << " messages in " << ms << "ms.";
|
||||
if (!fOutFilename.empty()) {
|
||||
auto sec = std::chrono::duration<double>(tEnd - tStart).count();
|
||||
LOG(info) << "Closed '" << fOutFilename << "' after writing " << fBytesWritten << " bytes."
|
||||
<< "(" << (fBytesWritten / (1000. * 1000.)) / sec << " MB/s)";
|
||||
}
|
||||
|
||||
LOG(info) << "Leaving RUNNING state.";
|
||||
}
|
||||
|
||||
void WriteToFile(const char* ptr, size_t size)
|
||||
{
|
||||
fOutputFile.write(ptr, size);
|
||||
if (fOutputFile.bad()) {
|
||||
LOG(error) << "failed writing to file";
|
||||
throw std::runtime_error("failed writing to file");
|
||||
}
|
||||
fBytesWritten += size;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
#endif /* FAIR_MQ_SINK_H */
|
@@ -1,35 +1,31 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQSplitter.h
|
||||
*
|
||||
* @since 2012-12-06
|
||||
* @author D. Klein, A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQSPLITTER_H_
|
||||
#define FAIRMQSPLITTER_H_
|
||||
#ifndef FAIR_MQ_SPLITTER_H
|
||||
#define FAIR_MQ_SPLITTER_H
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
#include <fairmq/Device.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
class FairMQSplitter : public FairMQDevice
|
||||
namespace fair::mq
|
||||
{
|
||||
|
||||
class Splitter : public Device
|
||||
{
|
||||
public:
|
||||
FairMQSplitter()
|
||||
Splitter()
|
||||
: fMultipart(true)
|
||||
, fNumOutputs(0)
|
||||
, fDirection(0)
|
||||
, fInChannelName()
|
||||
, fOutChannelName()
|
||||
{}
|
||||
~FairMQSplitter() {}
|
||||
|
||||
protected:
|
||||
bool fMultipart;
|
||||
@@ -47,9 +43,9 @@ class FairMQSplitter : public FairMQDevice
|
||||
fDirection = 0;
|
||||
|
||||
if (fMultipart) {
|
||||
OnData(fInChannelName, &FairMQSplitter::HandleData<FairMQParts>);
|
||||
OnData(fInChannelName, &Splitter::HandleData<FairMQParts>);
|
||||
} else {
|
||||
OnData(fInChannelName, &FairMQSplitter::HandleData<FairMQMessagePtr>);
|
||||
OnData(fInChannelName, &Splitter::HandleData<FairMQMessagePtr>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,4 +62,6 @@ class FairMQSplitter : public FairMQDevice
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FAIRMQSPLITTER_H_ */
|
||||
} // namespace fair::mq
|
||||
|
||||
#endif /* FAIR_MQ_SPLITTER_H */
|
@@ -1,13 +1,13 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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 <devices/FairMQBenchmarkSampler.h>
|
||||
#include <fairmq/devices/BenchmarkSampler.h>
|
||||
#include <fairmq/runDevice.h>
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
@@ -24,7 +24,7 @@ void addCustomOptions(bpo::options_description& options)
|
||||
("msg-rate", bpo::value<float>()->default_value(0), "Msg rate limit in maximum number of messages per second");
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /* config */)
|
||||
std::unique_ptr<fair::mq::Device> getDevice(const fair::mq::ProgOptions& /* config */)
|
||||
{
|
||||
return new FairMQBenchmarkSampler();
|
||||
return std::make_unique<fair::mq::BenchmarkSampler>();
|
||||
}
|
@@ -1,13 +1,13 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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 <devices/FairMQMerger.h>
|
||||
#include <fairmq/devices/Merger.h>
|
||||
#include <fairmq/runDevice.h>
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
@@ -19,7 +19,7 @@ void addCustomOptions(bpo::options_description& options)
|
||||
("multipart", bpo::value<bool>()->default_value(true), "Handle multipart payloads");
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
|
||||
std::unique_ptr<fair::mq::Device> getDevice(const fair::mq::ProgOptions& /*config*/)
|
||||
{
|
||||
return new FairMQMerger();
|
||||
return std::make_unique<fair::mq::Merger>();
|
||||
}
|
@@ -1,13 +1,13 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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 <devices/FairMQMultiplier.h>
|
||||
#include <fairmq/devices/Multiplier.h>
|
||||
#include <fairmq/runDevice.h>
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
@@ -19,7 +19,7 @@ void addCustomOptions(bpo::options_description& options)
|
||||
("multipart", bpo::value<bool>()->default_value(true), "Handle multipart payloads");
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
|
||||
std::unique_ptr<fair::mq::Device> getDevice(const fair::mq::ProgOptions& /*config*/)
|
||||
{
|
||||
return new FairMQMultiplier();
|
||||
return std::make_unique<fair::mq::Multiplier>();
|
||||
}
|
@@ -1,13 +1,13 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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 <devices/FairMQProxy.h>
|
||||
#include <fairmq/devices/Proxy.h>
|
||||
#include <fairmq/runDevice.h>
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
@@ -19,7 +19,7 @@ void addCustomOptions(bpo::options_description& options)
|
||||
("multipart", bpo::value<bool>()->default_value(true), "Handle multipart payloads");
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
|
||||
std::unique_ptr<fair::mq::Device> getDevice(const fair::mq::ProgOptions& /*config*/)
|
||||
{
|
||||
return new FairMQProxy();
|
||||
return std::make_unique<fair::mq::Proxy>();
|
||||
}
|
@@ -1,13 +1,13 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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 <devices/FairMQSink.h>
|
||||
#include <fairmq/devices/Sink.h>
|
||||
#include <fairmq/runDevice.h>
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
@@ -15,11 +15,13 @@ void addCustomOptions(bpo::options_description& options)
|
||||
{
|
||||
options.add_options()
|
||||
("in-channel", bpo::value<std::string>()->default_value("data"), "Name of the input channel")
|
||||
("out-filename", bpo::value<std::string>()->default_value(""), "Write incoming message buffers to the specified file")
|
||||
("max-file-size", bpo::value<uint64_t>()->default_value(2000000000), "Maximum file size for the file output (0 - unlimited)")
|
||||
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Number of run iterations (0 - infinite)")
|
||||
("multipart", bpo::value<bool>()->default_value(false), "Handle multipart payloads");
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
|
||||
std::unique_ptr<fair::mq::Device> getDevice(const fair::mq::ProgOptions& /*config*/)
|
||||
{
|
||||
return new FairMQSink();
|
||||
return std::make_unique<fair::mq::Sink>();
|
||||
}
|
@@ -1,13 +1,13 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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 <devices/FairMQSplitter.h>
|
||||
#include <fairmq/devices/Splitter.h>
|
||||
#include <fairmq/runDevice.h>
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
@@ -19,7 +19,7 @@ void addCustomOptions(bpo::options_description& options)
|
||||
("multipart", bpo::value<bool>()->default_value(true), "Handle multipart payloads");
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
|
||||
std::unique_ptr<fair::mq::Device> getDevice(const fair::mq::ProgOptions& /*config*/)
|
||||
{
|
||||
return new FairMQSplitter();
|
||||
return std::make_unique<fair::mq::Splitter>();
|
||||
}
|
@@ -41,7 +41,7 @@ class Socket final : public fair::mq::Socket
|
||||
|
||||
auto GetId() const -> std::string override { return fId; }
|
||||
|
||||
auto Events(uint32_t *events) -> void override { *events = 0; }
|
||||
auto Events(uint32_t *events) -> int override { *events = 0; return -1; }
|
||||
auto Bind(const std::string& address) -> bool override;
|
||||
auto Connect(const std::string& address) -> bool override;
|
||||
|
||||
|
@@ -92,22 +92,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 */) -> UnmanagedRegionPtr
|
||||
auto TransportFactory::CreateUnmanagedRegion(const size_t /*size*/, FairMQRegionCallback /*callback*/, const std::string& /* path = "" */, int /* flags = 0 */, fair::mq::RegionConfig /* cfg = fair::mq::RegionConfig() */) -> 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
|
||||
auto TransportFactory::CreateUnmanagedRegion(const size_t /*size*/, FairMQRegionBulkCallback /*callback*/, const std::string& /* path = "" */, int /* flags = 0 */, fair::mq::RegionConfig /* cfg = fair::mq::RegionConfig() */) -> 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
|
||||
auto TransportFactory::CreateUnmanagedRegion(const size_t /*size*/, const int64_t /*userFlags*/, FairMQRegionCallback /*callback*/, const std::string& /* path = "" */, int /* flags = 0 */, fair::mq::RegionConfig /* cfg = fair::mq::RegionConfig() */) -> 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
|
||||
auto TransportFactory::CreateUnmanagedRegion(const size_t /*size*/, const int64_t /*userFlags*/, FairMQRegionBulkCallback /*callback*/, const std::string& /* path = "" */, int /* flags = 0 */, fair::mq::RegionConfig /* cfg = fair::mq::RegionConfig() */) -> UnmanagedRegionPtr
|
||||
{
|
||||
throw runtime_error{"Not yet implemented UMR."};
|
||||
}
|
||||
|
@@ -44,10 +44,10 @@ 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, 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;
|
||||
auto CreateUnmanagedRegion(const size_t size, RegionCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) -> UnmanagedRegionPtr override;
|
||||
auto CreateUnmanagedRegion(const size_t size, RegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) -> UnmanagedRegionPtr override;
|
||||
auto CreateUnmanagedRegion(const size_t size, int64_t userFlags, RegionCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) -> UnmanagedRegionPtr override;
|
||||
auto CreateUnmanagedRegion(const size_t size, int64_t userFlags, RegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) -> 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; }
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,4 +9,4 @@
|
||||
// List of all builtin plugin headers (the ones which call REGISTER_FAIRMQ_PLUGIN macro)
|
||||
|
||||
#include <fairmq/plugins/config/Config.h>
|
||||
#include <fairmq/plugins/Control.h>
|
||||
#include <fairmq/plugins/control/Control.h>
|
||||
|
@@ -71,6 +71,7 @@ Plugin::ProgOptions ConfigPluginProgramOptions()
|
||||
("shm-zero-segment", po::value<bool >()->default_value(false), "Shared memory: zero the shared memory segment memory after initialization.")
|
||||
("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.")
|
||||
("shm-no-cleanup", po::value<bool >()->default_value(false), "Shared memory: do not cleanup the memory when last device leaves.")
|
||||
("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.")
|
||||
|
59
fairmq/runDevice.h
Normal file
59
fairmq/runDevice.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017-2021 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 <fairmq/DeviceRunner.h>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <memory>
|
||||
|
||||
// to be implemented by the user to return a child class of FairMQDevice
|
||||
std::unique_ptr<fair::mq::Device> getDevice(const fair::mq::ProgOptions& config);
|
||||
|
||||
// to be implemented by the user to add custom command line options (or just with empty body)
|
||||
void addCustomOptions(boost::program_options::options_description&);
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
using namespace fair::mq;
|
||||
using namespace fair::mq::hooks;
|
||||
|
||||
try {
|
||||
DeviceRunner runner(argc, argv);
|
||||
|
||||
// runner.AddHook<LoadPlugins>([](DeviceRunner& r){
|
||||
// // for example:
|
||||
// r.fPluginManager->SetSearchPaths({"/lib", "/lib/plugins"});
|
||||
// r.fPluginManager->LoadPlugin("asdf");
|
||||
// });
|
||||
|
||||
runner.AddHook<SetCustomCmdLineOptions>([](DeviceRunner& r){
|
||||
boost::program_options::options_description customOptions("Custom options");
|
||||
addCustomOptions(customOptions);
|
||||
r.fConfig.AddToCmdLineOptions(customOptions);
|
||||
});
|
||||
|
||||
// runner.AddHook<ModifyRawCmdLineArgs>([](DeviceRunner& r){
|
||||
// // for example:
|
||||
// r.fRawCmdLineArgs.push_back("--blubb");
|
||||
// });
|
||||
|
||||
runner.AddHook<InstantiateDevice>([](DeviceRunner& r){
|
||||
r.fDevice = getDevice(r.fConfig);
|
||||
});
|
||||
|
||||
return runner.Run();
|
||||
|
||||
// Run with builtin catch all exception handler, just:
|
||||
// return runner.RunWithExceptionHandlers();
|
||||
} catch (std::exception& e) {
|
||||
LOG(error) << "Uncaught exception reached the top of main: " << e.what();
|
||||
return 1;
|
||||
} catch (...) {
|
||||
LOG(error) << "Uncaught exception reached the top of main.";
|
||||
return 1;
|
||||
}
|
||||
}
|
@@ -65,7 +65,10 @@ struct DDSEnvironment::Impl
|
||||
" 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());
|
||||
auto rc(std::system(cmd.str().c_str()));
|
||||
if (rc != 0) {
|
||||
LOG(warn) << "DDSEnvironment::SetupConfigHome failed";
|
||||
}
|
||||
}
|
||||
|
||||
auto SetupPath() -> void
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <picosha2.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <functional> // std::equal_to
|
||||
|
||||
@@ -90,6 +91,17 @@ struct SegmentInfo
|
||||
AllocationAlgorithm fAllocationAlgorithm;
|
||||
};
|
||||
|
||||
struct SessionInfo
|
||||
{
|
||||
SessionInfo(const char* sessionName, int creatorId, const VoidAlloc& alloc)
|
||||
: fSessionName(sessionName, alloc)
|
||||
, fCreatorId(creatorId)
|
||||
{}
|
||||
|
||||
Str fSessionName;
|
||||
int fCreatorId;
|
||||
};
|
||||
|
||||
using Uint16SegmentInfoPairAlloc = boost::interprocess::allocator<std::pair<const uint16_t, SegmentInfo>, SegmentManager>;
|
||||
using Uint16SegmentInfoHashMap = boost::unordered_map<uint16_t, SegmentInfo, boost::hash<uint16_t>, std::equal_to<uint16_t>, Uint16SegmentInfoPairAlloc>;
|
||||
// using Uint16SegmentInfoMap = boost::interprocess::map<uint16_t, SegmentInfo, std::less<uint16_t>, Uint16SegmentInfoPairAlloc>;
|
||||
@@ -103,6 +115,15 @@ struct DeviceCounter
|
||||
std::atomic<unsigned int> fCount;
|
||||
};
|
||||
|
||||
struct EventCounter
|
||||
{
|
||||
EventCounter(uint64_t c)
|
||||
: fCount(c)
|
||||
{}
|
||||
|
||||
std::atomic<uint64_t> fCount;
|
||||
};
|
||||
|
||||
struct RegionCounter
|
||||
{
|
||||
RegionCounter(uint16_t c)
|
||||
@@ -185,15 +206,30 @@ struct RegionBlock
|
||||
|
||||
// find id for unique shmem name:
|
||||
// a hash of user id + session id, truncated to 8 characters (to accommodate for name size limit on some systems (MacOS)).
|
||||
inline std::string buildShmIdFromSessionIdAndUserId(const std::string& sessionId)
|
||||
inline std::string makeShmIdStr(const std::string& sessionId, const std::string& userId)
|
||||
{
|
||||
std::string seed((std::to_string(geteuid()) + sessionId));
|
||||
std::string seed(userId + sessionId);
|
||||
// generate a 8-digit hex value out of sha256 hash
|
||||
std::vector<unsigned char> hash(4);
|
||||
picosha2::hash256(seed.begin(), seed.end(), hash.begin(), hash.end());
|
||||
std::string shmId = picosha2::bytes_to_hex_string(hash.begin(), hash.end());
|
||||
|
||||
return shmId;
|
||||
return picosha2::bytes_to_hex_string(hash.begin(), hash.end());
|
||||
}
|
||||
|
||||
inline std::string makeShmIdStr(const std::string& sessionId)
|
||||
{
|
||||
return makeShmIdStr(sessionId, std::to_string(geteuid()));
|
||||
}
|
||||
|
||||
inline uint64_t makeShmIdUint64(const std::string& sessionId)
|
||||
{
|
||||
std::string shmId = makeShmIdStr(sessionId);
|
||||
uint64_t id = 0;
|
||||
std::stringstream ss;
|
||||
ss << std::hex << shmId;
|
||||
ss >> id;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
struct SegmentSize : public boost::static_visitor<size_t>
|
||||
|
@@ -44,8 +44,12 @@
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <utility> // pair
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <unistd.h> // getuid
|
||||
#include <sys/types.h> // getuid
|
||||
|
||||
#include <sys/mman.h> // mlock
|
||||
|
||||
namespace fair::mq::shmem
|
||||
@@ -54,31 +58,38 @@ namespace fair::mq::shmem
|
||||
class Manager
|
||||
{
|
||||
public:
|
||||
Manager(std::string shmId, std::string deviceId, size_t size, const ProgOptions* config)
|
||||
: fShmId(std::move(shmId))
|
||||
Manager(const std::string& sessionName, std::string deviceId, size_t size, const ProgOptions* config)
|
||||
: fShmId64(makeShmIdUint64(sessionName))
|
||||
, fShmId(makeShmIdStr(sessionName))
|
||||
, fSegmentId(config ? config->GetProperty<uint16_t>("shm-segment-id", 0) : 0)
|
||||
, fDeviceId(std::move(deviceId))
|
||||
, fSegments()
|
||||
, fManagementSegment(boost::interprocess::open_or_create, std::string("fmq_" + fShmId + "_mng").c_str(), 6553600)
|
||||
, fShmVoidAlloc(fManagementSegment.get_segment_manager())
|
||||
, fShmMtx(boost::interprocess::open_or_create, std::string("fmq_" + fShmId + "_mtx").c_str())
|
||||
, fRegionEventsCV(boost::interprocess::open_or_create, std::string("fmq_" + fShmId + "_cv").c_str())
|
||||
, fRegionEventsShmCV(boost::interprocess::open_or_create, std::string("fmq_" + fShmId + "_cv").c_str())
|
||||
, fRegionEventsSubscriptionActive(false)
|
||||
, fNumObservedEvents(0)
|
||||
, fDeviceCounter(nullptr)
|
||||
, fEventCounter(nullptr)
|
||||
, fShmSegments(nullptr)
|
||||
, fShmRegions(nullptr)
|
||||
, fInterrupted(false)
|
||||
, fMsgCounter(0)
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
, fMsgDebug(nullptr)
|
||||
, fShmMsgCounters(nullptr)
|
||||
, fMsgCounterNew(0)
|
||||
, fMsgCounterDelete(0)
|
||||
#endif
|
||||
, fHeartbeatThread()
|
||||
, fSendHeartbeats(true)
|
||||
, fThrowOnBadAlloc(config ? config->GetProperty<bool>("shm-throw-bad-alloc", true) : true)
|
||||
, fNoCleanup(config ? config->GetProperty<bool>("shm-no-cleanup", false) : false)
|
||||
{
|
||||
using namespace boost::interprocess;
|
||||
|
||||
LOG(debug) << "Generated shmid '" << fShmId << "' out of session id '" << sessionName << "'.";
|
||||
|
||||
bool mlockSegment = false;
|
||||
bool zeroSegment = false;
|
||||
bool autolaunchMonitor = false;
|
||||
@@ -93,15 +104,36 @@ class Manager
|
||||
}
|
||||
|
||||
if (autolaunchMonitor) {
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(fShmMtx);
|
||||
StartMonitor(fShmId);
|
||||
}
|
||||
|
||||
fHeartbeatThread = std::thread(&Manager::SendHeartbeats, this);
|
||||
|
||||
{
|
||||
std::stringstream ss;
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(fShmMtx);
|
||||
|
||||
fShmSegments = fManagementSegment.find_or_construct<Uint16SegmentInfoHashMap>(unique_instance)(fShmVoidAlloc);
|
||||
|
||||
SessionInfo* sessionInfo = fManagementSegment.find<SessionInfo>(unique_instance).first;
|
||||
if (sessionInfo) {
|
||||
LOG(debug) << "session info found, name: " << sessionInfo->fSessionName << ", creator id: " << sessionInfo->fCreatorId;
|
||||
} else {
|
||||
LOG(debug) << "no session info found, creating and initializing";
|
||||
sessionInfo = fManagementSegment.construct<SessionInfo>(unique_instance)(sessionName.c_str(), geteuid(), fShmVoidAlloc);
|
||||
LOG(debug) << "initialized session info, name: " << sessionInfo->fSessionName << ", creator id: " << sessionInfo->fCreatorId;
|
||||
}
|
||||
|
||||
fEventCounter = fManagementSegment.find<EventCounter>(unique_instance).first;
|
||||
if (fEventCounter) {
|
||||
LOG(debug) << "event counter found: " << fEventCounter->fCount;
|
||||
} else {
|
||||
LOG(debug) << "no event counter found, creating one and initializing with 0";
|
||||
fEventCounter = fManagementSegment.construct<EventCounter>(unique_instance)(0);
|
||||
LOG(debug) << "initialized event counter with: " << fEventCounter->fCount;
|
||||
}
|
||||
|
||||
try {
|
||||
auto it = fShmSegments->find(fSegmentId);
|
||||
if (it == fShmSegments->end()) {
|
||||
@@ -114,6 +146,7 @@ class Manager
|
||||
fShmSegments->emplace(fSegmentId, AllocationAlgorithm::simple_seq_fit);
|
||||
}
|
||||
ss << "Created ";
|
||||
(fEventCounter->fCount)++;
|
||||
} else {
|
||||
// found segment with the given id, opening
|
||||
if (it->second.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
||||
@@ -132,31 +165,31 @@ class Manager
|
||||
ss << "Opened ";
|
||||
}
|
||||
ss << "shared memory segment '" << "fmq_" << fShmId << "_m_" << fSegmentId << "'."
|
||||
<< " Size: " << boost::apply_visitor(SegmentSize{}, fSegments.at(fSegmentId)) << " bytes."
|
||||
<< " Available: " << boost::apply_visitor(SegmentFreeMemory{}, fSegments.at(fSegmentId)) << " bytes."
|
||||
<< " Size: " << boost::apply_visitor(SegmentSize(), fSegments.at(fSegmentId)) << " bytes."
|
||||
<< " Available: " << boost::apply_visitor(SegmentFreeMemory(), fSegments.at(fSegmentId)) << " bytes."
|
||||
<< " Allocation algorithm: " << allocationAlgorithm;
|
||||
LOG(debug) << ss.str();
|
||||
} catch(interprocess_exception& bie) {
|
||||
LOG(error) << "something went wrong: " << bie.what();
|
||||
LOG(error) << "Failed to create/open shared memory segment (" << "fmq_" << fShmId << "_m_" << fSegmentId << "): " << bie.what();
|
||||
throw std::runtime_error(tools::ToString("Failed to create/open shared memory segment (", "fmq_", fShmId, "_m_", fSegmentId, "): ", bie.what()));
|
||||
}
|
||||
|
||||
if (mlockSegment) {
|
||||
LOG(debug) << "Locking the managed segment memory pages...";
|
||||
if (mlock(boost::apply_visitor(SegmentAddress{}, fSegments.at(fSegmentId)), boost::apply_visitor(SegmentSize{}, fSegments.at(fSegmentId))) == -1) {
|
||||
if (mlock(boost::apply_visitor(SegmentAddress(), fSegments.at(fSegmentId)), boost::apply_visitor(SegmentSize(), fSegments.at(fSegmentId))) == -1) {
|
||||
LOG(error) << "Could not lock the managed segment memory. Code: " << errno << ", reason: " << strerror(errno);
|
||||
}
|
||||
LOG(debug) << "Successfully locked the managed segment memory pages.";
|
||||
}
|
||||
if (zeroSegment) {
|
||||
LOG(debug) << "Zeroing the managed segment free memory...";
|
||||
boost::apply_visitor(SegmentMemoryZeroer{}, fSegments.at(fSegmentId));
|
||||
boost::apply_visitor(SegmentMemoryZeroer(), fSegments.at(fSegmentId));
|
||||
LOG(debug) << "Successfully zeroed the managed segment free memory.";
|
||||
}
|
||||
|
||||
fShmRegions = fManagementSegment.find_or_construct<Uint16RegionInfoHashMap>(unique_instance)(fShmVoidAlloc);
|
||||
|
||||
fDeviceCounter = fManagementSegment.find<DeviceCounter>(unique_instance).first;
|
||||
|
||||
if (fDeviceCounter) {
|
||||
LOG(debug) << "device counter found, with value of " << fDeviceCounter->fCount << ". incrementing.";
|
||||
(fDeviceCounter->fCount)++;
|
||||
@@ -172,8 +205,6 @@ class Manager
|
||||
fShmMsgCounters = fManagementSegment.find_or_construct<Uint16MsgCounterHashMap>(unique_instance)(fShmVoidAlloc);
|
||||
#endif
|
||||
}
|
||||
|
||||
fHeartbeatThread = std::thread(&Manager::SendHeartbeats, this);
|
||||
}
|
||||
|
||||
Manager() = delete;
|
||||
@@ -199,8 +230,15 @@ class Manager
|
||||
|
||||
boost::filesystem::path p = boost::process::search_path("fairmq-shmmonitor", ownPath);
|
||||
|
||||
bool verbose = false;
|
||||
if (const char* verboseEnv = getenv("FAIRMQ_SHMMONITOR_VERBOSE")) {
|
||||
if (std::string(verboseEnv) == "true") {
|
||||
verbose = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!p.empty()) {
|
||||
boost::process::spawn(p, "-x", "--shmid", id, "-d", "-t", "2000", env);
|
||||
boost::process::spawn(p, "-x", "-m", "--shmid", id, "-d", "-t", "2000", (verbose ? "--verbose" : ""), env);
|
||||
int numTries = 0;
|
||||
do {
|
||||
try {
|
||||
@@ -225,10 +263,13 @@ class Manager
|
||||
void Resume() { fInterrupted.store(false); }
|
||||
void Reset()
|
||||
{
|
||||
if (fMsgCounter.load() != 0) {
|
||||
LOG(error) << "Message counter during Reset expected to be 0, found: " << fMsgCounter.load();
|
||||
throw MessageError(tools::ToString("Message counter during Reset expected to be 0, found: ", fMsgCounter.load()));
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
auto diff = fMsgCounterNew.load() - fMsgCounterDelete.load();
|
||||
if (diff != 0) {
|
||||
LOG(error) << "Message counter during Reset expected to be 0, found: " << diff;
|
||||
throw MessageError(tools::ToString("Message counter during Reset expected to be 0, found: ", diff));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
bool Interrupted() { return fInterrupted.load(); }
|
||||
|
||||
@@ -236,8 +277,9 @@ class Manager
|
||||
const int64_t userFlags,
|
||||
RegionCallback callback,
|
||||
RegionBulkCallback bulkCallback,
|
||||
const std::string& path = "",
|
||||
int flags = 0)
|
||||
const std::string& path,
|
||||
int flags,
|
||||
fair::mq::RegionConfig cfg)
|
||||
{
|
||||
using namespace boost::interprocess;
|
||||
try {
|
||||
@@ -267,20 +309,35 @@ class Manager
|
||||
return {nullptr, id};
|
||||
}
|
||||
|
||||
// create region info
|
||||
fShmRegions->emplace(id, RegionInfo(path.c_str(), flags, userFlags, fShmVoidAlloc));
|
||||
|
||||
auto r = fRegions.emplace(id, std::make_unique<Region>(fShmId, id, size, false, callback, bulkCallback, path, flags));
|
||||
// LOG(debug) << "Created region with id '" << id << "', path: '" << path << "', flags: '" << flags << "'";
|
||||
|
||||
if (cfg.lock) {
|
||||
LOG(debug) << "Locking region " << id << "...";
|
||||
if (mlock(r.first->second->fRegion.get_address(), r.first->second->fRegion.get_size()) == -1) {
|
||||
LOG(error) << "Could not lock region " << id << ". Code: " << errno << ", reason: " << strerror(errno);
|
||||
}
|
||||
LOG(debug) << "Successfully locked region " << id << ".";
|
||||
}
|
||||
if (cfg.zero) {
|
||||
LOG(debug) << "Zeroing free memory of region " << id << "...";
|
||||
memset(r.first->second->fRegion.get_address(), 0x00, r.first->second->fRegion.get_size());
|
||||
LOG(debug) << "Successfully zeroed free memory of region " << id << ".";
|
||||
}
|
||||
|
||||
fShmRegions->emplace(id, RegionInfo(path.c_str(), flags, userFlags, fShmVoidAlloc));
|
||||
|
||||
r.first->second->InitializeQueues();
|
||||
r.first->second->StartReceivingAcks();
|
||||
result.first = &(r.first->second->fRegion);
|
||||
result.second = id;
|
||||
|
||||
(fEventCounter->fCount)++;
|
||||
}
|
||||
fRegionEventsCV.notify_all();
|
||||
fRegionsGen += 1; // signal TL cache invalidation
|
||||
fRegionEventsShmCV.notify_all();
|
||||
|
||||
return result;
|
||||
|
||||
} catch (interprocess_exception& e) {
|
||||
LOG(error) << "cannot create region. Already created/not cleaned up?";
|
||||
LOG(error) << e.what();
|
||||
@@ -290,8 +347,28 @@ class Manager
|
||||
|
||||
Region* GetRegion(const uint16_t id)
|
||||
{
|
||||
// NOTE: gcc optimizations. Prevent loading tls addresses many times in the fast path
|
||||
const auto &lTlCache = fTlRegionCache;
|
||||
const auto &lTlCacheVec = lTlCache.fRegionsTLCache;
|
||||
const auto lTlCacheGen = lTlCache.fRegionsTLCacheGen;
|
||||
|
||||
// fast path
|
||||
for (const auto &lRegion : lTlCacheVec) {
|
||||
if ((std::get<1>(lRegion) == id) && (lTlCacheGen == fRegionsGen) && (std::get<2>(lRegion) == fShmId64)) {
|
||||
return std::get<0>(lRegion);
|
||||
}
|
||||
}
|
||||
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(fShmMtx);
|
||||
return GetRegionUnsafe(id);
|
||||
// slow path: check invalidation
|
||||
if (lTlCacheGen != fRegionsGen) {
|
||||
fTlRegionCache.fRegionsTLCache.clear();
|
||||
}
|
||||
|
||||
auto *lRegion = GetRegionUnsafe(id);
|
||||
fTlRegionCache.fRegionsTLCache.emplace_back(std::make_tuple(lRegion, id, fShmId64));
|
||||
fTlRegionCache.fRegionsTLCacheGen = fRegionsGen;
|
||||
return lRegion;
|
||||
}
|
||||
|
||||
Region* GetRegionUnsafe(const uint16_t id)
|
||||
@@ -315,7 +392,7 @@ class Manager
|
||||
LOG(error) << oor.what();
|
||||
return nullptr;
|
||||
} catch (boost::interprocess::interprocess_exception& e) {
|
||||
LOG(warn) << "Could not get remote region for id '" << id << "'";
|
||||
LOG(error) << "Could not get remote region for id '" << id << "': " << e.what();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -323,12 +400,19 @@ class Manager
|
||||
|
||||
void RemoveRegion(const uint16_t id)
|
||||
{
|
||||
fRegions.erase(id);
|
||||
{
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(fShmMtx);
|
||||
fShmRegions->at(id).fDestroyed = true;
|
||||
try {
|
||||
fRegions.at(id)->StopAcks();
|
||||
{
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(fShmMtx);
|
||||
fShmRegions->at(id).fDestroyed = true;
|
||||
fRegions.erase(id);
|
||||
(fEventCounter->fCount)++;
|
||||
}
|
||||
fRegionEventsShmCV.notify_all();
|
||||
} catch(std::out_of_range& oor) {
|
||||
LOG(debug) << "RemoveRegion() could not locate region with id '" << id << "'";
|
||||
}
|
||||
fRegionEventsCV.notify_all();
|
||||
fRegionsGen += 1; // signal TL cache invalidation
|
||||
}
|
||||
|
||||
std::vector<fair::mq::RegionInfo> GetRegionInfo()
|
||||
@@ -349,8 +433,12 @@ class Manager
|
||||
info.event = e.second.fDestroyed ? RegionEvent::destroyed : RegionEvent::created;
|
||||
if (!e.second.fDestroyed) {
|
||||
auto region = GetRegionUnsafe(info.id);
|
||||
info.ptr = region->fRegion.get_address();
|
||||
info.size = region->fRegion.get_size();
|
||||
if (region) {
|
||||
info.ptr = region->fRegion.get_address();
|
||||
info.size = region->fRegion.get_size();
|
||||
} else {
|
||||
throw std::runtime_error(tools::ToString("GetRegionInfoUnsafe() could not get region with id '", info.id, "'"));
|
||||
}
|
||||
} else {
|
||||
info.ptr = nullptr;
|
||||
info.size = 0;
|
||||
@@ -366,8 +454,8 @@ class Manager
|
||||
info.managed = true;
|
||||
info.id = e.first;
|
||||
info.event = RegionEvent::created;
|
||||
info.ptr = boost::apply_visitor(SegmentAddress{}, fSegments.at(e.first));
|
||||
info.size = boost::apply_visitor(SegmentSize{}, fSegments.at(e.first));
|
||||
info.ptr = boost::apply_visitor(SegmentAddress(), fSegments.at(e.first));
|
||||
info.size = boost::apply_visitor(SegmentSize(), fSegments.at(e.first));
|
||||
result.push_back(info);
|
||||
} catch (const std::out_of_range& oor) {
|
||||
LOG(error) << "could not find segment with id " << e.first;
|
||||
@@ -385,7 +473,7 @@ class Manager
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(fShmMtx);
|
||||
fRegionEventsSubscriptionActive = false;
|
||||
lock.unlock();
|
||||
fRegionEventsCV.notify_all();
|
||||
fRegionEventsShmCV.notify_all();
|
||||
fRegionEventThread.join();
|
||||
}
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(fShmMtx);
|
||||
@@ -402,7 +490,7 @@ class Manager
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(fShmMtx);
|
||||
fRegionEventsSubscriptionActive = false;
|
||||
lock.unlock();
|
||||
fRegionEventsCV.notify_all();
|
||||
fRegionEventsShmCV.notify_all();
|
||||
fRegionEventThread.join();
|
||||
lock.lock();
|
||||
fRegionEventCallback = nullptr;
|
||||
@@ -415,35 +503,50 @@ class Manager
|
||||
while (fRegionEventsSubscriptionActive) {
|
||||
auto infos = GetRegionInfoUnsafe();
|
||||
for (const auto& i : infos) {
|
||||
auto el = fObservedRegionEvents.find(i.id);
|
||||
if (el == fObservedRegionEvents.end()) {
|
||||
fRegionEventCallback(i);
|
||||
fObservedRegionEvents.emplace(i.id, i.event);
|
||||
} else {
|
||||
auto el = fObservedRegionEvents.find({i.id, i.managed});
|
||||
if (el == fObservedRegionEvents.end()) { // if event id has not been observed
|
||||
fObservedRegionEvents.emplace(std::make_pair(i.id, i.managed), i.event);
|
||||
// if a region has been created and destroyed rapidly, we could see 'destroyed' without ever seeing 'created'
|
||||
// TODO: do we care to show 'created' events if we know region is already destroyed?
|
||||
if (i.event == RegionEvent::created) {
|
||||
fRegionEventCallback(i);
|
||||
++fNumObservedEvents;
|
||||
} else {
|
||||
fNumObservedEvents += 2;
|
||||
}
|
||||
} else { // if event id has been observed (expected - there are two events per id - created & destroyed)
|
||||
// fire a callback if we have observed 'created' event and incoming is 'destroyed'
|
||||
if (el->second == RegionEvent::created && i.event == RegionEvent::destroyed) {
|
||||
fRegionEventCallback(i);
|
||||
el->second = i.event;
|
||||
++fNumObservedEvents;
|
||||
} else {
|
||||
// LOG(debug) << "ignoring event for id" << i.id << ":";
|
||||
// LOG(debug) << "incoming event: " << i.event;
|
||||
// LOG(debug) << "stored event: " << el->second;
|
||||
// LOG(debug) << "ignoring event " << i.id << ": incoming: " << i.event << ", stored: " << el->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
fRegionEventsCV.wait(lock);
|
||||
fRegionEventsShmCV.wait(lock, [&] { return !fRegionEventsSubscriptionActive || fNumObservedEvents != fEventCounter->fCount; });
|
||||
}
|
||||
}
|
||||
|
||||
void IncrementMsgCounter() { fMsgCounter.fetch_add(1, std::memory_order_relaxed); }
|
||||
void DecrementMsgCounter() { fMsgCounter.fetch_sub(1, std::memory_order_relaxed); }
|
||||
void IncrementMsgCounter()
|
||||
{
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
fMsgCounterNew.fetch_add(1, std::memory_order_relaxed);
|
||||
#endif
|
||||
}
|
||||
void DecrementMsgCounter()
|
||||
{
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
fMsgCounterDelete.fetch_add(1, std::memory_order_relaxed);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
void IncrementShmMsgCounter(uint16_t segmentId) { ++((*fShmMsgCounters)[segmentId].fCount); }
|
||||
void DecrementShmMsgCounter(uint16_t segmentId) { --((*fShmMsgCounters)[segmentId].fCount); }
|
||||
#endif
|
||||
|
||||
boost::interprocess::named_mutex& GetMtx() { return fShmMtx; }
|
||||
|
||||
void SendHeartbeats()
|
||||
{
|
||||
std::string controlQueueName("fmq_" + fShmId + "_cq");
|
||||
@@ -471,7 +574,7 @@ class Manager
|
||||
auto it = fSegments.find(id);
|
||||
if (it == fSegments.end()) {
|
||||
try {
|
||||
// get region info
|
||||
// get segment info
|
||||
SegmentInfo segmentInfo = fShmSegments->at(id);
|
||||
LOG(debug) << "Located segment with id '" << id << "'";
|
||||
|
||||
@@ -492,11 +595,11 @@ class Manager
|
||||
|
||||
boost::interprocess::managed_shared_memory::handle_t GetHandleFromAddress(const void* ptr, uint16_t segmentId) const
|
||||
{
|
||||
return boost::apply_visitor(SegmentHandleFromAddress{ptr}, fSegments.at(segmentId));
|
||||
return boost::apply_visitor(SegmentHandleFromAddress(ptr), fSegments.at(segmentId));
|
||||
}
|
||||
void* GetAddressFromHandle(const boost::interprocess::managed_shared_memory::handle_t handle, uint16_t segmentId) const
|
||||
{
|
||||
return boost::apply_visitor(SegmentAddressFromHandle{handle}, fSegments.at(segmentId));
|
||||
return boost::apply_visitor(SegmentAddressFromHandle(handle), fSegments.at(segmentId));
|
||||
}
|
||||
|
||||
char* Allocate(const size_t size, size_t alignment = 0)
|
||||
@@ -509,7 +612,7 @@ class Manager
|
||||
// boost::interprocess::managed_shared_memory::size_type actualSize = size;
|
||||
// char* hint = 0; // unused for boost::interprocess::allocate_new
|
||||
// ptr = fSegments.at(fSegmentId).allocation_command<char>(boost::interprocess::allocate_new, size, actualSize, hint);
|
||||
size_t segmentSize = boost::apply_visitor(SegmentSize{}, fSegments.at(fSegmentId));
|
||||
size_t segmentSize = boost::apply_visitor(SegmentSize(), fSegments.at(fSegmentId));
|
||||
if (size > segmentSize) {
|
||||
throw MessageBadAlloc(tools::ToString("Requested message size (", size, ") exceeds segment size (", segmentSize, ")"));
|
||||
}
|
||||
@@ -521,7 +624,7 @@ class Manager
|
||||
} catch (boost::interprocess::bad_alloc& ba) {
|
||||
// LOG(warn) << "Shared memory full...";
|
||||
if (ThrowingOnBadAlloc()) {
|
||||
throw MessageBadAlloc(tools::ToString("shmem: could not create a message of size ", size, ", alignment: ", (alignment != 0) ? std::to_string(alignment) : "default", ", free memory: ", boost::apply_visitor(SegmentFreeMemory{}, fSegments.at(fSegmentId))));
|
||||
throw MessageBadAlloc(tools::ToString("shmem: could not create a message of size ", size, ", alignment: ", (alignment != 0) ? std::to_string(alignment) : "default", ", free memory: ", boost::apply_visitor(SegmentFreeMemory(), fSegments.at(fSegmentId))));
|
||||
}
|
||||
// rateLimiter.maybe_sleep();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
@@ -549,7 +652,7 @@ class Manager
|
||||
|
||||
void Deallocate(boost::interprocess::managed_shared_memory::handle_t handle, uint16_t segmentId)
|
||||
{
|
||||
boost::apply_visitor(SegmentDeallocate{GetAddressFromHandle(handle, segmentId)}, fSegments.at(segmentId));
|
||||
boost::apply_visitor(SegmentDeallocate(GetAddressFromHandle(handle, segmentId)), fSegments.at(segmentId));
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(fShmMtx);
|
||||
DecrementShmMsgCounter(segmentId);
|
||||
@@ -563,7 +666,7 @@ class Manager
|
||||
|
||||
char* ShrinkInPlace(size_t newSize, char* localPtr, uint16_t segmentId)
|
||||
{
|
||||
return boost::apply_visitor(SegmentBufferShrink{newSize, localPtr}, fSegments.at(segmentId));
|
||||
return boost::apply_visitor(SegmentBufferShrink(newSize, localPtr), fSegments.at(segmentId));
|
||||
}
|
||||
|
||||
uint16_t GetSegmentId() const { return fSegmentId; }
|
||||
@@ -573,6 +676,7 @@ class Manager
|
||||
using namespace boost::interprocess;
|
||||
bool lastRemoved = false;
|
||||
|
||||
fRegionsGen += 1; // signal TL cache invalidation
|
||||
UnsubscribeFromRegionEvents();
|
||||
|
||||
{
|
||||
@@ -590,7 +694,7 @@ class Manager
|
||||
(fDeviceCounter->fCount)--;
|
||||
|
||||
if (fDeviceCounter->fCount == 0) {
|
||||
LOG(debug) << "Last segment user, removing segment.";
|
||||
LOG(debug) << "Last segment user, " << (fNoCleanup ? "skipping removal (--shm-no-cleanup is true)." : "removing segment.");
|
||||
lastRemoved = true;
|
||||
} else {
|
||||
LOG(debug) << "Other segment users present (" << fDeviceCounter->fCount << "), skipping removal.";
|
||||
@@ -599,12 +703,13 @@ class Manager
|
||||
LOG(error) << "Manager could not acquire lock: " << e.what();
|
||||
}
|
||||
|
||||
if (lastRemoved) {
|
||||
if (lastRemoved && !fNoCleanup) {
|
||||
Monitor::Cleanup(ShmId{fShmId});
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t fShmId64;
|
||||
std::string fShmId;
|
||||
uint16_t fSegmentId;
|
||||
std::string fDeviceId;
|
||||
@@ -613,22 +718,32 @@ class Manager
|
||||
VoidAlloc fShmVoidAlloc;
|
||||
boost::interprocess::named_mutex fShmMtx;
|
||||
|
||||
boost::interprocess::named_condition fRegionEventsCV;
|
||||
boost::interprocess::named_condition fRegionEventsShmCV;
|
||||
std::thread fRegionEventThread;
|
||||
bool fRegionEventsSubscriptionActive;
|
||||
std::function<void(fair::mq::RegionInfo)> fRegionEventCallback;
|
||||
std::unordered_map<uint16_t, RegionEvent> fObservedRegionEvents;
|
||||
std::map<std::pair<uint16_t, bool>, RegionEvent> fObservedRegionEvents; // pair: <region id, managed>
|
||||
uint64_t fNumObservedEvents;
|
||||
|
||||
DeviceCounter* fDeviceCounter;
|
||||
EventCounter* fEventCounter;
|
||||
Uint16SegmentInfoHashMap* fShmSegments;
|
||||
Uint16RegionInfoHashMap* fShmRegions;
|
||||
std::unordered_map<uint16_t, std::unique_ptr<Region>> fRegions;
|
||||
// make sure this is alone in the cache line: mostly read
|
||||
alignas(128) inline static std::atomic<unsigned long> fRegionsGen = 0ul;
|
||||
inline static thread_local struct ManagerTLCache {
|
||||
unsigned long fRegionsTLCacheGen;
|
||||
std::vector<std::tuple<Region*, uint16_t, uint64_t>> fRegionsTLCache;
|
||||
} fTlRegionCache;
|
||||
|
||||
std::atomic<bool> fInterrupted;
|
||||
std::atomic<int32_t> fMsgCounter; // TODO: find a better lifetime solution instead of the counter
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
// make sure the counters are not thrashing the cache line between threads doing creation and deallocation
|
||||
Uint16MsgDebugMapHashMap* fMsgDebug;
|
||||
Uint16MsgCounterHashMap* fShmMsgCounters;
|
||||
alignas(128) std::atomic_uint64_t fMsgCounterNew;
|
||||
alignas(128) std::atomic_uint64_t fMsgCounterDelete;
|
||||
#endif
|
||||
|
||||
std::thread fHeartbeatThread;
|
||||
@@ -637,6 +752,9 @@ class Manager
|
||||
std::condition_variable fHeartbeatsCV;
|
||||
|
||||
bool fThrowOnBadAlloc;
|
||||
bool fNoCleanup;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace fair::mq::shmem
|
||||
|
@@ -109,12 +109,17 @@ class Message final : public fair::mq::Message
|
||||
, fRegionPtr(nullptr)
|
||||
, fLocalPtr(static_cast<char*>(data))
|
||||
{
|
||||
if (region->GetType() != GetType()) {
|
||||
LOG(error) << "region type (" << region->GetType() << ") does not match message type (" << GetType() << ")";
|
||||
throw TransportError(tools::ToString("region type (", region->GetType(), ") does not match message type (", GetType(), ")"));
|
||||
}
|
||||
|
||||
if (reinterpret_cast<const char*>(data) >= reinterpret_cast<const char*>(region->GetData()) &&
|
||||
reinterpret_cast<const char*>(data) <= reinterpret_cast<const char*>(region->GetData()) + region->GetSize()) {
|
||||
fMeta.fHandle = (boost::interprocess::managed_shared_memory::handle_t)(reinterpret_cast<const char*>(data) - reinterpret_cast<const char*>(region->GetData()));
|
||||
} else {
|
||||
LOG(error) << "trying to create region message with data from outside the region";
|
||||
throw std::runtime_error("trying to create region message with data from outside the region");
|
||||
throw TransportError("trying to create region message with data from outside the region");
|
||||
}
|
||||
fManager.IncrementMsgCounter();
|
||||
}
|
||||
@@ -211,11 +216,31 @@ class Message final : public fair::mq::Message
|
||||
return true;
|
||||
} else if (newSize <= fMeta.fSize) {
|
||||
try {
|
||||
fLocalPtr = fManager.ShrinkInPlace(newSize, fLocalPtr, fMeta.fSegmentId);
|
||||
fMeta.fSize = newSize;
|
||||
return true;
|
||||
try {
|
||||
fLocalPtr = fManager.ShrinkInPlace(newSize, fLocalPtr, fMeta.fSegmentId);
|
||||
fMeta.fSize = newSize;
|
||||
return true;
|
||||
} catch (boost::interprocess::bad_alloc& e) {
|
||||
// if shrinking fails (can happen due to boost alignment requirements):
|
||||
// unused size >= 1000000 bytes: reallocate fully
|
||||
// unused size < 1000000 bytes: simply reset the size and keep the rest of the buffer until message destruction
|
||||
if (fMeta.fSize - newSize >= 1000000) {
|
||||
char* newPtr = fManager.Allocate(newSize, fAlignment);
|
||||
if (newPtr) {
|
||||
std::memcpy(newPtr, fLocalPtr, newSize);
|
||||
fManager.Deallocate(fMeta.fHandle, fMeta.fSegmentId);
|
||||
fLocalPtr = newPtr;
|
||||
fMeta.fHandle = fManager.GetHandleFromAddress(fLocalPtr, fMeta.fSegmentId);
|
||||
} else {
|
||||
LOG(debug) << "could not set used size: " << e.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fMeta.fSize = newSize;
|
||||
return true;
|
||||
}
|
||||
} catch (boost::interprocess::interprocess_exception& e) {
|
||||
LOG(info) << "could not set used size: " << e.what();
|
||||
LOG(debug) << "could not set used size: " << e.what();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -257,7 +282,7 @@ class Message final : public fair::mq::Message
|
||||
Manager& fManager;
|
||||
bool fQueued;
|
||||
MetaHeader fMeta;
|
||||
size_t fAlignment; // TODO: put this to debug mode
|
||||
size_t fAlignment;
|
||||
mutable Region* fRegionPtr;
|
||||
mutable char* fLocalPtr;
|
||||
|
||||
@@ -284,6 +309,8 @@ class Message final : public fair::mq::Message
|
||||
}
|
||||
|
||||
if (fRegionPtr) {
|
||||
fRegionPtr->InitializeQueues();
|
||||
fRegionPtr->StartSendingAcks();
|
||||
fRegionPtr->ReleaseBlock({fMeta.fHandle, fMeta.fSize, fMeta.fHint});
|
||||
} else {
|
||||
LOG(warn) << "region ack queue for id " << fMeta.fRegionId << " no longer exist. Not sending ack";
|
||||
@@ -299,7 +326,7 @@ class Message final : public fair::mq::Message
|
||||
Deallocate();
|
||||
fAlignment = 0;
|
||||
|
||||
fManager.DecrementMsgCounter(); // TODO: put this to debug mode
|
||||
fManager.DecrementMsgCounter();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -10,7 +10,6 @@
|
||||
#include "Common.h"
|
||||
|
||||
#include <fairmq/tools/Strings.h>
|
||||
#include <fairlogger/Logger.h>
|
||||
|
||||
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||
#include <boost/interprocess/file_mapping.hpp>
|
||||
@@ -32,6 +31,14 @@
|
||||
#include <termios.h>
|
||||
#include <poll.h>
|
||||
|
||||
#if FAIRMQ_HAS_STD_FILESYSTEM
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#else
|
||||
#include <boost/filesystem.hpp>
|
||||
namespace fs = ::boost::filesystem;
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using bie = ::boost::interprocess::interprocess_exception;
|
||||
namespace bipc = ::boost::interprocess;
|
||||
@@ -45,115 +52,6 @@ namespace
|
||||
namespace fair::mq::shmem
|
||||
{
|
||||
|
||||
void signalHandler(int signal)
|
||||
{
|
||||
gSignalStatus = signal;
|
||||
}
|
||||
|
||||
Monitor::Monitor(const string& shmId, bool selfDestruct, bool interactive, bool viewOnly, unsigned int timeoutInMS, unsigned int intervalInMS, bool runAsDaemon, bool cleanOnExit)
|
||||
: fSelfDestruct(selfDestruct)
|
||||
, fInteractive(interactive)
|
||||
, fViewOnly(viewOnly)
|
||||
, fIsDaemon(runAsDaemon)
|
||||
, fSeenOnce(false)
|
||||
, fCleanOnExit(cleanOnExit)
|
||||
, fTimeoutInMS(timeoutInMS)
|
||||
, fIntervalInMS(intervalInMS)
|
||||
, fShmId(shmId)
|
||||
, fSegmentName("fmq_" + fShmId + "_m_0")
|
||||
, fManagementSegmentName("fmq_" + fShmId + "_mng")
|
||||
, fControlQueueName("fmq_" + fShmId + "_cq")
|
||||
, fTerminating(false)
|
||||
, fHeartbeatTriggered(false)
|
||||
, fLastHeartbeat(chrono::high_resolution_clock::now())
|
||||
, fSignalThread()
|
||||
, fDeviceHeartbeats()
|
||||
{
|
||||
if (!fViewOnly) {
|
||||
try {
|
||||
bipc::named_mutex monitorStatus(bipc::create_only, string("fmq_" + fShmId + "_ms").c_str());
|
||||
} catch (bie&) {
|
||||
cout << "fairmq-shmmonitor for shared memory id " << fShmId << " already started or not properly exited. Try `fairmq-shmmonitor --cleanup --shmid " << fShmId << "`" << endl;
|
||||
throw DaemonPresent(tools::ToString("fairmq-shmmonitor for shared memory id ", fShmId, " already started or not properly exited."));
|
||||
}
|
||||
}
|
||||
|
||||
Logger::SetConsoleColor(false);
|
||||
Logger::DefineVerbosity(Verbosity::user1, VerbositySpec::Make(VerbositySpec::Info::timestamp_us));
|
||||
Logger::SetVerbosity(Verbosity::verylow);
|
||||
}
|
||||
|
||||
void Monitor::CatchSignals()
|
||||
{
|
||||
signal(SIGINT, signalHandler);
|
||||
signal(SIGTERM, signalHandler);
|
||||
fSignalThread = thread(&Monitor::SignalMonitor, this);
|
||||
}
|
||||
|
||||
void Monitor::SignalMonitor()
|
||||
{
|
||||
while (true) {
|
||||
if (gSignalStatus != 0) {
|
||||
fTerminating = true;
|
||||
cout << "signal: " << gSignalStatus << endl;
|
||||
break;
|
||||
} else if (fTerminating) {
|
||||
break;
|
||||
}
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(100));
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::Run()
|
||||
{
|
||||
thread heartbeatThread;
|
||||
if (!fViewOnly) {
|
||||
RemoveQueue(fControlQueueName);
|
||||
heartbeatThread = thread(&Monitor::MonitorHeartbeats, this);
|
||||
}
|
||||
|
||||
if (fInteractive) {
|
||||
Interactive();
|
||||
} else {
|
||||
while (!fTerminating) {
|
||||
this_thread::sleep_for(chrono::milliseconds(fIntervalInMS));
|
||||
CheckSegment();
|
||||
}
|
||||
}
|
||||
|
||||
if (!fViewOnly) {
|
||||
heartbeatThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::MonitorHeartbeats()
|
||||
{
|
||||
try {
|
||||
bipc::message_queue mq(bipc::open_or_create, fControlQueueName.c_str(), 1000, 256);
|
||||
|
||||
unsigned int priority;
|
||||
bipc::message_queue::size_type recvdSize;
|
||||
char msg[256] = {0};
|
||||
|
||||
while (!fTerminating) {
|
||||
bpt::ptime rcvTill = bpt::microsec_clock::universal_time() + bpt::milliseconds(100);
|
||||
if (mq.timed_receive(&msg, sizeof(msg), recvdSize, priority, rcvTill)) {
|
||||
fHeartbeatTriggered = true;
|
||||
fLastHeartbeat = chrono::high_resolution_clock::now();
|
||||
string deviceId(msg, recvdSize);
|
||||
fDeviceHeartbeats[deviceId] = fLastHeartbeat;
|
||||
} else {
|
||||
// cout << "control queue timeout" << endl;
|
||||
}
|
||||
}
|
||||
} catch (bie& ie) {
|
||||
cout << ie.what() << endl;
|
||||
}
|
||||
|
||||
RemoveQueue(fControlQueueName);
|
||||
}
|
||||
|
||||
struct TerminalConfig
|
||||
{
|
||||
TerminalConfig()
|
||||
@@ -175,6 +73,268 @@ struct TerminalConfig
|
||||
}
|
||||
};
|
||||
|
||||
void signalHandler(int signal)
|
||||
{
|
||||
gSignalStatus = signal;
|
||||
}
|
||||
|
||||
Monitor::Monitor(const string& shmId, bool selfDestruct, bool interactive, bool viewOnly, unsigned int timeoutInMS, unsigned int intervalInMS, bool monitor, bool cleanOnExit)
|
||||
: fSelfDestruct(selfDestruct)
|
||||
, fInteractive(interactive)
|
||||
, fViewOnly(viewOnly)
|
||||
, fMonitor(monitor)
|
||||
, fSeenOnce(false)
|
||||
, fCleanOnExit(cleanOnExit)
|
||||
, fTimeoutInMS(timeoutInMS)
|
||||
, fIntervalInMS(intervalInMS)
|
||||
, fShmId(shmId)
|
||||
, fControlQueueName("fmq_" + fShmId + "_cq")
|
||||
, fTerminating(false)
|
||||
, fHeartbeatTriggered(false)
|
||||
, fLastHeartbeat(chrono::high_resolution_clock::now())
|
||||
, fSignalThread()
|
||||
, fDeviceHeartbeats()
|
||||
{
|
||||
if (!fViewOnly) {
|
||||
try {
|
||||
bipc::named_mutex monitorStatus(bipc::create_only, string("fmq_" + fShmId + "_ms").c_str());
|
||||
} catch (bie&) {
|
||||
if (fInteractive) {
|
||||
LOG(error) << "fairmq-shmmonitor for shm id " << fShmId << " is already running. Try `fairmq-shmmonitor --cleanup --shmid " << fShmId << "`, or run in view-only mode (-v)";
|
||||
} else {
|
||||
LOG(error) << "fairmq-shmmonitor for shm id " << fShmId << " is already running. Try `fairmq-shmmonitor --cleanup --shmid " << fShmId << "`";
|
||||
}
|
||||
throw DaemonPresent(tools::ToString("fairmq-shmmonitor (in monitoring mode) for shm id ", fShmId, " is already running."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::CatchSignals()
|
||||
{
|
||||
signal(SIGINT, signalHandler);
|
||||
signal(SIGTERM, signalHandler);
|
||||
fSignalThread = thread(&Monitor::SignalMonitor, this);
|
||||
}
|
||||
|
||||
void Monitor::SignalMonitor()
|
||||
{
|
||||
while (true) {
|
||||
if (gSignalStatus != 0) {
|
||||
fTerminating = true;
|
||||
LOG(info) << "signal: " << gSignalStatus;
|
||||
break;
|
||||
} else if (fTerminating) {
|
||||
break;
|
||||
}
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(100));
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::Run()
|
||||
{
|
||||
thread heartbeatThread;
|
||||
if (!fViewOnly) {
|
||||
RemoveQueue(fControlQueueName);
|
||||
heartbeatThread = thread(&Monitor::ReceiveHeartbeats, this);
|
||||
}
|
||||
|
||||
if (fInteractive) {
|
||||
Interactive();
|
||||
} else {
|
||||
Watch();
|
||||
}
|
||||
|
||||
if (!fViewOnly) {
|
||||
heartbeatThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::Watch()
|
||||
{
|
||||
while (!fTerminating) {
|
||||
using namespace boost::interprocess;
|
||||
|
||||
try {
|
||||
managed_shared_memory managementSegment(open_read_only, std::string("fmq_" + fShmId + "_mng").c_str());
|
||||
|
||||
fSeenOnce = true;
|
||||
|
||||
auto now = chrono::high_resolution_clock::now();
|
||||
unsigned int duration = chrono::duration_cast<chrono::milliseconds>(now - fLastHeartbeat).count();
|
||||
|
||||
if (fHeartbeatTriggered && duration > fTimeoutInMS) {
|
||||
// memory is present, but no heartbeats since timeout duration
|
||||
LOG(info) << "no heartbeats since over " << fTimeoutInMS << " milliseconds, cleaning...";
|
||||
Cleanup(ShmId{fShmId});
|
||||
fHeartbeatTriggered = false;
|
||||
if (fSelfDestruct) {
|
||||
LOG(info) << "self destructing (segment has been observed and cleaned up by the monitor)";
|
||||
fTerminating = true;
|
||||
}
|
||||
}
|
||||
} catch (bie&) {
|
||||
fHeartbeatTriggered = false;
|
||||
|
||||
if (fSelfDestruct) {
|
||||
if (fSeenOnce) {
|
||||
// segment has been observed at least once, can self-destruct
|
||||
LOG(info) << "self destructing (segment has been observed and cleaned up orderly)";
|
||||
fTerminating = true;
|
||||
} else {
|
||||
// if self-destruct is requested, and no segment has ever been observed, quit after double timeout duration
|
||||
auto now = chrono::high_resolution_clock::now();
|
||||
unsigned int duration = chrono::duration_cast<chrono::milliseconds>(now - fLastHeartbeat).count();
|
||||
|
||||
if (duration > fTimeoutInMS * 2) {
|
||||
Cleanup(ShmId{fShmId});
|
||||
LOG(info) << "self destructing (no segments observed within (timeout * 2) since start)";
|
||||
fTerminating = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(100));
|
||||
}
|
||||
}
|
||||
|
||||
bool Monitor::PrintShm(const ShmId& shmId)
|
||||
{
|
||||
using namespace boost::interprocess;
|
||||
|
||||
try {
|
||||
managed_shared_memory managementSegment(open_read_only, std::string("fmq_" + shmId.shmId + "_mng").c_str());
|
||||
VoidAlloc allocInstance(managementSegment.get_segment_manager());
|
||||
|
||||
Uint16SegmentInfoHashMap* segmentInfos = managementSegment.find<Uint16SegmentInfoHashMap>(unique_instance).first;
|
||||
std::unordered_map<uint16_t, boost::variant<RBTreeBestFitSegment, SimpleSeqFitSegment>> segments;
|
||||
|
||||
if (!segmentInfos) {
|
||||
LOG(error) << "Found management segment, but cannot locate segment info, something went wrong...";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& s : *segmentInfos) {
|
||||
if (s.second.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
||||
segments.emplace(s.first, RBTreeBestFitSegment(open_read_only, std::string("fmq_" + shmId.shmId + "_m_" + to_string(s.first)).c_str()));
|
||||
} else {
|
||||
segments.emplace(s.first, SimpleSeqFitSegment(open_read_only, std::string("fmq_" + shmId.shmId + "_m_" + to_string(s.first)).c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int numDevices = 0;
|
||||
int creatorId = -1;
|
||||
std::string sessionName;
|
||||
|
||||
DeviceCounter* deviceCounter = managementSegment.find<DeviceCounter>(unique_instance).first;
|
||||
if (deviceCounter) {
|
||||
numDevices = deviceCounter->fCount;
|
||||
}
|
||||
SessionInfo* sessionInfo = managementSegment.find<SessionInfo>(unique_instance).first;
|
||||
if (sessionInfo) {
|
||||
creatorId = sessionInfo->fCreatorId;
|
||||
sessionName = sessionInfo->fSessionName;
|
||||
}
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
Uint16MsgCounterHashMap* msgCounters = managementSegment.find<Uint16MsgCounterHashMap>(unique_instance).first;
|
||||
#endif
|
||||
|
||||
stringstream ss;
|
||||
size_t mfree = managementSegment.get_free_memory();
|
||||
size_t mtotal = managementSegment.get_size();
|
||||
size_t mused = mtotal - mfree;
|
||||
|
||||
ss << "shm id: " << shmId.shmId
|
||||
<< ", session: " << sessionName
|
||||
<< ", creator id: " << creatorId
|
||||
<< ", devices: " << numDevices
|
||||
<< ", segments:\n";
|
||||
|
||||
for (const auto& s : segments) {
|
||||
size_t free = boost::apply_visitor(SegmentFreeMemory(), s.second);
|
||||
size_t total = boost::apply_visitor(SegmentSize(), s.second);
|
||||
size_t used = total - free;
|
||||
ss << " [" << s.first
|
||||
<< "]: total: " << total
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
<< ", msgs: " << ( (msgCounters != nullptr) ? to_string((*msgCounters)[s.first].fCount) : "unknown")
|
||||
#else
|
||||
<< ", msgs: NODEBUG"
|
||||
#endif
|
||||
<< ", free: " << free
|
||||
<< ", used: " << used
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
ss << " [m]: "
|
||||
<< "total: " << mtotal
|
||||
<< ", free: " << mfree
|
||||
<< ", used: " << mused;
|
||||
LOGV(info, user1) << ss.str();
|
||||
} catch (bie&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Monitor::ListAll(const std::string& path)
|
||||
{
|
||||
try {
|
||||
if (fs::is_empty(path)) {
|
||||
LOG(info) << "directory " << fs::path(path) << " is empty.";
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& entry : fs::directory_iterator(path)) {
|
||||
string filename = entry.path().filename().string();
|
||||
// LOG(info) << filename << ", size: " << entry.file_size() << " bytes";
|
||||
if (tools::StrStartsWith(filename, "fmq_") || tools::StrStartsWith(filename, "sem.fmq_")) {
|
||||
// LOG(info) << "The file '" << filename << "' belongs to FairMQ.";
|
||||
if (tools::StrEndsWith(filename, "_mng")) {
|
||||
string shmId = filename.substr(4, 8);
|
||||
LOG(info) << "\nFound shmid '" << shmId << "':\n";
|
||||
if (!PrintShm(ShmId{shmId})) {
|
||||
LOG(info) << "could not open file for shmid '" << shmId << "'";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(info) << "The file '" << filename << "' does not belong to FairMQ, skipping...";
|
||||
}
|
||||
}
|
||||
} catch (fs::filesystem_error& fse) {
|
||||
LOG(error) << "error: " << fse.what();
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::ReceiveHeartbeats()
|
||||
{
|
||||
try {
|
||||
bipc::message_queue mq(bipc::open_or_create, fControlQueueName.c_str(), 1000, 256);
|
||||
|
||||
unsigned int priority;
|
||||
bipc::message_queue::size_type recvdSize;
|
||||
char msg[256] = {0};
|
||||
|
||||
while (!fTerminating) {
|
||||
bpt::ptime rcvTill = bpt::microsec_clock::universal_time() + bpt::milliseconds(100);
|
||||
if (mq.timed_receive(&msg, sizeof(msg), recvdSize, priority, rcvTill)) {
|
||||
fHeartbeatTriggered = true;
|
||||
fLastHeartbeat = chrono::high_resolution_clock::now();
|
||||
string deviceId(msg, recvdSize);
|
||||
fDeviceHeartbeats[deviceId] = fLastHeartbeat;
|
||||
} else {
|
||||
// LOG(info) << "control queue timeout";
|
||||
}
|
||||
}
|
||||
} catch (bie& ie) {
|
||||
LOG(info) << ie.what();
|
||||
}
|
||||
|
||||
RemoveQueue(fControlQueueName);
|
||||
}
|
||||
|
||||
void Monitor::Interactive()
|
||||
{
|
||||
char c;
|
||||
@@ -184,7 +344,7 @@ void Monitor::Interactive()
|
||||
|
||||
TerminalConfig tcfg;
|
||||
|
||||
cout << endl;
|
||||
LOG(info) << "\n";
|
||||
PrintHelp();
|
||||
|
||||
while (!fTerminating) {
|
||||
@@ -197,30 +357,30 @@ void Monitor::Interactive()
|
||||
|
||||
switch (c) {
|
||||
case 'q':
|
||||
cout << "\n[q] --> quitting." << endl;
|
||||
LOG(info) << "\n[q] --> quitting.";
|
||||
fTerminating = true;
|
||||
break;
|
||||
case 'x':
|
||||
cout << "\n[x] --> closing shared memory:" << endl;
|
||||
LOG(info) << "\n[x] --> closing shared memory:";
|
||||
if (!fViewOnly) {
|
||||
Cleanup(ShmId{fShmId});
|
||||
} else {
|
||||
cout << "cannot close because in view only mode" << endl;
|
||||
LOG(info) << "cannot close because in view only mode";
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
cout << "\n[h] --> help:" << endl << endl;
|
||||
LOG(info) << "\n[h] --> help:\n";
|
||||
PrintHelp();
|
||||
cout << endl;
|
||||
LOG(info);
|
||||
break;
|
||||
case '\n':
|
||||
cout << "\n[\\n] --> invalid input." << endl;
|
||||
LOG(info) << "\n[\\n] --> invalid input.";
|
||||
break;
|
||||
case 'b':
|
||||
PrintDebugInfo(ShmId{fShmId});
|
||||
break;
|
||||
default:
|
||||
cout << "\n[" << c << "] --> invalid input." << endl;
|
||||
LOG(info) << "\n[" << c << "] --> invalid input.";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -233,118 +393,7 @@ void Monitor::Interactive()
|
||||
break;
|
||||
}
|
||||
|
||||
CheckSegment();
|
||||
|
||||
if (!fTerminating) {
|
||||
cout << "\r";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::CheckSegment()
|
||||
{
|
||||
using namespace boost::interprocess;
|
||||
|
||||
try {
|
||||
managed_shared_memory managementSegment(open_only, fManagementSegmentName.c_str());
|
||||
VoidAlloc allocInstance(managementSegment.get_segment_manager());
|
||||
|
||||
Uint16SegmentInfoHashMap* segmentInfos = managementSegment.find<Uint16SegmentInfoHashMap>(unique_instance).first;
|
||||
std::unordered_map<uint16_t, boost::variant<RBTreeBestFitSegment, SimpleSeqFitSegment>> segments;
|
||||
|
||||
if (!segmentInfos) {
|
||||
cout << "Found management segment, but cannot locate segment info, something went wrong..." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& s : *segmentInfos) {
|
||||
if (s.second.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
||||
segments.emplace(s.first, RBTreeBestFitSegment(open_only, std::string("fmq_" + fShmId + "_m_" + to_string(s.first)).c_str()));
|
||||
} else {
|
||||
segments.emplace(s.first, SimpleSeqFitSegment(open_only, std::string("fmq_" + fShmId + "_m_" + to_string(s.first)).c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
fSeenOnce = true;
|
||||
|
||||
unsigned int numDevices = 0;
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
Uint16MsgCounterHashMap* msgCounters = nullptr;
|
||||
#endif
|
||||
|
||||
if (fInteractive || fViewOnly) {
|
||||
DeviceCounter* dc = managementSegment.find<DeviceCounter>(unique_instance).first;
|
||||
if (dc) {
|
||||
numDevices = dc->fCount;
|
||||
}
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
msgCounters = managementSegment.find_or_construct<Uint16MsgCounterHashMap>(unique_instance)(allocInstance);
|
||||
#endif
|
||||
}
|
||||
|
||||
auto now = chrono::high_resolution_clock::now();
|
||||
unsigned int duration = chrono::duration_cast<chrono::milliseconds>(now - fLastHeartbeat).count();
|
||||
|
||||
if (fHeartbeatTriggered && duration > fTimeoutInMS) {
|
||||
cout << "no heartbeats since over " << fTimeoutInMS << " milliseconds, cleaning..." << endl;
|
||||
Cleanup(ShmId{fShmId});
|
||||
fHeartbeatTriggered = false;
|
||||
if (fSelfDestruct) {
|
||||
cout << "\nself destructing" << endl;
|
||||
fTerminating = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fInteractive || fViewOnly) {
|
||||
stringstream ss;
|
||||
size_t mfree = managementSegment.get_free_memory();
|
||||
size_t mtotal = managementSegment.get_size();
|
||||
size_t mused = mtotal - mfree;
|
||||
|
||||
ss << "shm id: " << fShmId
|
||||
<< ", devices: " << numDevices << ", segments:\n";
|
||||
for (const auto& s : segments) {
|
||||
size_t free = boost::apply_visitor(SegmentFreeMemory{}, s.second);
|
||||
size_t total = boost::apply_visitor(SegmentSize{}, s.second);
|
||||
size_t used = total - free;
|
||||
ss << " [" << s.first
|
||||
<< "]: total: " << total
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
<< ", msgs: " << (*msgCounters)[s.first].fCount
|
||||
#else
|
||||
<< ", msgs: NODEBUG"
|
||||
#endif
|
||||
<< ", free: " << free
|
||||
<< ", used: " << used
|
||||
<< "\n";
|
||||
}
|
||||
ss << " [m]: "
|
||||
<< "total: " << mtotal
|
||||
<< ", free: " << mfree
|
||||
<< ", used: " << mused;
|
||||
LOGV(info, user1) << ss.str();
|
||||
}
|
||||
} catch (bie&) {
|
||||
fHeartbeatTriggered = false;
|
||||
|
||||
auto now = chrono::high_resolution_clock::now();
|
||||
unsigned int duration = chrono::duration_cast<chrono::milliseconds>(now - fLastHeartbeat).count();
|
||||
|
||||
if (fIsDaemon && duration > fTimeoutInMS * 2) {
|
||||
Cleanup(ShmId{fShmId});
|
||||
fHeartbeatTriggered = false;
|
||||
if (fSelfDestruct) {
|
||||
cout << "\nself destructing" << endl;
|
||||
fTerminating = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fSelfDestruct) {
|
||||
if (fSeenOnce) {
|
||||
cout << "self destructing" << endl;
|
||||
fTerminating = true;
|
||||
}
|
||||
}
|
||||
PrintShm(ShmId{fShmId});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +413,7 @@ void Monitor::PrintDebugInfo(const ShmId& shmId __attribute__((unused)))
|
||||
for (const auto& e : *debug) {
|
||||
numMessages += e.second.size();
|
||||
}
|
||||
cout << endl << "found " << numMessages << " messages." << endl;
|
||||
LOG(info) << endl << "found " << numMessages << " messages.";
|
||||
|
||||
for (const auto& s : *debug) {
|
||||
for (const auto& e : s.second) {
|
||||
@@ -373,25 +422,24 @@ void Monitor::PrintDebugInfo(const ShmId& shmId __attribute__((unused)))
|
||||
time_t t = chrono::system_clock::to_time_t(tmpt);
|
||||
uint64_t ms = e.second.fCreationTime % 1000000;
|
||||
auto tm = localtime(&t);
|
||||
cout << "segment: " << setw(3) << setfill(' ') << s.first
|
||||
LOG(info) << "segment: " << setw(3) << setfill(' ') << s.first
|
||||
<< ", offset: " << setw(12) << setfill(' ') << e.first
|
||||
<< ", size: " << setw(10) << setfill(' ') << e.second.fSize
|
||||
<< ", creator PID: " << e.second.fPid << setfill('0')
|
||||
<< ", at: " << setw(2) << tm->tm_hour << ":" << setw(2) << tm->tm_min << ":" << setw(2) << tm->tm_sec << "." << setw(6) << ms << endl;
|
||||
<< ", at: " << setw(2) << tm->tm_hour << ":" << setw(2) << tm->tm_min << ":" << setw(2) << tm->tm_sec << "." << setw(6) << ms;
|
||||
}
|
||||
}
|
||||
cout << setfill(' ');
|
||||
} catch (bie&) {
|
||||
cout << "no segments found" << endl;
|
||||
LOG(info) << "no segments found";
|
||||
}
|
||||
#else
|
||||
cout << "FairMQ was not compiled in debug mode (FAIRMQ_DEBUG_MODE)" << endl;
|
||||
LOG(info) << "FairMQ was not compiled in debug mode (FAIRMQ_DEBUG_MODE)";
|
||||
#endif
|
||||
}
|
||||
|
||||
void Monitor::PrintDebugInfo(const SessionId& sessionId)
|
||||
{
|
||||
ShmId shmId{buildShmIdFromSessionIdAndUserId(sessionId.sessionId)};
|
||||
ShmId shmId{makeShmIdStr(sessionId.sessionId)};
|
||||
PrintDebugInfo(shmId);
|
||||
}
|
||||
|
||||
@@ -417,26 +465,26 @@ unordered_map<uint16_t, std::vector<BufferDebugInfo>> Monitor::GetDebugInfo(cons
|
||||
}
|
||||
}
|
||||
} catch (bie&) {
|
||||
cout << "no segments found" << endl;
|
||||
LOG(info) << "no segments found";
|
||||
}
|
||||
#else
|
||||
cout << "FairMQ was not compiled in debug mode (FAIRMQ_DEBUG_MODE)" << endl;
|
||||
LOG(info) << "FairMQ was not compiled in debug mode (FAIRMQ_DEBUG_MODE)";
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
unordered_map<uint16_t, std::vector<BufferDebugInfo>> Monitor::GetDebugInfo(const SessionId& sessionId)
|
||||
{
|
||||
ShmId shmId{buildShmIdFromSessionIdAndUserId(sessionId.sessionId)};
|
||||
ShmId shmId{makeShmIdStr(sessionId.sessionId)};
|
||||
return GetDebugInfo(shmId);
|
||||
}
|
||||
|
||||
void Monitor::PrintHelp()
|
||||
{
|
||||
cout << "controls: [x] close memory, "
|
||||
<< "[b] print a list of allocated messages (only available when compiled with FAIMQ_DEBUG_MODE=ON), "
|
||||
<< "[h] help, "
|
||||
<< "[q] quit." << endl;
|
||||
LOG(info) << "controls: [x] close memory, "
|
||||
<< "[b] print a list of allocated messages (only available when compiled with FAIMQ_DEBUG_MODE=ON), "
|
||||
<< "[h] help, "
|
||||
<< "[q] quit.";
|
||||
}
|
||||
|
||||
|
||||
@@ -444,12 +492,12 @@ std::pair<std::string, bool> RunRemoval(std::function<bool(const std::string&)>
|
||||
{
|
||||
if (f(name)) {
|
||||
if (verbose) {
|
||||
cout << "Successfully removed '" << name << "'." << endl;
|
||||
LOG(info) << "Successfully removed '" << name << "'.";
|
||||
}
|
||||
return {name, true};
|
||||
} else {
|
||||
if (verbose) {
|
||||
cout << "Did not remove '" << name << "'. Already removed?" << endl;
|
||||
LOG(debug) << "Did not remove '" << name << "'. Already removed?";
|
||||
}
|
||||
return {name, false};
|
||||
}
|
||||
@@ -466,7 +514,7 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const ShmId& shmId, b
|
||||
std::vector<std::pair<std::string, bool>> result;
|
||||
|
||||
if (verbose) {
|
||||
cout << "Cleaning up for shared memory id '" << shmId.shmId << "'..." << endl;
|
||||
LOG(info) << "Cleaning up for shared memory id '" << shmId.shmId << "'...";
|
||||
}
|
||||
|
||||
string managementSegmentName("fmq_" + shmId.shmId + "_mng");
|
||||
@@ -477,7 +525,7 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const ShmId& shmId, b
|
||||
RegionCounter* rc = managementSegment.find<RegionCounter>(bipc::unique_instance).first;
|
||||
if (rc) {
|
||||
if (verbose) {
|
||||
cout << "Region counter found: " << rc->fCount << endl;
|
||||
LOG(debug) << "Region counter found: " << rc->fCount;
|
||||
}
|
||||
uint16_t regionCount = rc->fCount;
|
||||
|
||||
@@ -489,7 +537,7 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const ShmId& shmId, b
|
||||
string path = ri.fPath.c_str();
|
||||
int flags = ri.fFlags;
|
||||
if (verbose) {
|
||||
cout << "Found RegionInfo with path: '" << path << "', flags: " << flags << ", fDestroyed: " << ri.fDestroyed << "." << endl;
|
||||
LOG(info) << "Found RegionInfo with path: '" << path << "', flags: " << flags << ", fDestroyed: " << ri.fDestroyed << ".";
|
||||
}
|
||||
if (path != "") {
|
||||
result.emplace_back(RunRemoval(Monitor::RemoveFileMapping, path + "fmq_" + shmId.shmId + "_rg_" + to_string(i), verbose));
|
||||
@@ -504,12 +552,12 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const ShmId& shmId, b
|
||||
}
|
||||
} else {
|
||||
if (verbose) {
|
||||
cout << "No region counter found. No regions to cleanup." << endl;
|
||||
LOG(info) << "No region counter found. No regions to cleanup.";
|
||||
}
|
||||
}
|
||||
} catch(out_of_range& oor) {
|
||||
if (verbose) {
|
||||
cout << "Could not locate element in the region map, out of range: " << oor.what() << endl;
|
||||
LOG(info) << "Could not locate element in the region map, out of range: " << oor.what();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,7 +570,7 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const ShmId& shmId, b
|
||||
result.emplace_back(RunRemoval(Monitor::RemoveObject, managementSegmentName.c_str(), verbose));
|
||||
} catch (bie&) {
|
||||
if (verbose) {
|
||||
cout << "Did not find '" << managementSegmentName << "' shared memory segment. No regions to cleanup." << endl;
|
||||
LOG(info) << "Did not find '" << managementSegmentName << "' shared memory segment. No regions to cleanup.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,9 +582,9 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const ShmId& shmId, b
|
||||
|
||||
std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const SessionId& sessionId, bool verbose /* = true */)
|
||||
{
|
||||
ShmId shmId{buildShmIdFromSessionIdAndUserId(sessionId.sessionId)};
|
||||
ShmId shmId{makeShmIdStr(sessionId.sessionId)};
|
||||
if (verbose) {
|
||||
cout << "Cleanup called with session id '" << sessionId.sessionId << "', translating to shared memory id '" << shmId.shmId << "'" << endl;
|
||||
LOG(info) << "Cleanup called with session id '" << sessionId.sessionId << "', translating to shared memory id '" << shmId.shmId << "'";
|
||||
}
|
||||
return Cleanup(shmId, verbose);
|
||||
}
|
||||
@@ -551,9 +599,9 @@ std::vector<std::pair<std::string, bool>> Monitor::CleanupFull(const ShmId& shmI
|
||||
|
||||
std::vector<std::pair<std::string, bool>> Monitor::CleanupFull(const SessionId& sessionId, bool verbose /* = true */)
|
||||
{
|
||||
ShmId shmId{buildShmIdFromSessionIdAndUserId(sessionId.sessionId)};
|
||||
ShmId shmId{makeShmIdStr(sessionId.sessionId)};
|
||||
if (verbose) {
|
||||
cout << "Cleanup called with session id '" << sessionId.sessionId << "', translating to shared memory id '" << shmId.shmId << "'" << endl;
|
||||
LOG(info) << "Cleanup called with session id '" << sessionId.sessionId << "', translating to shared memory id '" << shmId.shmId << "'";
|
||||
}
|
||||
return CleanupFull(shmId, verbose);
|
||||
}
|
||||
|
@@ -8,6 +8,8 @@
|
||||
#ifndef FAIR_MQ_SHMEM_MONITOR_H_
|
||||
#define FAIR_MQ_SHMEM_MONITOR_H_
|
||||
|
||||
#include <fairlogger/Logger.h>
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
@@ -82,6 +84,9 @@ class Monitor
|
||||
static std::unordered_map<uint16_t, std::vector<BufferDebugInfo>> GetDebugInfo(const ShmId& shmId);
|
||||
static std::unordered_map<uint16_t, std::vector<BufferDebugInfo>> GetDebugInfo(const SessionId& shmId);
|
||||
|
||||
static bool PrintShm(const ShmId& shmId);
|
||||
static void ListAll(const std::string& path);
|
||||
|
||||
static bool RemoveObject(const std::string& name);
|
||||
static bool RemoveFileMapping(const std::string& name);
|
||||
static bool RemoveQueue(const std::string& name);
|
||||
@@ -92,7 +97,8 @@ class Monitor
|
||||
|
||||
private:
|
||||
void PrintHelp();
|
||||
void MonitorHeartbeats();
|
||||
void Watch();
|
||||
void ReceiveHeartbeats();
|
||||
void CheckSegment();
|
||||
void Interactive();
|
||||
void SignalMonitor();
|
||||
@@ -100,14 +106,12 @@ class Monitor
|
||||
bool fSelfDestruct; // will self-destruct after the memory has been closed
|
||||
bool fInteractive; // running in interactive mode
|
||||
bool fViewOnly; // view only mode
|
||||
bool fIsDaemon;
|
||||
bool fMonitor;
|
||||
bool fSeenOnce; // true is segment has been opened successfully at least once
|
||||
bool fCleanOnExit;
|
||||
unsigned int fTimeoutInMS;
|
||||
unsigned int fIntervalInMS;
|
||||
std::string fShmId;
|
||||
std::string fSegmentName;
|
||||
std::string fManagementSegmentName;
|
||||
std::string fControlQueueName;
|
||||
std::atomic<bool> fTerminating;
|
||||
std::atomic<bool> fHeartbeatTriggered;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Shared Memory transport
|
||||
## Shared Memory transport
|
||||
|
||||
Shared memory transport for FairMQ. To try with existing devices, run the devices with `--transport shmem` option or configure channel transport in JSON (see examples/MQ/multiple-transports).
|
||||
|
||||
@@ -6,7 +6,7 @@ The transport manages shared memory via boost::interprocess library. The transfe
|
||||
|
||||
Devices track and cleanup shared memory on shutdown. For more information on the current shared memory segment and additional cleanup options, see following section.
|
||||
|
||||
# Shared Memory objects / files
|
||||
## Shared Memory objects / files
|
||||
|
||||
FairMQ Shared Memory currently uses the following names to register shared memory on the system:
|
||||
|
||||
@@ -15,7 +15,7 @@ FairMQ Shared Memory currently uses the following names to register shared memor
|
||||
| `fmq_<shmId>_m_<segmentId>` | managed segment(s) (user data) | one of the devices | devices |
|
||||
| `fmq_<shmId>_mng` | management segment (management data) | one of the devices | devices |
|
||||
| `fmq_<shmId>_mtx` | mutex | one of the devices | devices |
|
||||
| `fmq_<shmId>_cv` | condition variable | one of the devices | devices with unmanaged regions |
|
||||
| `fmq_<shmId>_cv` | condition variable | one of the devices | devices |
|
||||
| `fmq_<shmId>_rg_<index>` | unmanaged region(s) | one of the devices | devices with unmanaged regions |
|
||||
| `fmq_<shmId>_rgq_<index>` | unmanaged region queue(s) | one of the devices | devices with unmanaged regions |
|
||||
| `fmq_<shmId>_ms` | shmmonitor status | shmmonitor | devices, shmmonitor |
|
||||
@@ -25,20 +25,35 @@ The shmId is generated out of session id and user id.
|
||||
|
||||
## Shared memory monitor
|
||||
|
||||
The shared memory monitor tool, supplied with the shared memory transport can be used to monitor shared memory use and automatically cleanup shared memory in case of device crashes.
|
||||
The shared memory monitor tool (`fairmq-shmmonitor`) can be used to monitor and cleanup the created shared memory.
|
||||
|
||||
With default arguments the monitor will run indefinitely with no output, and clean up shared memory segment if it is open and no heartbeats from devices arrive within a timeout period. It can be further customized with following parameters:
|
||||
Most commands act for the specified session, identified either via session id (`--session`,`-s`) or shmid (`--shmid`).
|
||||
|
||||
`--session <arg>`: for which session to run the monitor (default is "default"). The actual ressource names will be built out of session id, user id (hashed and truncated).
|
||||
`--cleanup`: start monitor, perform cleanup of the memory and quit.
|
||||
`--shmid <arg>`: if provided, this shmem id will be used instead of the one generated from session id. Use this if you know the name of the shared memory ressource, but do not have the used session id.
|
||||
`--self-destruct`: run until the memory segment is closed (either naturally via cleanup performed by devices or in case of a crash (no heartbeats within timeout)).
|
||||
`--interactive`: run interactively, with detailed segment details and user input for various shmem operations.
|
||||
`--timeout <arg>`: specifiy the timeout for the heartbeats from shmem transports in milliseconds (default 5000).
|
||||
The monitor runs in one of the following modes:
|
||||
|
||||
The options can be combined, with the exception of `--cleanup` option, which will invoke the described behaviour independent of other options.
|
||||
Without the `--self-destruct` option, the monitor will run continuously, moitoring (and cleaning up if needed) consecutive topologies.
|
||||
| command | action |
|
||||
| --------------------------- | ---------------------------------------------- |
|
||||
| no args | Print segment info of the specified session/shm ID and exit. |
|
||||
| `--view`,`-v` | Print segment info of the specified session/shm ID and exit. |
|
||||
| `--interactive`,`-i` | Print segment info of the specified session/shm ID at a given interval (`--interval`), with some keyboard controls. Can be combined with `--view` for read-only access (and avoid receiving heartbeats). |
|
||||
| `--monitor`,`-m` | Monitor the session shm usage by receiving heartbeats from shmem users, cleaning it up if no heartbeats arrived within configured timeout (`--timeout`/`-t`). Only one heartbeat receiver per session is currently possible. If `--self-destruct`/`-x` is added, monitor will exit either when (a) no shm has been observed for interval * 2, (b) a cleanup due to reached timeout has been performed, or (c) shm has been observed, but is now cleaned up. |
|
||||
| `--cleanup`,`-c` | Cleanup the shm for the specified session and exit. |
|
||||
| `--debug`,`-b` | Print the list of messages in the current session and exit. Only availabe when FairMQ is compiled with `FAIRMQ_DEBUG_MODE=ON` (high performance impact). |
|
||||
| `--get-shmid` | Translate given session id and user id (`--user-id`) to a shmem id (uses current user id if none provided) and exit. |
|
||||
| `--list-all` | Print segment info for all sessions present on the system and exit. |
|
||||
|
||||
Possible further implementation would be to run the monitor with `--self-destruct` with each topology.
|
||||
Additional cmd options:
|
||||
|
||||
The Monitor class can also be used independently from the supplied executable (built from `runMonitor.cxx`), allowing integration on any level. For example invoking the monitor could be a functionality that a device offers.
|
||||
| command | action |
|
||||
| --------------------------- | ---------------------------------------------- |
|
||||
| `--cleanup-on-exit` | Perform a cleanup on exit, when running in monitoring or interactive mode. |
|
||||
| `--daemonize`,`-d` | Can be combined with the monitoring mode to detach the process from the parent. |
|
||||
| `--verbose`,`-d` | When running as a daemon, store monitor output in `fairmq-shmmonitor_<timestamp>.log` |
|
||||
|
||||
For full option details, run with `-h`.
|
||||
|
||||
The Monitor class can also be used independently from the supplied executable, allowing integration on any level.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Bus Error (SIGBUS) can occur if the transport tries to access shared memory that is not accessible. One reason could be because the used memory in the segment exceeds the capacity or available memory of the shmem filesystem (capacity is by default set to half of RAM on Linux).
|
||||
|
@@ -47,7 +47,7 @@ struct Region
|
||||
Region(const std::string& shmId, uint16_t id, uint64_t size, bool remote, RegionCallback callback, RegionBulkCallback bulkCallback, const std::string& path, int flags)
|
||||
: fRemote(remote)
|
||||
, fLinger(100)
|
||||
, fStop(false)
|
||||
, fStopAcks(false)
|
||||
, fName("fmq_" + shmId + "_rg_" + std::to_string(id))
|
||||
, fQueueName("fmq_" + shmId + "_rgq_" + std::to_string(id))
|
||||
, fShmemObject()
|
||||
@@ -85,18 +85,26 @@ struct Region
|
||||
LOG(debug) << "shmem: initialized file: " << fName;
|
||||
fRegion = mapped_region(fFileMapping, read_write, 0, size, 0, flags);
|
||||
} else {
|
||||
if (fRemote) {
|
||||
fShmemObject = shared_memory_object(open_only, fName.c_str(), read_write);
|
||||
} else {
|
||||
fShmemObject = shared_memory_object(create_only, fName.c_str(), read_write);
|
||||
fShmemObject.truncate(size);
|
||||
try {
|
||||
if (fRemote) {
|
||||
fShmemObject = shared_memory_object(open_only, fName.c_str(), read_write);
|
||||
} else {
|
||||
fShmemObject = shared_memory_object(create_only, fName.c_str(), read_write);
|
||||
fShmemObject.truncate(size);
|
||||
}
|
||||
} catch(interprocess_exception& e) {
|
||||
LOG(error) << "Failed " << (fRemote ? "opening" : "creating") << " shared_memory_object for region id '" << id << "': " << e.what();
|
||||
throw;
|
||||
}
|
||||
try {
|
||||
fRegion = mapped_region(fShmemObject, read_write, 0, 0, 0, flags);
|
||||
} catch(interprocess_exception& e) {
|
||||
LOG(error) << "Failed mapping shared_memory_object for region id '" << id << "': " << e.what();
|
||||
throw;
|
||||
}
|
||||
fRegion = mapped_region(fShmemObject, read_write, 0, 0, 0, flags);
|
||||
}
|
||||
|
||||
InitializeQueues();
|
||||
StartSendingAcks();
|
||||
LOG(debug) << "shmem: initialized region: " << fName;
|
||||
LOG(trace) << "shmem: initialized region: " << fName << " (" << (fRemote ? "remote" : "local") << ")";
|
||||
}
|
||||
|
||||
Region() = delete;
|
||||
@@ -108,15 +116,22 @@ struct Region
|
||||
{
|
||||
using namespace boost::interprocess;
|
||||
|
||||
if (fRemote) {
|
||||
fQueue = std::make_unique<message_queue>(open_only, fQueueName.c_str());
|
||||
} else {
|
||||
fQueue = std::make_unique<message_queue>(create_only, fQueueName.c_str(), 1024, fAckBunchSize * sizeof(RegionBlock));
|
||||
if (fQueue == nullptr) {
|
||||
if (fRemote) {
|
||||
fQueue = std::make_unique<message_queue>(open_only, fQueueName.c_str());
|
||||
} else {
|
||||
fQueue = std::make_unique<message_queue>(create_only, fQueueName.c_str(), 1024, fAckBunchSize * sizeof(RegionBlock));
|
||||
}
|
||||
LOG(trace) << "shmem: initialized region queue: " << fQueueName << " (" << (fRemote ? "remote" : "local") << ")";
|
||||
}
|
||||
LOG(debug) << "shmem: initialized region queue: " << fQueueName;
|
||||
}
|
||||
|
||||
void StartSendingAcks() { fAcksSender = std::thread(&Region::SendAcks, this); }
|
||||
void StartSendingAcks()
|
||||
{
|
||||
if (!fAcksSender.joinable()) {
|
||||
fAcksSender = std::thread(&Region::SendAcks, this);
|
||||
}
|
||||
}
|
||||
void SendAcks()
|
||||
{
|
||||
std::unique_ptr<RegionBlock[]> blocks = std::make_unique<RegionBlock[]>(fAckBunchSize);
|
||||
@@ -140,23 +155,28 @@ struct Region
|
||||
}
|
||||
|
||||
if (blocksToSend > 0) {
|
||||
while (!fQueue->try_send(blocks.get(), blocksToSend * sizeof(RegionBlock), 0) && !fStop) {
|
||||
while (!fQueue->try_send(blocks.get(), blocksToSend * sizeof(RegionBlock), 0) && !fStopAcks) {
|
||||
// receiver slow? yield and try again...
|
||||
std::this_thread::yield();
|
||||
}
|
||||
// LOG(debug) << "Sent " << blocksToSend << " blocks.";
|
||||
} else { // blocksToSend == 0
|
||||
if (fStop) {
|
||||
if (fStopAcks) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG(debug) << "AcksSender for " << fName << " leaving " << "(blocks left to free: " << fBlocksToFree.size() << ", "
|
||||
LOG(trace) << "AcksSender for " << fName << " leaving " << "(blocks left to free: " << fBlocksToFree.size() << ", "
|
||||
<< " blocks left to send: " << blocksToSend << ").";
|
||||
}
|
||||
|
||||
void StartReceivingAcks() { fAcksReceiver = std::thread(&Region::ReceiveAcks, this); }
|
||||
void StartReceivingAcks()
|
||||
{
|
||||
if (!fAcksReceiver.joinable()) {
|
||||
fAcksReceiver = std::thread(&Region::ReceiveAcks, this);
|
||||
}
|
||||
}
|
||||
void ReceiveAcks()
|
||||
{
|
||||
unsigned int priority;
|
||||
@@ -168,7 +188,7 @@ struct Region
|
||||
while (true) {
|
||||
uint32_t timeout = 100;
|
||||
bool leave = false;
|
||||
if (fStop) {
|
||||
if (fStopAcks) {
|
||||
timeout = fLinger;
|
||||
leave = true;
|
||||
}
|
||||
@@ -195,7 +215,7 @@ struct Region
|
||||
}
|
||||
}
|
||||
|
||||
LOG(debug) << "AcksReceiver for " << fName << " leaving (remaining queue size: " << fQueue->get_num_msg() << ").";
|
||||
LOG(trace) << "AcksReceiver for " << fName << " leaving (remaining queue size: " << fQueue->get_num_msg() << ").";
|
||||
}
|
||||
|
||||
void ReleaseBlock(const RegionBlock& block)
|
||||
@@ -213,9 +233,25 @@ struct Region
|
||||
void SetLinger(uint32_t linger) { fLinger = linger; }
|
||||
uint32_t GetLinger() const { return fLinger; }
|
||||
|
||||
void StopAcks()
|
||||
{
|
||||
fStopAcks = true;
|
||||
|
||||
if (fAcksSender.joinable()) {
|
||||
fBlockSendCV.notify_one();
|
||||
fAcksSender.join();
|
||||
}
|
||||
|
||||
if (!fRemote) {
|
||||
if (fAcksReceiver.joinable()) {
|
||||
fAcksReceiver.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~Region()
|
||||
{
|
||||
fStop = true;
|
||||
fStopAcks = true;
|
||||
|
||||
if (fAcksSender.joinable()) {
|
||||
fBlockSendCV.notify_one();
|
||||
@@ -228,11 +264,11 @@ struct Region
|
||||
}
|
||||
|
||||
if (boost::interprocess::shared_memory_object::remove(fName.c_str())) {
|
||||
LOG(debug) << "Region '" << fName << "' destroyed.";
|
||||
LOG(trace) << "Region '" << fName << "' destroyed.";
|
||||
}
|
||||
|
||||
if (boost::interprocess::file_mapping::remove(fName.c_str())) {
|
||||
LOG(debug) << "File mapping '" << fName << "' destroyed.";
|
||||
LOG(trace) << "File mapping '" << fName << "' destroyed.";
|
||||
}
|
||||
|
||||
if (fFile) {
|
||||
@@ -240,19 +276,18 @@ struct Region
|
||||
}
|
||||
|
||||
if (boost::interprocess::message_queue::remove(fQueueName.c_str())) {
|
||||
LOG(debug) << "Region queue '" << fQueueName << "' destroyed.";
|
||||
LOG(trace) << "Region queue '" << fQueueName << "' destroyed.";
|
||||
}
|
||||
} else {
|
||||
// LOG(debug) << "shmem: region '" << fName << "' is remote, no cleanup necessary.";
|
||||
LOG(debug) << "Region queue '" << fQueueName << "' is remote, no cleanup necessary";
|
||||
// LOG(debug) << "Region queue '" << fQueueName << "' is remote, no cleanup necessary";
|
||||
}
|
||||
|
||||
LOG(debug) << "Region '" << fName << "' (" << (fRemote ? "remote" : "local") << ") destructed.";
|
||||
// LOG(debug) << "Region '" << fName << "' (" << (fRemote ? "remote" : "local") << ") destructed.";
|
||||
}
|
||||
|
||||
bool fRemote;
|
||||
uint32_t fLinger;
|
||||
std::atomic<bool> fStop;
|
||||
std::atomic<bool> fStopAcks;
|
||||
std::string fName;
|
||||
std::string fQueueName;
|
||||
boost::interprocess::shared_memory_object fShmemObject;
|
||||
|
@@ -378,12 +378,10 @@ class Socket final : public fair::mq::Socket
|
||||
}
|
||||
}
|
||||
|
||||
void Events(uint32_t* events) override
|
||||
int Events(uint32_t* events) override
|
||||
{
|
||||
size_t eventsSize = sizeof(uint32_t);
|
||||
if (zmq_getsockopt(fSocket, ZMQ_EVENTS, events, &eventsSize) < 0) {
|
||||
throw SocketError(tools::ToString("failed setting ZMQ_EVENTS, reason: ", zmq_strerror(errno)));
|
||||
}
|
||||
return zmq_getsockopt(fSocket, ZMQ_EVENTS, events, &eventsSize);
|
||||
}
|
||||
|
||||
int GetLinger() const override
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include <memory> // unique_ptr, make_unique
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace fair::mq::shmem
|
||||
{
|
||||
@@ -35,10 +36,8 @@ namespace fair::mq::shmem
|
||||
class TransportFactory final : public fair::mq::TransportFactory
|
||||
{
|
||||
public:
|
||||
TransportFactory(const std::string& id = "", const ProgOptions* config = nullptr)
|
||||
: fair::mq::TransportFactory(id)
|
||||
, fDeviceId(id)
|
||||
, fShmId()
|
||||
TransportFactory(const std::string& deviceId = "", const ProgOptions* config = nullptr)
|
||||
: fair::mq::TransportFactory(deviceId)
|
||||
, fZmqCtx(zmq_ctx_new())
|
||||
, fManager(nullptr)
|
||||
{
|
||||
@@ -69,9 +68,6 @@ class TransportFactory final : public fair::mq::TransportFactory
|
||||
throw SharedMemoryError(tools::ToString("Provided shared memory allocation algorithm '", allocationAlgorithm, "' is not supported. Supported are 'rbtree_best_fit'/'simple_seq_fit'"));
|
||||
}
|
||||
|
||||
fShmId = buildShmIdFromSessionIdAndUserId(sessionName);
|
||||
LOG(debug) << "Generated shmid '" << fShmId << "' out of session id '" << sessionName << "'.";
|
||||
|
||||
try {
|
||||
if (zmq_ctx_set(fZmqCtx, ZMQ_IO_THREADS, numIoThreads) != 0) {
|
||||
LOG(error) << "failed configuring context, reason: " << zmq_strerror(errno);
|
||||
@@ -82,10 +78,13 @@ class TransportFactory final : public fair::mq::TransportFactory
|
||||
LOG(error) << "failed configuring context, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
|
||||
fManager = std::make_unique<Manager>(fShmId, fDeviceId, segmentSize, config);
|
||||
fManager = std::make_unique<Manager>(sessionName, deviceId, segmentSize, config);
|
||||
} catch (boost::interprocess::interprocess_exception& e) {
|
||||
LOG(error) << "Could not initialize shared memory transport: " << e.what();
|
||||
throw std::runtime_error(tools::ToString("Could not initialize shared memory transport: ", e.what()));
|
||||
} catch (const std::exception& e) {
|
||||
LOG(error) << "Could not initialize shared memory transport: " << e.what();
|
||||
throw std::runtime_error(tools::ToString("Could not initialize shared memory transport: ", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,29 +141,29 @@ class TransportFactory final : public fair::mq::TransportFactory
|
||||
return std::make_unique<Poller>(channelsMap, channelList);
|
||||
}
|
||||
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, RegionCallback callback = nullptr, const std::string& path = "", int flags = 0) override
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, RegionCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) override
|
||||
{
|
||||
return CreateUnmanagedRegion(size, 0, callback, nullptr, path, flags);
|
||||
return CreateUnmanagedRegion(size, 0, callback, nullptr, path, flags, cfg);
|
||||
}
|
||||
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, RegionBulkCallback bulkCallback = nullptr, const std::string& path = "", int flags = 0) override
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, RegionBulkCallback bulkCallback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) override
|
||||
{
|
||||
return CreateUnmanagedRegion(size, 0, nullptr, bulkCallback, path, flags);
|
||||
return CreateUnmanagedRegion(size, 0, nullptr, bulkCallback, path, flags, cfg);
|
||||
}
|
||||
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, int64_t userFlags, RegionCallback callback = nullptr, const std::string& path = "", int flags = 0) override
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, int64_t userFlags, RegionCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) override
|
||||
{
|
||||
return CreateUnmanagedRegion(size, userFlags, callback, nullptr, path, flags);
|
||||
return CreateUnmanagedRegion(size, userFlags, callback, nullptr, path, flags, cfg);
|
||||
}
|
||||
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, int64_t userFlags, RegionBulkCallback bulkCallback = nullptr, const std::string& path = "", int flags = 0) override
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, int64_t userFlags, RegionBulkCallback bulkCallback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) override
|
||||
{
|
||||
return CreateUnmanagedRegion(size, userFlags, nullptr, bulkCallback, path, flags);
|
||||
return CreateUnmanagedRegion(size, userFlags, nullptr, bulkCallback, path, flags, cfg);
|
||||
}
|
||||
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, int64_t userFlags, RegionCallback callback, RegionBulkCallback bulkCallback, const std::string& path, int flags)
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, int64_t userFlags, RegionCallback callback, RegionBulkCallback bulkCallback, const std::string& path, int flags, fair::mq::RegionConfig cfg)
|
||||
{
|
||||
return std::make_unique<UnmanagedRegion>(*fManager, size, userFlags, callback, bulkCallback, path, flags, this);
|
||||
return std::make_unique<UnmanagedRegion>(*fManager, size, userFlags, callback, bulkCallback, path, flags, this, cfg);
|
||||
}
|
||||
|
||||
void SubscribeToRegionEvents(RegionEventCallback callback) override { fManager->SubscribeToRegionEvents(callback); }
|
||||
@@ -200,8 +199,6 @@ class TransportFactory final : public fair::mq::TransportFactory
|
||||
}
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
std::string fShmId;
|
||||
void* fZmqCtx;
|
||||
std::unique_ptr<Manager> fManager;
|
||||
};
|
||||
|
@@ -37,15 +37,16 @@ class UnmanagedRegion final : public fair::mq::UnmanagedRegion
|
||||
const int64_t userFlags,
|
||||
RegionCallback callback,
|
||||
RegionBulkCallback bulkCallback,
|
||||
const std::string& path = "",
|
||||
int flags = 0,
|
||||
FairMQTransportFactory* factory = nullptr)
|
||||
const std::string& path,
|
||||
int flags,
|
||||
FairMQTransportFactory* factory,
|
||||
fair::mq::RegionConfig cfg)
|
||||
: FairMQUnmanagedRegion(factory)
|
||||
, fManager(manager)
|
||||
, fRegion(nullptr)
|
||||
, fRegionId(0)
|
||||
{
|
||||
auto result = fManager.CreateRegion(size, userFlags, callback, bulkCallback, path, flags);
|
||||
auto result = fManager.CreateRegion(size, userFlags, callback, bulkCallback, path, flags, cfg);
|
||||
fRegion = result.first;
|
||||
fRegionId = result.second;
|
||||
}
|
||||
@@ -56,6 +57,8 @@ class UnmanagedRegion final : public fair::mq::UnmanagedRegion
|
||||
void SetLinger(uint32_t linger) override { fManager.GetRegion(fRegionId)->SetLinger(linger); }
|
||||
uint32_t GetLinger() const override { return fManager.GetRegion(fRegionId)->GetLinger(); }
|
||||
|
||||
Transport GetType() const override { return fair::mq::Transport::SHM; }
|
||||
|
||||
~UnmanagedRegion() override { fManager.RemoveRegion(fRegionId); }
|
||||
|
||||
private:
|
||||
|
@@ -69,6 +69,10 @@ static void daemonize()
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
try {
|
||||
fair::Logger::SetConsoleColor(false);
|
||||
fair::Logger::DefineVerbosity(fair::Verbosity::user1, fair::VerbositySpec::Make(fair::VerbositySpec::Info::timestamp_us));
|
||||
fair::Logger::SetVerbosity(fair::Verbosity::verylow);
|
||||
|
||||
string sessionName;
|
||||
string shmId;
|
||||
bool cleanup = false;
|
||||
@@ -78,8 +82,15 @@ int main(int argc, char** argv)
|
||||
unsigned int timeoutInMS = 5000;
|
||||
unsigned int intervalInMS = 100;
|
||||
bool runAsDaemon = false;
|
||||
bool monitor = false;
|
||||
bool debug = false;
|
||||
bool cleanOnExit = false;
|
||||
bool getShmId = false;
|
||||
bool listAll = false;
|
||||
string listAllPath;
|
||||
bool verbose = false;
|
||||
string severity;
|
||||
int userId = -1;
|
||||
|
||||
options_description desc("Options");
|
||||
desc.add_options()
|
||||
@@ -90,28 +101,44 @@ int main(int argc, char** argv)
|
||||
("interactive,i" , value<bool>(&interactive)->implicit_value(true), "Interactive run")
|
||||
("view,v" , value<bool>(&viewOnly)->implicit_value(true), "Run in view only mode")
|
||||
("timeout,t" , value<unsigned int>(&timeoutInMS)->default_value(5000), "Heartbeat timeout in milliseconds")
|
||||
("daemonize,d" , value<bool>(&runAsDaemon)->implicit_value(true), "Daemonize the monitor")
|
||||
("debug,b" , value<bool>(&debug)->implicit_value(true), "Debug - Print a list of messages)")
|
||||
("daemonize,d" , value<bool>(&runAsDaemon)->implicit_value(true), "Daemonize the monitor process (only in monitoring mode)")
|
||||
("monitor,m" , value<bool>(&monitor)->implicit_value(true), "Run in monitoring mode")
|
||||
("debug,b" , value<bool>(&debug)->implicit_value(true), "Debug - Print a list of messages)")
|
||||
("clean-on-exit,e", value<bool>(&cleanOnExit)->implicit_value(true), "Perform cleanup on exit")
|
||||
("interval" , value<unsigned int>(&intervalInMS)->default_value(100), "Output interval for interactive/view-only mode")
|
||||
("help,h", "Print help");
|
||||
("interval" , value<unsigned int>(&intervalInMS)->default_value(1000),"Output interval for interactive mode")
|
||||
("get-shmid" , value<bool>(&getShmId)->implicit_value(true), "Translate given session id and user id to a shmem id (uses current user id if none provided)")
|
||||
("list-all" , value<bool>(&listAll)->implicit_value(true), "List all sessions & segments")
|
||||
("list-all-path" , value<string>(&listAllPath)->default_value("/dev/shm/"),"Path for the --list-all command to search segments in")
|
||||
("verbose" , value<bool>(&verbose)->implicit_value(true), "Verbose mode (daemon will output to a file 'fairmq-shmmonitor_<timestamp>')")
|
||||
("severity" , value<string>(&severity)->default_value("info"), "Log severity")
|
||||
("user-id" , value<int>(&userId)->default_value(-1), "User id (used with --get-shmid)")
|
||||
("help,h", "Print help");
|
||||
|
||||
variables_map vm;
|
||||
store(parse_command_line(argc, argv, desc), vm);
|
||||
|
||||
if (vm.count("help")) {
|
||||
cout << "FairMQ Shared Memory Monitor" << endl << desc << endl;
|
||||
LOG(info) << "FairMQ Shared Memory Monitor" << "\n" << desc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
notify(vm);
|
||||
|
||||
if (runAsDaemon) {
|
||||
daemonize();
|
||||
fair::Logger::SetConsoleSeverity(severity);
|
||||
|
||||
if (getShmId) {
|
||||
if (userId == -1) {
|
||||
LOG(info) << "shmem id for session '" << sessionName << "' and current user id " << geteuid()
|
||||
<< " is: " << makeShmIdStr(sessionName);
|
||||
} else {
|
||||
LOG(info) << "shmem id for session '" << sessionName << "' and user id " << userId
|
||||
<< " is: " << makeShmIdStr(sessionName, to_string(userId));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (shmId == "") {
|
||||
shmId = buildShmIdFromSessionIdAndUserId(sessionName);
|
||||
if (shmId.empty()) {
|
||||
shmId = makeShmIdStr(sessionName);
|
||||
}
|
||||
|
||||
if (cleanup) {
|
||||
@@ -124,19 +151,39 @@ int main(int argc, char** argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
cout << "Starting shared memory monitor for session: \"" << sessionName << "\" (shmId: " << shmId << ")..." << endl;
|
||||
if (viewOnly && !interactive) {
|
||||
cout << "running in non-interactive view-only mode, outputting with interval of " << intervalInMS << "ms. (change with --interval), press ctrl+C to exit." << endl;
|
||||
if (listAll) {
|
||||
Monitor::ListAll(listAllPath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Monitor monitor(shmId, selfDestruct, interactive, viewOnly, timeoutInMS, intervalInMS, runAsDaemon, cleanOnExit);
|
||||
if (!viewOnly && !interactive && !monitor) {
|
||||
// if neither of the run modes are selected, use view only mode.
|
||||
viewOnly = true;
|
||||
}
|
||||
|
||||
monitor.CatchSignals();
|
||||
monitor.Run();
|
||||
if (viewOnly && !interactive) {
|
||||
if (!Monitor::PrintShm(ShmId{shmId})) {
|
||||
LOG(info) << "No segments found.";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (runAsDaemon && monitor) {
|
||||
if (verbose) {
|
||||
fair::Logger::InitFileSink("trace", "fairmq-shmmonitor");
|
||||
}
|
||||
daemonize();
|
||||
}
|
||||
|
||||
LOG(info) << "Starting shared memory monitor for session: \"" << sessionName << "\" (shm id: " << shmId << ")...";
|
||||
|
||||
Monitor shmmonitor(shmId, selfDestruct, interactive, viewOnly, timeoutInMS, intervalInMS, monitor, cleanOnExit);
|
||||
shmmonitor.CatchSignals();
|
||||
shmmonitor.Run();
|
||||
} catch (Monitor::DaemonPresent& dp) {
|
||||
return 0;
|
||||
} catch (exception& e) {
|
||||
cerr << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" << endl;
|
||||
LOG(error) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit";
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@@ -39,6 +39,24 @@ inline auto ToStrVector(const int argc, char*const* argv, const bool dropProgram
|
||||
}
|
||||
}
|
||||
|
||||
inline bool StrStartsWith(std::string const& str, std::string const& start)
|
||||
{
|
||||
if (str.length() >= start.length()) {
|
||||
return (0 == str.compare(0, start.length(), start));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool StrEndsWith(std::string const& str, std::string const& end)
|
||||
{
|
||||
if (str.length() >= end.length()) {
|
||||
return (0 == str.compare(str.length() - end.length(), end.length(), end));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fair::mq::tools
|
||||
|
||||
#endif /* FAIR_MQ_TOOLS_STRINGS_H */
|
||||
|
@@ -1,10 +1,11 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 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 <fairmq/tools/Unique.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
@@ -109,6 +109,11 @@ class Message final : public fair::mq::Message
|
||||
, fAlignment(0)
|
||||
, fMsg(std::make_unique<zmq_msg_t>())
|
||||
{
|
||||
if (region->GetType() != GetType()) {
|
||||
LOG(error) << "region type (" << region->GetType() << ") does not match message type (" << GetType() << ")";
|
||||
throw TransportError(tools::ToString("region type (", region->GetType(), ") does not match message type (", GetType(), ")"));
|
||||
}
|
||||
|
||||
// FIXME: make this zero-copy:
|
||||
// simply taking over the provided buffer can casue premature delete, since region could be
|
||||
// destroyed before the message is sent out. Needs lifetime extension for the ZMQ region.
|
||||
|
@@ -323,12 +323,10 @@ class Socket final : public fair::mq::Socket
|
||||
}
|
||||
}
|
||||
|
||||
void Events(uint32_t* events) override
|
||||
int Events(uint32_t* events) override
|
||||
{
|
||||
size_t eventsSize = sizeof(uint32_t);
|
||||
if (zmq_getsockopt(fSocket, ZMQ_EVENTS, events, &eventsSize) < 0) {
|
||||
throw SocketError(tools::ToString("failed setting ZMQ_EVENTS, reason: ", zmq_strerror(errno)));
|
||||
}
|
||||
return zmq_getsockopt(fSocket, ZMQ_EVENTS, events, &eventsSize);
|
||||
}
|
||||
|
||||
void SetLinger(const int value) override
|
||||
|
@@ -96,29 +96,29 @@ class TransportFactory final : public FairMQTransportFactory
|
||||
return std::make_unique<Poller>(channelsMap, channelList);
|
||||
}
|
||||
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, RegionCallback callback, const std::string& path = "", int flags = 0) override
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, RegionCallback callback, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) override
|
||||
{
|
||||
return CreateUnmanagedRegion(size, 0, callback, nullptr, path, flags);
|
||||
return CreateUnmanagedRegion(size, 0, callback, nullptr, path, flags, cfg);
|
||||
}
|
||||
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, RegionBulkCallback bulkCallback, const std::string& path = "", int flags = 0) override
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, RegionBulkCallback bulkCallback, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) override
|
||||
{
|
||||
return CreateUnmanagedRegion(size, 0, nullptr, bulkCallback, path, flags);
|
||||
return CreateUnmanagedRegion(size, 0, nullptr, bulkCallback, path, flags, cfg);
|
||||
}
|
||||
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, RegionCallback callback, const std::string& path = "", int flags = 0) override
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, RegionCallback callback, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) override
|
||||
{
|
||||
return CreateUnmanagedRegion(size, userFlags, callback, nullptr, path, flags);
|
||||
return CreateUnmanagedRegion(size, userFlags, callback, nullptr, path, flags, cfg);
|
||||
}
|
||||
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, RegionBulkCallback bulkCallback, const std::string& path = "", int flags = 0) override
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, RegionBulkCallback bulkCallback, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) override
|
||||
{
|
||||
return CreateUnmanagedRegion(size, userFlags, nullptr, bulkCallback, path, flags);
|
||||
return CreateUnmanagedRegion(size, userFlags, nullptr, bulkCallback, path, flags, cfg);
|
||||
}
|
||||
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, RegionCallback callback, RegionBulkCallback bulkCallback, const std::string&, int)
|
||||
UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, RegionCallback callback, RegionBulkCallback bulkCallback, const std::string&, int /* flags */, fair::mq::RegionConfig cfg)
|
||||
{
|
||||
UnmanagedRegionPtr ptr = std::make_unique<UnmanagedRegion>(*fCtx, size, userFlags, callback, bulkCallback, this);
|
||||
UnmanagedRegionPtr ptr = std::make_unique<UnmanagedRegion>(*fCtx, size, userFlags, callback, bulkCallback, this, cfg);
|
||||
auto zPtr = static_cast<UnmanagedRegion*>(ptr.get());
|
||||
fCtx->AddRegion(false, zPtr->GetId(), zPtr->GetData(), zPtr->GetSize(), zPtr->GetUserFlags(), RegionEvent::created);
|
||||
return ptr;
|
||||
|
@@ -16,6 +16,8 @@
|
||||
#include <cstddef> // size_t
|
||||
#include <string>
|
||||
|
||||
#include <sys/mman.h> // mlock
|
||||
|
||||
namespace fair::mq::zmq
|
||||
{
|
||||
|
||||
@@ -30,7 +32,8 @@ class UnmanagedRegion final : public fair::mq::UnmanagedRegion
|
||||
int64_t userFlags,
|
||||
RegionCallback callback,
|
||||
RegionBulkCallback bulkCallback,
|
||||
FairMQTransportFactory* factory = nullptr)
|
||||
FairMQTransportFactory* factory,
|
||||
fair::mq::RegionConfig cfg)
|
||||
: fair::mq::UnmanagedRegion(factory)
|
||||
, fCtx(ctx)
|
||||
, fId(fCtx.RegionCount())
|
||||
@@ -39,7 +42,20 @@ class UnmanagedRegion final : public fair::mq::UnmanagedRegion
|
||||
, fUserFlags(userFlags)
|
||||
, fCallback(callback)
|
||||
, fBulkCallback(bulkCallback)
|
||||
{}
|
||||
{
|
||||
if (cfg.lock) {
|
||||
LOG(debug) << "Locking region " << fId << "...";
|
||||
if (mlock(fBuffer, fSize) == -1) {
|
||||
LOG(error) << "Could not lock region " << fId << ". Code: " << errno << ", reason: " << strerror(errno);
|
||||
}
|
||||
LOG(debug) << "Successfully locked region " << fId << ".";
|
||||
}
|
||||
if (cfg.zero) {
|
||||
LOG(debug) << "Zeroing free memory of region " << fId << "...";
|
||||
memset(fBuffer, 0x00, fSize);
|
||||
LOG(debug) << "Successfully zeroed free memory of region " << fId << ".";
|
||||
}
|
||||
}
|
||||
|
||||
UnmanagedRegion(const UnmanagedRegion&) = delete;
|
||||
UnmanagedRegion operator=(const UnmanagedRegion&) = delete;
|
||||
@@ -51,6 +67,8 @@ class UnmanagedRegion final : public fair::mq::UnmanagedRegion
|
||||
void SetLinger(uint32_t /* linger */) override { LOG(debug) << "ZeroMQ UnmanagedRegion linger option not implemented. Acknowledgements are local."; }
|
||||
uint32_t GetLinger() const override { LOG(debug) << "ZeroMQ UnmanagedRegion linger option not implemented. Acknowledgements are local."; return 0; }
|
||||
|
||||
Transport GetType() const override { return Transport::ZMQ; }
|
||||
|
||||
virtual ~UnmanagedRegion()
|
||||
{
|
||||
LOG(debug) << "destroying region " << fId;
|
||||
|
@@ -217,6 +217,7 @@ add_testsuite(Properties
|
||||
SOURCES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
properties/_properties.cxx
|
||||
properties/_suboptparser.cxx
|
||||
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
|
41
test/ci/slurm-submit.sh
Executable file
41
test/ci/slurm-submit.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#! /bin/bash
|
||||
|
||||
label="$1"
|
||||
jobsh="$2"
|
||||
|
||||
if [ -z "$ALFACI_SLURM_CPUS" ]
|
||||
then
|
||||
ALFACI_SLURM_CPUS=32
|
||||
fi
|
||||
if [ -z "$ALFACI_SLURM_EXTRA_OPTS" ]
|
||||
then
|
||||
ALFACI_SLURM_EXTRA_OPTS="--hint=compute_bound"
|
||||
fi
|
||||
if [ -z "$ALFACI_SLURM_TIMEOUT" ]
|
||||
then
|
||||
ALFACI_SLURM_TIMEOUT=30
|
||||
fi
|
||||
if [ -z "$ALFACI_SLURM_QUEUE" ]
|
||||
then
|
||||
ALFACI_SLURM_QUEUE=main
|
||||
fi
|
||||
|
||||
echo "*** Slurm request options :"
|
||||
echo "*** Working directory ..: $PWD"
|
||||
echo "*** Queue ..............: $ALFACI_SLURM_QUEUE"
|
||||
echo "*** CPUs ...............: $ALFACI_SLURM_CPUS"
|
||||
echo "*** Wall Time ..........: $ALFACI_SLURM_TIMEOUT min"
|
||||
echo "*** Job Name ...........: ${label}"
|
||||
echo "*** Extra Options ......: ${ALFACI_SLURM_EXTRA_OPTS}"
|
||||
echo "*** Submitting job at ....: $(date -R)"
|
||||
(
|
||||
set -x
|
||||
srun -p $ALFACI_SLURM_QUEUE -c $ALFACI_SLURM_CPUS -n 1 \
|
||||
-t $ALFACI_SLURM_TIMEOUT \
|
||||
--job-name="${label}" \
|
||||
${ALFACI_SLURM_EXTRA_OPTS} \
|
||||
bash "${jobsh}"
|
||||
)
|
||||
retval=$?
|
||||
echo "*** Exit Code ............: $retval"
|
||||
exit "$retval"
|
@@ -153,9 +153,11 @@ TEST(ErrorState, interactive_InReset)
|
||||
EXPECT_EXIT(RunErrorStateIn("Reset", "interactive", "q"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
|
||||
#ifdef FAIRMQ_DEBUG_MODE
|
||||
TEST(ErrorState, OrphanMessages)
|
||||
{
|
||||
BadDevice badDevice;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
@@ -40,34 +40,34 @@ void RunPushPullWithMsgResize(const string& transport, const string& _address)
|
||||
pull.Connect(address);
|
||||
|
||||
{
|
||||
FairMQMessagePtr outMsg(push.NewMessage(1000));
|
||||
ASSERT_EQ(outMsg->GetSize(), 1000);
|
||||
memcpy(outMsg->GetData(), "ABC", 3);
|
||||
ASSERT_EQ(outMsg->SetUsedSize(500), true);
|
||||
ASSERT_EQ(outMsg->SetUsedSize(500), true);
|
||||
ASSERT_EQ(outMsg->SetUsedSize(700), false);
|
||||
ASSERT_EQ(outMsg->GetSize(), 500);
|
||||
FairMQMessagePtr outMsg(push.NewMessage(6));
|
||||
ASSERT_EQ(outMsg->GetSize(), 6);
|
||||
memcpy(outMsg->GetData(), "ABCDEF", 6);
|
||||
ASSERT_EQ(outMsg->SetUsedSize(5), true);
|
||||
ASSERT_EQ(outMsg->SetUsedSize(5), true);
|
||||
ASSERT_EQ(outMsg->SetUsedSize(7), false);
|
||||
ASSERT_EQ(outMsg->GetSize(), 5);
|
||||
// check if the data is still intact
|
||||
ASSERT_EQ(static_cast<char*>(outMsg->GetData())[0], 'A');
|
||||
ASSERT_EQ(static_cast<char*>(outMsg->GetData())[1], 'B');
|
||||
ASSERT_EQ(static_cast<char*>(outMsg->GetData())[2], 'C');
|
||||
ASSERT_EQ(outMsg->SetUsedSize(250), true);
|
||||
ASSERT_EQ(outMsg->GetSize(), 250);
|
||||
ASSERT_EQ(static_cast<char*>(outMsg->GetData())[3], 'D');
|
||||
ASSERT_EQ(static_cast<char*>(outMsg->GetData())[4], 'E');
|
||||
ASSERT_EQ(outMsg->SetUsedSize(2), true);
|
||||
ASSERT_EQ(outMsg->GetSize(), 2);
|
||||
ASSERT_EQ(static_cast<char*>(outMsg->GetData())[0], 'A');
|
||||
ASSERT_EQ(static_cast<char*>(outMsg->GetData())[1], 'B');
|
||||
ASSERT_EQ(static_cast<char*>(outMsg->GetData())[2], 'C');
|
||||
FairMQMessagePtr msgCopy(push.NewMessage());
|
||||
msgCopy->Copy(*outMsg);
|
||||
ASSERT_EQ(msgCopy->GetSize(), 250);
|
||||
ASSERT_EQ(msgCopy->GetSize(), 2);
|
||||
|
||||
ASSERT_EQ(push.Send(outMsg), 250);
|
||||
ASSERT_EQ(push.Send(outMsg), 2);
|
||||
|
||||
FairMQMessagePtr inMsg(pull.NewMessage());
|
||||
ASSERT_EQ(pull.Receive(inMsg), 250);
|
||||
ASSERT_EQ(inMsg->GetSize(), 250);
|
||||
ASSERT_EQ(pull.Receive(inMsg), 2);
|
||||
ASSERT_EQ(inMsg->GetSize(), 2);
|
||||
ASSERT_EQ(static_cast<char*>(inMsg->GetData())[0], 'A');
|
||||
ASSERT_EQ(static_cast<char*>(inMsg->GetData())[1], 'B');
|
||||
ASSERT_EQ(static_cast<char*>(inMsg->GetData())[2], 'C');
|
||||
}
|
||||
|
||||
{
|
||||
|
36
test/properties/_suboptparser.cxx
Normal file
36
test/properties/_suboptparser.cxx
Normal file
@@ -0,0 +1,36 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2021 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 <fairmq/Properties.h>
|
||||
#include <fairmq/SuboptParser.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace std;
|
||||
using namespace fair::mq;
|
||||
|
||||
auto contains(Properties const& parsed, string_view key, string_view value) -> bool
|
||||
{
|
||||
return PropertyHelper::ConvertPropertyToString(parsed.at(string(key))) == value;
|
||||
}
|
||||
|
||||
TEST(SuboptParser, ChannelNameSelector)
|
||||
{
|
||||
Properties parsed(SuboptParser({"name=foo-data,address=tcp://0.0.0.0:6000,type=push",
|
||||
"bar-data:address=tcp://0.0.0.0:7000,type=pull"},
|
||||
"foo"));
|
||||
ASSERT_TRUE(contains(parsed, "chans.foo-data.0.address", "tcp://0.0.0.0:6000"));
|
||||
ASSERT_TRUE(contains(parsed, "chans.foo-data.0.type", "push"));
|
||||
ASSERT_TRUE(contains(parsed, "chans.bar-data.0.address", "tcp://0.0.0.0:7000"));
|
||||
ASSERT_TRUE(contains(parsed, "chans.bar-data.0.type", "pull"));
|
||||
}
|
||||
|
||||
} // namespace
|
@@ -23,6 +23,67 @@ namespace
|
||||
|
||||
using namespace std;
|
||||
|
||||
void RegionsCache(const string& transport, const string& address)
|
||||
{
|
||||
size_t session1 = fair::mq::tools::UuidHash();
|
||||
size_t session2 = fair::mq::tools::UuidHash();
|
||||
|
||||
fair::mq::ProgOptions config1;
|
||||
fair::mq::ProgOptions config2;
|
||||
config1.SetProperty<string>("session", to_string(session1));
|
||||
config2.SetProperty<string>("session", to_string(session2));
|
||||
|
||||
auto factory1 = FairMQTransportFactory::CreateTransportFactory(transport, fair::mq::tools::Uuid(), &config1);
|
||||
auto factory2 = FairMQTransportFactory::CreateTransportFactory(transport, fair::mq::tools::Uuid(), &config2);
|
||||
|
||||
auto region1 = factory1->CreateUnmanagedRegion(1000000, [](void*, size_t, void*) {});
|
||||
auto region2 = factory2->CreateUnmanagedRegion(1000000, [](void*, size_t, void*) {});
|
||||
void* r1ptr = region1->GetData();
|
||||
void* r2ptr = region2->GetData();
|
||||
|
||||
FairMQChannel push1("Push1", "push", factory1);
|
||||
FairMQChannel pull1("Pull1", "pull", factory1);
|
||||
push1.Bind(address + to_string(1));
|
||||
pull1.Connect(address + to_string(1));
|
||||
FairMQChannel push2("Push2", "push", factory2);
|
||||
FairMQChannel pull2("Pull2", "pull", factory2);
|
||||
push2.Bind(address + to_string(2));
|
||||
pull2.Connect(address + to_string(2));
|
||||
|
||||
{
|
||||
static_cast<char*>(r1ptr)[0] = 97; // a
|
||||
static_cast<char*>(static_cast<char*>(r1ptr) + 100)[0] = 98; // b
|
||||
static_cast<char*>(r2ptr)[0] = 99; // c
|
||||
static_cast<char*>(static_cast<char*>(r2ptr) + 100)[0] = 100; // d
|
||||
|
||||
FairMQMessagePtr m1(push1.NewMessage(region1, r1ptr, 100, nullptr));
|
||||
FairMQMessagePtr m2(push1.NewMessage(region1, static_cast<char*>(r1ptr) + 100, 100, nullptr));
|
||||
push1.Send(m1);
|
||||
push1.Send(m2);
|
||||
|
||||
FairMQMessagePtr m3(push2.NewMessage(region2, r2ptr, 100, nullptr));
|
||||
FairMQMessagePtr m4(push2.NewMessage(region2, static_cast<char*>(r2ptr) + 100, 100, nullptr));
|
||||
push2.Send(m3);
|
||||
push2.Send(m4);
|
||||
}
|
||||
|
||||
{
|
||||
FairMQMessagePtr m1(pull1.NewMessage());
|
||||
FairMQMessagePtr m2(pull1.NewMessage());
|
||||
ASSERT_EQ(pull1.Receive(m1), 100);
|
||||
ASSERT_EQ(pull1.Receive(m2), 100);
|
||||
ASSERT_EQ(static_cast<char*>(m1->GetData())[0], 'a');
|
||||
ASSERT_EQ(static_cast<char*>(m2->GetData())[0], 'b');
|
||||
|
||||
FairMQMessagePtr m3(pull2.NewMessage());
|
||||
FairMQMessagePtr m4(pull2.NewMessage());
|
||||
ASSERT_EQ(pull2.Receive(m3), 100);
|
||||
ASSERT_EQ(pull2.Receive(m4), 100);
|
||||
ASSERT_EQ(static_cast<char*>(m3->GetData())[0], 'c');
|
||||
ASSERT_EQ(static_cast<char*>(m4->GetData())[0], 'd');
|
||||
}
|
||||
}
|
||||
|
||||
void RegionEventSubscriptions(const string& transport)
|
||||
{
|
||||
size_t session{fair::mq::tools::UuidHash()};
|
||||
@@ -50,12 +111,12 @@ void RegionEventSubscriptions(const string& transport)
|
||||
|
||||
ASSERT_EQ(factory->SubscribedToRegionEvents(), false);
|
||||
factory->SubscribeToRegionEvents([&](FairMQRegionInfo info) {
|
||||
LOG(warn) << ">>>" << info.event;
|
||||
LOG(warn) << "managed: " << info.managed;
|
||||
LOG(warn) << "id: " << info.id;
|
||||
LOG(warn) << "ptr: " << info.ptr;
|
||||
LOG(warn) << "size: " << info.size;
|
||||
LOG(warn) << "flags: " << info.flags;
|
||||
LOG(info) << ">>> " << info.event << ": "
|
||||
<< (info.managed ? "managed" : "unmanaged")
|
||||
<< ", id: " << info.id
|
||||
<< ", ptr: " << info.ptr
|
||||
<< ", size: " << info.size
|
||||
<< ", flags: " << info.flags;
|
||||
if (info.event == FairMQRegionEvent::created) {
|
||||
if (info.id == id1) {
|
||||
ASSERT_EQ(info.size, size1);
|
||||
@@ -160,6 +221,16 @@ void RegionCallbacks(const string& transport, const string& _address)
|
||||
LOG(info) << "2 done.";
|
||||
}
|
||||
|
||||
TEST(Cache, zeromq)
|
||||
{
|
||||
RegionsCache("zeromq", "ipc://test_region_cache");
|
||||
}
|
||||
|
||||
TEST(Cache, shmem)
|
||||
{
|
||||
RegionsCache("shmem", "ipc://test_region_cache");
|
||||
}
|
||||
|
||||
TEST(EventSubscriptions, zeromq)
|
||||
{
|
||||
RegionEventSubscriptions("zeromq");
|
||||
|
Reference in New Issue
Block a user