mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2026-07-12 10:11:36 +00:00
Compare commits
57 Commits
v1.10.0
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
079c4cd232 | ||
|
|
8c60e8f1f7 | ||
|
|
a34fa64dc1 | ||
|
|
ed87268394 | ||
|
|
7e63d4ae9a | ||
|
|
1fb5ad8c33 | ||
|
|
add85cb18d | ||
|
|
331c50ab0e | ||
|
|
988ef81922 | ||
|
|
b568535910 | ||
|
|
2febbe3146 | ||
|
|
2bd9a072a9 | ||
|
|
fc69b5e7ae | ||
|
|
19e607e486 | ||
|
|
f08d42fcb8 | ||
|
|
1597999aed | ||
|
|
215c31428b | ||
|
|
a0e8271aca | ||
|
|
4b2c6cafac | ||
|
|
ab4bc49088 | ||
|
|
89e16c0b19 | ||
|
|
35d713ebaa | ||
|
|
4dfe24d411 | ||
|
|
d2aa2f10de | ||
|
|
d5e0c29ced | ||
|
|
0feda158b4 | ||
|
|
7a44c5e19e | ||
|
|
e23c4d8ff1 | ||
|
|
8ab00ecddc | ||
|
|
b53d25738e | ||
|
|
824825e911 | ||
|
|
2cf49cc50d | ||
|
|
7e30c33bcf | ||
|
|
0fd27cbbc3 | ||
|
|
f374e228ff | ||
|
|
bb5c0a998c | ||
|
|
ffc9c60f73 | ||
|
|
1186bda040 | ||
|
|
14be1ce368 | ||
|
|
83cef5bdca | ||
|
|
7f44fba4c0 | ||
|
|
3dcfc29ec2 | ||
|
|
fa64faf3f7 | ||
|
|
25abd605f3 | ||
|
|
695ed89b6c | ||
|
|
cd074a3f1e | ||
|
|
00c343858e | ||
|
|
5dfeebba95 | ||
|
|
642a4e06f0 | ||
|
|
89f9f09c82 | ||
|
|
a422361ee9 | ||
|
|
d1fbe4e89a | ||
|
|
ef98c9c7ec | ||
|
|
399170879c | ||
|
|
1392a31250 | ||
|
|
060a5f2599 | ||
|
|
7a8ccb8df6 |
@@ -1,3 +1,3 @@
|
|||||||
---
|
---
|
||||||
Checks: 'cppcoreguidelines-*,misc-unused-alias-decls,misc-unused-parameters,modernize-pass-by-value,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'
|
Checks: '-*,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-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/)'
|
HeaderFilterRegex: '/(fairmq/)'
|
||||||
|
|||||||
78
.github/actions/setup-deps/action.yml
vendored
Normal file
78
.github/actions/setup-deps/action.yml
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
name: Install dependencies
|
||||||
|
description: Setup spack and install dependencies
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
gcc:
|
||||||
|
description: 'GCC version to use'
|
||||||
|
required: true
|
||||||
|
env:
|
||||||
|
description: 'Spack environment name (latest, boost187, tsan)'
|
||||||
|
default: 'latest'
|
||||||
|
fresh:
|
||||||
|
description: 'Use fresh concretization'
|
||||||
|
default: 'false'
|
||||||
|
push-gcc:
|
||||||
|
description: 'Push the freshly-built gcc node to the buildcache (buildcache workflow only)'
|
||||||
|
default: 'false'
|
||||||
|
push-token:
|
||||||
|
description: 'Token with packages:write, required when push-gcc is true'
|
||||||
|
default: ''
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
# Composite action step names are not shown in the UI (https://github.com/actions/runner/issues/1877),
|
||||||
|
# so we use ::group:: to make them visible.
|
||||||
|
steps:
|
||||||
|
- name: Setup spack
|
||||||
|
uses: spack/setup-spack@v3
|
||||||
|
with:
|
||||||
|
color: true
|
||||||
|
buildcache: true
|
||||||
|
|
||||||
|
- name: Find system compiler
|
||||||
|
shell: spack-bash {0}
|
||||||
|
run: |
|
||||||
|
echo "::group::Find system compiler"
|
||||||
|
spack compiler find
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
- name: Add FairMQ buildcache mirror
|
||||||
|
shell: spack-bash {0}
|
||||||
|
run: |
|
||||||
|
echo "::group::Add FairMQ buildcache mirror"
|
||||||
|
spack mirror add --unsigned --type binary \
|
||||||
|
ghcr-buildcache oci://ghcr.io/fairrootgroup/fairmq-spack-buildcache
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
- name: Install GCC
|
||||||
|
shell: spack-bash {0}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ inputs.push-token }}
|
||||||
|
run: |
|
||||||
|
echo "::group::Install GCC"
|
||||||
|
spack install ${{ inputs.fresh == 'true' && '--fresh' || '' }} gcc@${{ inputs.gcc }} target=x86_64_v3
|
||||||
|
gcc_hash=$(spack find --json gcc@${{ inputs.gcc }} target=x86_64_v3 | jq -r 'sort_by(.version | split(".") | map(tonumber)) | last | .hash')
|
||||||
|
if [ "${{ inputs.push-gcc }}" = "true" ]; then
|
||||||
|
# Push the gcc node now, BEFORE `spack compiler find` registers it as an
|
||||||
|
# external -- externals are excluded from `buildcache push`. This is what
|
||||||
|
# lets CI pull gcc from the cache (~1 min) instead of building it (~1 h).
|
||||||
|
# --allow-missing: when gcc itself was pulled from the cache, its
|
||||||
|
# build-time dependencies are not installed locally and would
|
||||||
|
# otherwise fail the push.
|
||||||
|
spack mirror set --oci-username ${{ github.actor }} --oci-password-variable GITHUB_TOKEN ghcr-buildcache
|
||||||
|
spack buildcache push --unsigned --allow-missing ghcr-buildcache /$gcc_hash
|
||||||
|
fi
|
||||||
|
spack compiler find "$(spack location -i /$gcc_hash)"
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
shell: spack-bash {0}
|
||||||
|
run: |
|
||||||
|
echo "::group::Install dependencies"
|
||||||
|
spack repo add "$GITHUB_WORKSPACE/test/ci/spack_repo/fairmq_ci"
|
||||||
|
spack env create fairmq test/ci/spack-${{ inputs.env }}.yaml
|
||||||
|
spack -e fairmq add gcc@${{ inputs.gcc }}
|
||||||
|
spack -e fairmq config add "packages:all:require:'%gcc@${{ inputs.gcc }}'"
|
||||||
|
spack -e fairmq install --fail-fast ${{ inputs.fresh == 'true' && '--fresh' || '' }}
|
||||||
|
spack env activate --sh fairmq | grep '^export ' | sed 's/^export //;s/;$//' >> $GITHUB_ENV
|
||||||
|
echo "::endgroup::"
|
||||||
82
.github/workflows/buildcache.yml
vendored
Normal file
82
.github/workflows/buildcache.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
name: Spack Buildcache
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 3 * * 0' # Weekly on Sunday at 3am UTC
|
||||||
|
push:
|
||||||
|
branches: [dev, master]
|
||||||
|
paths:
|
||||||
|
- 'test/ci/spack-*.yaml'
|
||||||
|
- 'test/ci/spack_repo/**'
|
||||||
|
- '.github/workflows/buildcache.yml'
|
||||||
|
- '.github/actions/setup-deps/**'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
if: github.repository == 'FairRootGroup/FairMQ'
|
||||||
|
name: ${{ matrix.env }}-gcc-${{ matrix.gcc }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
gcc: ['12', '13', '14', '15']
|
||||||
|
env: ['latest']
|
||||||
|
include:
|
||||||
|
- gcc: '15'
|
||||||
|
env: 'boost187'
|
||||||
|
- gcc: '15'
|
||||||
|
env: 'tsan'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Setup spack environment
|
||||||
|
uses: ./.github/actions/setup-deps
|
||||||
|
with:
|
||||||
|
gcc: ${{ matrix.gcc }}
|
||||||
|
env: ${{ matrix.env }}
|
||||||
|
fresh: 'true'
|
||||||
|
push-gcc: 'true'
|
||||||
|
push-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Push to buildcache
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
shell: spack-bash {0}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
spack -e fairmq mirror set --oci-username ${{ github.actor }} --oci-password-variable GITHUB_TOKEN ghcr-buildcache
|
||||||
|
# --allow-missing: build-time dependencies of specs that were
|
||||||
|
# satisfied from the buildcache are not installed locally and
|
||||||
|
# would otherwise fail the whole push.
|
||||||
|
spack -e fairmq buildcache push --unsigned --allow-missing ghcr-buildcache
|
||||||
|
|
||||||
|
update-index:
|
||||||
|
if: github.repository == 'FairRootGroup/FairMQ' && !cancelled()
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Setup spack
|
||||||
|
uses: spack/setup-spack@v3
|
||||||
|
with:
|
||||||
|
color: true
|
||||||
|
|
||||||
|
- name: Update buildcache index
|
||||||
|
shell: spack-bash {0}
|
||||||
|
run: |
|
||||||
|
spack env create fairmq test/ci/spack-latest.yaml
|
||||||
|
spack -e fairmq mirror set --oci-username ${{ github.actor }} --oci-password-variable GITHUB_TOKEN ghcr-buildcache
|
||||||
|
spack -e fairmq buildcache update-index ghcr-buildcache
|
||||||
2
.github/workflows/check_metadata.yaml
vendored
2
.github/workflows/check_metadata.yaml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- name: Try updating metadata
|
- name: Try updating metadata
|
||||||
run: python meta_update.py
|
run: python meta_update.py
|
||||||
- name: Check for Updates
|
- name: Check for Updates
|
||||||
|
|||||||
209
.github/workflows/ci.yml
vendored
Normal file
209
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master, dev]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
if: github.repository == 'FairRootGroup/FairMQ'
|
||||||
|
name: ${{ matrix.env }}-gcc-${{ matrix.gcc }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
gcc: ['12', '13', '14', '15']
|
||||||
|
env: ['latest']
|
||||||
|
include:
|
||||||
|
- gcc: '15'
|
||||||
|
env: 'boost187'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
fetch-tags: true
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup spack environment
|
||||||
|
uses: ./.github/actions/setup-deps
|
||||||
|
with:
|
||||||
|
gcc: ${{ matrix.gcc }}
|
||||||
|
env: ${{ matrix.env }}
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23
|
||||||
|
with:
|
||||||
|
key: ${{ github.job }}-${{ matrix.env }}-gcc${{ matrix.gcc }}
|
||||||
|
max-size: 500M
|
||||||
|
|
||||||
|
- name: Configure and Build
|
||||||
|
uses: threeal/cmake-action@725d1314ccf9ea922805d7e3f9d9bcbca892b406 # v2.1.0
|
||||||
|
with:
|
||||||
|
generator: Ninja
|
||||||
|
options: |
|
||||||
|
CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
|
CMAKE_INSTALL_PREFIX=${{ github.workspace }}/install
|
||||||
|
BUILD_TESTING=ON
|
||||||
|
CMAKE_C_COMPILER_LAUNCHER=ccache
|
||||||
|
CMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
# Region/segment tests mlock() shared memory; raise the locked-memory
|
||||||
|
# limit so it does not hit RLIMIT_MEMLOCK on the runner.
|
||||||
|
sudo prlimit --pid $$ --memlock=unlimited:unlimited
|
||||||
|
ulimit -l
|
||||||
|
ctest --test-dir build --output-on-failure --no-tests=error
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
run: cmake --install build
|
||||||
|
|
||||||
|
sanitizers:
|
||||||
|
if: github.repository == 'FairRootGroup/FairMQ'
|
||||||
|
name: ${{ matrix.sanitizer.name }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
sanitizer:
|
||||||
|
- name: asan+lsan+ubsan
|
||||||
|
gcc: '14'
|
||||||
|
env: latest
|
||||||
|
options: |
|
||||||
|
ENABLE_SANITIZER_ADDRESS=ON
|
||||||
|
ENABLE_SANITIZER_LEAK=ON
|
||||||
|
ENABLE_SANITIZER_UNDEFINED_BEHAVIOR=ON
|
||||||
|
cxx-flags: -O1 -fno-omit-frame-pointer
|
||||||
|
- name: tsan
|
||||||
|
gcc: '15'
|
||||||
|
env: tsan
|
||||||
|
options: ENABLE_SANITIZER_THREAD=ON
|
||||||
|
cxx-flags: -fno-omit-frame-pointer
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
fetch-tags: true
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup spack environment
|
||||||
|
uses: ./.github/actions/setup-deps
|
||||||
|
with:
|
||||||
|
gcc: ${{ matrix.sanitizer.gcc }}
|
||||||
|
env: ${{ matrix.sanitizer.env }}
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23
|
||||||
|
with:
|
||||||
|
key: ${{ github.job }}-${{ matrix.sanitizer.name }}
|
||||||
|
max-size: 500M
|
||||||
|
|
||||||
|
- name: Locate instrumented libstdc++
|
||||||
|
if: matrix.sanitizer.name == 'tsan'
|
||||||
|
shell: spack-bash {0}
|
||||||
|
# The test processes must load the tsan-instrumented libstdc++
|
||||||
|
# instead of the compiler's own (same soname, LD_LIBRARY_PATH beats
|
||||||
|
# the RUNPATH). Set per test via ctest, not at the job level: like
|
||||||
|
# any shared library built with gcc -fsanitize=thread it has
|
||||||
|
# unresolved __tsan_* symbols, so loading it into uninstrumented
|
||||||
|
# tools (cmake, ctest, ninja) would break them.
|
||||||
|
run: |
|
||||||
|
prefix=$(spack -e fairmq location -i libstdcxx-tsan)
|
||||||
|
echo "test_library_path=$prefix/lib" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Configure and Build
|
||||||
|
uses: threeal/cmake-action@725d1314ccf9ea922805d7e3f9d9bcbca892b406 # v2.1.0
|
||||||
|
with:
|
||||||
|
generator: Ninja
|
||||||
|
cxx-flags: ${{ matrix.sanitizer.cxx-flags }}
|
||||||
|
options: |
|
||||||
|
CMAKE_BUILD_TYPE=Debug
|
||||||
|
BUILD_TESTING=ON
|
||||||
|
CMAKE_C_COMPILER_LAUNCHER=ccache
|
||||||
|
CMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
FAIRMQ_TEST_LD_LIBRARY_PATH=${{ env.test_library_path }}
|
||||||
|
${{ matrix.sanitizer.options }}
|
||||||
|
|
||||||
|
- name: Verify tsan instrumentation wiring
|
||||||
|
if: matrix.sanitizer.name == 'tsan'
|
||||||
|
shell: spack-bash {0}
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
# the test environment must resolve libstdc++ to the instrumented copy
|
||||||
|
LD_LIBRARY_PATH=$test_library_path ldd build/test/testsuite_Channel \
|
||||||
|
| grep 'libstdc++' | tee /dev/stderr | grep -q libstdcxx-tsan
|
||||||
|
# libzmq must be instrumented
|
||||||
|
nm -D --undefined-only "$(spack -e fairmq location -i libzmq)/lib/libzmq.so" \
|
||||||
|
| grep -q __tsan_
|
||||||
|
# the instrumented libstdc++ must match the compiler release exactly,
|
||||||
|
# or binaries may reference GLIBCXX versions the runtime lacks
|
||||||
|
# (--color=never: the CI config forces SPACK_COLOR=always, which
|
||||||
|
# would wrap the version in ANSI escapes)
|
||||||
|
test "$(spack --color=never -e fairmq find --format '{version}' libstdcxx-tsan)" \
|
||||||
|
= "$(g++ -dumpfullversion)"
|
||||||
|
# the LD_LIBRARY_PATH prepend must reach the registered tests
|
||||||
|
# (via a file: grep -q quits on first match, and SIGPIPE on the
|
||||||
|
# large json output would fail the step under pipefail)
|
||||||
|
ctest --test-dir build --show-only=json-v1 > ctest-show-only.json
|
||||||
|
grep -q libstdcxx-tsan ctest-show-only.json
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
# Region/segment tests mlock() shared memory; raise the locked-memory
|
||||||
|
# limit so it does not hit RLIMIT_MEMLOCK on the runner.
|
||||||
|
sudo prlimit --pid $$ --memlock=unlimited:unlimited
|
||||||
|
ulimit -l
|
||||||
|
ctest --test-dir build --output-on-failure --no-tests=error
|
||||||
|
|
||||||
|
static-analysis:
|
||||||
|
if: github.repository == 'FairRootGroup/FairMQ'
|
||||||
|
name: static-analysis
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
fetch-tags: true
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup spack environment
|
||||||
|
uses: ./.github/actions/setup-deps
|
||||||
|
with:
|
||||||
|
gcc: '14'
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23
|
||||||
|
with:
|
||||||
|
key: ${{ github.job }}
|
||||||
|
max-size: 500M
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
run: |
|
||||||
|
cmake -S . -B build -G Ninja \
|
||||||
|
-DCMAKE_BUILD_TYPE=Debug \
|
||||||
|
-DBUILD_TESTING=ON \
|
||||||
|
-DRUN_STATIC_ANALYSIS=ON \
|
||||||
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
set -o pipefail
|
||||||
|
cmake --build build 2>&1 | tee build.log
|
||||||
|
|
||||||
|
- name: Check for warnings
|
||||||
|
run: |
|
||||||
|
test -f build.log || { echo "::error::build.log was not produced"; exit 1; }
|
||||||
|
if grep -q "warning:" build.log; then
|
||||||
|
echo "::error::Static analysis found warnings"
|
||||||
|
grep "warning:" build.log
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
2
.github/workflows/codemeta_validate.yaml
vendored
2
.github/workflows/codemeta_validate.yaml
vendored
@@ -16,6 +16,6 @@ jobs:
|
|||||||
container:
|
container:
|
||||||
image: gitlab-registry.in2p3.fr/escape2020/wp3/eossr:v1.0
|
image: gitlab-registry.in2p3.fr/escape2020/wp3/eossr:v1.0
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- name: validate codemeta
|
- name: validate codemeta
|
||||||
run: eossr-metadata-validator codemeta.json
|
run: eossr-metadata-validator codemeta.json
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ include(FairMQDependencies)
|
|||||||
|
|
||||||
|
|
||||||
# Targets ######################################################################
|
# Targets ######################################################################
|
||||||
|
if(FAIRMQ_TEST_LD_LIBRARY_PATH AND CMAKE_VERSION VERSION_LESS 3.22)
|
||||||
|
# The per-test injection relies on ctest's ENVIRONMENT_MODIFICATION, which
|
||||||
|
# older CMake silently drops -- the tests would run against the default
|
||||||
|
# runtime while looking green.
|
||||||
|
message(FATAL_ERROR "FAIRMQ_TEST_LD_LIBRARY_PATH requires CMake >= 3.22")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(BUILD_FAIRMQ)
|
if(BUILD_FAIRMQ)
|
||||||
add_subdirectory(fairmq)
|
add_subdirectory(fairmq)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
################################################################################
|
|
||||||
# Copyright (C) 2021-2023 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" #
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
cmake_host_system_information(RESULT fqdn QUERY FQDN)
|
|
||||||
|
|
||||||
set(CTEST_SOURCE_DIRECTORY .)
|
|
||||||
set(CTEST_BINARY_DIRECTORY build)
|
|
||||||
set(CTEST_CMAKE_GENERATOR "Ninja")
|
|
||||||
set(CTEST_USE_LAUNCHERS ON)
|
|
||||||
set(CTEST_CONFIGURATION_TYPE "RelWithDebInfo")
|
|
||||||
set(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE 102400)
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
if ("$ENV{CTEST_SITE}" STREQUAL "")
|
|
||||||
set(CTEST_SITE "${fqdn}")
|
|
||||||
else()
|
|
||||||
set(CTEST_SITE $ENV{CTEST_SITE})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if ("$ENV{LABEL}" STREQUAL "")
|
|
||||||
set(CTEST_BUILD_NAME "build")
|
|
||||||
else()
|
|
||||||
set(CTEST_BUILD_NAME $ENV{LABEL})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ctest_start(Continuous)
|
|
||||||
|
|
||||||
list(APPEND options "-DDISABLE_COLOR=ON" "-DBUILD_EXAMPLES=ON" "-DBUILD_TESTING=ON")
|
|
||||||
if(RUN_STATIC_ANALYSIS)
|
|
||||||
list(APPEND options "-DRUN_STATIC_ANALYSIS=ON")
|
|
||||||
endif()
|
|
||||||
if(CMAKE_BUILD_TYPE)
|
|
||||||
set(CTEST_CONFIGURATION_TYPE ${CMAKE_BUILD_TYPE})
|
|
||||||
endif()
|
|
||||||
if(ENABLE_SANITIZER_ADDRESS)
|
|
||||||
list(APPEND options "-DENABLE_SANITIZER_ADDRESS=ON")
|
|
||||||
endif()
|
|
||||||
if(ENABLE_SANITIZER_LEAK)
|
|
||||||
list(APPEND options "-DENABLE_SANITIZER_LEAK=ON")
|
|
||||||
endif()
|
|
||||||
if(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR)
|
|
||||||
list(APPEND options "-DENABLE_SANITIZER_UNDEFINED_BEHAVIOR=ON")
|
|
||||||
endif()
|
|
||||||
if(ENABLE_SANITIZER_MEMORY)
|
|
||||||
list(APPEND options "-DENABLE_SANITIZER_MEMORY=ON")
|
|
||||||
endif()
|
|
||||||
if(ENABLE_SANITIZER_THREAD)
|
|
||||||
list(APPEND options "-DENABLE_SANITIZER_THREAD=ON")
|
|
||||||
endif()
|
|
||||||
if(CMAKE_CXX_COMPILER)
|
|
||||||
list(APPEND options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}")
|
|
||||||
endif()
|
|
||||||
if(CMAKE_CXX_FLAGS)
|
|
||||||
list(APPEND options "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}")
|
|
||||||
endif()
|
|
||||||
list(REMOVE_DUPLICATES options)
|
|
||||||
list(JOIN options ";" optionsstr)
|
|
||||||
ctest_configure(OPTIONS "${optionsstr}")
|
|
||||||
|
|
||||||
ctest_submit()
|
|
||||||
|
|
||||||
ctest_build(FLAGS "-j${NCPUS}")
|
|
||||||
|
|
||||||
ctest_submit()
|
|
||||||
|
|
||||||
if(NOT RUN_STATIC_ANALYSIS)
|
|
||||||
ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}"
|
|
||||||
PARALLEL_LEVEL ${NCPUS}
|
|
||||||
SCHEDULE_RANDOM ON
|
|
||||||
RETURN_VALUE _ctest_test_ret_val)
|
|
||||||
|
|
||||||
ctest_submit()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(_ctest_test_ret_val)
|
|
||||||
Message(FATAL_ERROR "Some tests failed.")
|
|
||||||
endif()
|
|
||||||
118
Jenkinsfile
vendored
118
Jenkinsfile
vendored
@@ -1,118 +0,0 @@
|
|||||||
#!groovy
|
|
||||||
|
|
||||||
def jobMatrix(String type, List specs) {
|
|
||||||
def nodes = [:]
|
|
||||||
for (spec in specs) {
|
|
||||||
def job = ""
|
|
||||||
def selector = "slurm"
|
|
||||||
def os = ""
|
|
||||||
def ver = ""
|
|
||||||
|
|
||||||
if (type == 'build') {
|
|
||||||
job = "${spec.os}-${spec.ver}-${spec.arch}-${spec.compiler}"
|
|
||||||
if (spec.os =~ /^macos/) {
|
|
||||||
selector = "${spec.os}-${spec.ver}-${spec.arch}"
|
|
||||||
}
|
|
||||||
os = spec.os
|
|
||||||
ver = spec.ver
|
|
||||||
} else { // == 'check'
|
|
||||||
job = "${spec.name}"
|
|
||||||
os = 'fedora'
|
|
||||||
ver = '36'
|
|
||||||
}
|
|
||||||
|
|
||||||
def label = "${job}"
|
|
||||||
def extra = spec.extra
|
|
||||||
|
|
||||||
nodes[label] = {
|
|
||||||
node(selector) {
|
|
||||||
githubNotify(context: "${label}", description: 'Building ...', status: 'PENDING')
|
|
||||||
try {
|
|
||||||
deleteDir()
|
|
||||||
checkout scm
|
|
||||||
|
|
||||||
def jobscript = 'job.sh'
|
|
||||||
def ctestcmd = "ctest ${extra} -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 \"${ctestcmd}\" >> ${jobscript}
|
|
||||||
"""
|
|
||||||
sh "cat ${jobscript}"
|
|
||||||
sh "bash ${jobscript}"
|
|
||||||
} else { // selector == "slurm"
|
|
||||||
def imageurl = "oras://ghcr.io/fairrootgroup/fairmq-dev/${os}-${ver}-sif:latest"
|
|
||||||
def execopts = "--ipc --uts --pid -B/shared"
|
|
||||||
def containercmd = "singularity exec ${execopts} ${imageurl} bash -l -c \\\"${ctestcmd} ${extra}\\\""
|
|
||||||
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}"
|
|
||||||
|
|
||||||
if (job == "static-analyzers") {
|
|
||||||
recordIssues(enabledForFailure: true,
|
|
||||||
tools: [gcc(pattern: 'build/Testing/Temporary/*.log')],
|
|
||||||
filters: [excludeFile('extern/*'), excludeFile('usr/*')],
|
|
||||||
skipBlames: true,
|
|
||||||
skipPublishingChecks: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteDir()
|
|
||||||
githubNotify(context: "${label}", description: 'Success', status: 'SUCCESS')
|
|
||||||
} catch (e) {
|
|
||||||
deleteDir()
|
|
||||||
githubNotify(context: "${label}", description: 'Error', status: 'ERROR')
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nodes
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline{
|
|
||||||
agent none
|
|
||||||
stages {
|
|
||||||
stage("CI") {
|
|
||||||
steps{
|
|
||||||
script {
|
|
||||||
def builds = jobMatrix('build', [
|
|
||||||
[os: 'ubuntu', ver: '20.04', arch: 'x86_64', compiler: 'gcc-9'],
|
|
||||||
[os: 'ubuntu', ver: '22.04', arch: 'x86_64', compiler: 'gcc-11'],
|
|
||||||
[os: 'ubuntu', ver: '24.04', arch: 'x86_64', compiler: 'gcc-13'],
|
|
||||||
[os: 'fedora', ver: '33', arch: 'x86_64', compiler: 'gcc-10'],
|
|
||||||
[os: 'fedora', ver: '34', arch: 'x86_64', compiler: 'gcc-11'],
|
|
||||||
[os: 'fedora', ver: '35', arch: 'x86_64', compiler: 'gcc-11'],
|
|
||||||
[os: 'fedora', ver: '36', arch: 'x86_64', compiler: 'gcc-12'],
|
|
||||||
[os: 'fedora', ver: '37', arch: 'x86_64', compiler: 'gcc-12'],
|
|
||||||
[os: 'fedora', ver: '38', arch: 'x86_64', compiler: 'gcc-13'],
|
|
||||||
[os: 'fedora', ver: '39', arch: 'x86_64', compiler: 'gcc-13'],
|
|
||||||
[os: 'fedora', ver: '40', arch: 'x86_64', compiler: 'gcc-14'],
|
|
||||||
[os: 'macos', ver: '14', arch: 'x86_64', compiler: 'apple-clang-16'],
|
|
||||||
[os: 'macos', ver: '15', arch: 'x86_64', compiler: 'apple-clang-16'],
|
|
||||||
[os: 'macos', ver: '15', arch: 'arm64', compiler: 'apple-clang-16'],
|
|
||||||
])
|
|
||||||
|
|
||||||
def all_debug = "-DCMAKE_BUILD_TYPE=Debug"
|
|
||||||
|
|
||||||
def checks = jobMatrix('check', [
|
|
||||||
[name: 'static-analyzers', extra: "${all_debug} -DRUN_STATIC_ANALYSIS=ON"],
|
|
||||||
[name: '{address,leak,ub}-sanitizers',
|
|
||||||
extra: "${all_debug} -DENABLE_SANITIZER_ADDRESS=ON -DENABLE_SANITIZER_LEAK=ON -DENABLE_SANITIZER_UNDEFINED_BEHAVIOUR=ON -DCMAKE_CXX_FLAGS='-O1 -fno-omit-frame-pointer'"],
|
|
||||||
[name: 'thread-sanitizer', extra: "${all_debug} -DENABLE_SANITIZER_THREAD=ON -DCMAKE_CXX_COMPILER=clang++"],
|
|
||||||
])
|
|
||||||
|
|
||||||
parallel(builds + checks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -68,6 +68,7 @@ function(build_bundled package bundle)
|
|||||||
|
|
||||||
exec(${CMAKE_COMMAND} -S ${${package}_SOURCE_DIR} -B ${${package}_BINARY_DIR} -G ${CMAKE_GENERATOR}
|
exec(${CMAKE_COMMAND} -S ${${package}_SOURCE_DIR} -B ${${package}_BINARY_DIR} -G ${CMAKE_GENERATOR}
|
||||||
-DCMAKE_INSTALL_PREFIX=${${package}_INSTALL_DIR} -DBUILD_GMOCK=OFF
|
-DCMAKE_INSTALL_PREFIX=${${package}_INSTALL_DIR} -DBUILD_GMOCK=OFF
|
||||||
|
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||||
)
|
)
|
||||||
exec(${CMAKE_COMMAND} --build ${${package}_BINARY_DIR})
|
exec(${CMAKE_COMMAND} --build ${${package}_BINARY_DIR})
|
||||||
exec(${CMAKE_COMMAND} --build ${${package}_BINARY_DIR} --target install)
|
exec(${CMAKE_COMMAND} --build ${${package}_BINARY_DIR} --target install)
|
||||||
|
|||||||
@@ -23,6 +23,18 @@ if(BUILD_FAIRMQ OR BUILD_TIDY_TOOL)
|
|||||||
find_package2(PUBLIC Boost REQUIRED VERSION 1.66
|
find_package2(PUBLIC Boost REQUIRED VERSION 1.66
|
||||||
COMPONENTS container program_options filesystem date_time regex
|
COMPONENTS container program_options filesystem date_time regex
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Check Boost.Process compatibility
|
||||||
|
# Boost 1.88 has broken Boost.Process v2 without v1 compatibility headers
|
||||||
|
# Boost 1.89+ provides <boost/process/v1.hpp> for the old API
|
||||||
|
if(Boost_VERSION VERSION_EQUAL "1.88.0")
|
||||||
|
message(FATAL_ERROR "Boost version 1.88 is not supported due to Boost.Process API changes. "
|
||||||
|
"Please use Boost < 1.88 or >= 1.89")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(Boost_VERSION VERSION_GREATER_EQUAL "1.89")
|
||||||
|
set(FAIRMQ_BOOST_PROCESS_V1_HEADER ON CACHE INTERNAL "Use boost/process/v1.hpp for Boost >= 1.89")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(BUILD_FAIRMQ)
|
if(BUILD_FAIRMQ)
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ endif()
|
|||||||
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_LIBDIR}" isSystemDir)
|
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_LIBDIR}" isSystemDir)
|
||||||
if("${isSystemDir}" STREQUAL "-1")
|
if("${isSystemDir}" STREQUAL "-1")
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
list(APPEND CMAKE_EXE_LINKER_FLAGS "-Wl,--enable-new-dtags")
|
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,--enable-new-dtags")
|
||||||
list(APPEND CMAKE_SHARED_LINKER_FLAGS "-Wl,--enable-new-dtags")
|
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -Wl,--enable-new-dtags")
|
||||||
list(PREPEND CMAKE_INSTALL_RPATH "$ORIGIN/../${PROJECT_INSTALL_LIBDIR}")
|
list(PREPEND CMAKE_INSTALL_RPATH "$ORIGIN/../${PROJECT_INSTALL_LIBDIR}")
|
||||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||||
list(PREPEND CMAKE_INSTALL_RPATH "@loader_path/../${PROJECT_INSTALL_LIBDIR}")
|
list(PREPEND CMAKE_INSTALL_RPATH "@loader_path/../${PROJECT_INSTALL_LIBDIR}")
|
||||||
|
|||||||
@@ -12,6 +12,22 @@ set(test_script_prefix "test-ex")
|
|||||||
set(testsuite "Example")
|
set(testsuite "Example")
|
||||||
set(transports "zeromq" "shmem")
|
set(transports "zeromq" "shmem")
|
||||||
|
|
||||||
|
# Environment for every example test (directory scope, so the subdirectories
|
||||||
|
# see it too)
|
||||||
|
set(env_mods)
|
||||||
|
if(ENABLE_SANITIZER_LEAK AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.22)
|
||||||
|
get_filename_component(lsan_supps "${CMAKE_SOURCE_DIR}/test/leak_sanitizer_suppressions.txt" ABSOLUTE)
|
||||||
|
list(APPEND env_mods "LSAN_OPTIONS=set:suppressions=${lsan_supps}")
|
||||||
|
endif()
|
||||||
|
# Run the example tests against an alternative runtime library directory as
|
||||||
|
# well (see test/CMakeLists.txt). The test scripts only launch instrumented
|
||||||
|
# binaries (bash itself does not link libstdc++). Note: unlike the
|
||||||
|
# testsuites, the example binaries get no locale-cache warmup -- their
|
||||||
|
# main() comes from the installed public header fairmq/runDevice.h.
|
||||||
|
if(FAIRMQ_TEST_LD_LIBRARY_PATH)
|
||||||
|
list(APPEND env_mods "LD_LIBRARY_PATH=path_list_prepend:${FAIRMQ_TEST_LD_LIBRARY_PATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
function(add_example)
|
function(add_example)
|
||||||
cmake_parse_arguments(PARSE_ARGV 0 ARG
|
cmake_parse_arguments(PARSE_ARGV 0 ARG
|
||||||
"CONFIG;NO_TRANSPORT;NO_TEST"
|
"CONFIG;NO_TRANSPORT;NO_TEST"
|
||||||
@@ -29,11 +45,6 @@ function(add_example)
|
|||||||
message(FATAL_ERROR "NAME arg is required")
|
message(FATAL_ERROR "NAME arg is required")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_SANITIZER_LEAK AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.22)
|
|
||||||
get_filename_component(lsan_supps "${CMAKE_SOURCE_DIR}/test/leak_sanitizer_suppressions.txt" ABSOLUTE)
|
|
||||||
set(lsan_options "LSAN_OPTIONS=set:suppressions=${lsan_supps}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(ARG_DEVICE)
|
if(ARG_DEVICE)
|
||||||
set(exe_targets)
|
set(exe_targets)
|
||||||
foreach(device IN LISTS ARG_DEVICE)
|
foreach(device IN LISTS ARG_DEVICE)
|
||||||
@@ -78,8 +89,8 @@ function(add_example)
|
|||||||
set(test "${testsuite}.${name}.${transport}")
|
set(test "${testsuite}.${name}.${transport}")
|
||||||
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${test_script} ${transport})
|
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${test_script} ${transport})
|
||||||
set_tests_properties(${test} PROPERTIES TIMEOUT "30")
|
set_tests_properties(${test} PROPERTIES TIMEOUT "30")
|
||||||
if(lsan_options)
|
if(env_mods)
|
||||||
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION ${lsan_options})
|
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION "${env_mods}")
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
foreach(transport IN LISTS transports)
|
foreach(transport IN LISTS transports)
|
||||||
@@ -88,16 +99,16 @@ function(add_example)
|
|||||||
set(test "${testsuite}.${name}.${variant}.${transport}")
|
set(test "${testsuite}.${name}.${variant}.${transport}")
|
||||||
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${test_script} ${transport} ${variant})
|
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${test_script} ${transport} ${variant})
|
||||||
set_tests_properties(${test} PROPERTIES TIMEOUT "30")
|
set_tests_properties(${test} PROPERTIES TIMEOUT "30")
|
||||||
if(lsan_options)
|
if(env_mods)
|
||||||
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION ${lsan_options})
|
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION "${env_mods}")
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
else()
|
else()
|
||||||
set(test "${testsuite}.${name}.${transport}")
|
set(test "${testsuite}.${name}.${transport}")
|
||||||
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${test_script} ${transport})
|
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${test_script} ${transport})
|
||||||
set_tests_properties(${test} PROPERTIES TIMEOUT "30")
|
set_tests_properties(${test} PROPERTIES TIMEOUT "30")
|
||||||
if(lsan_options)
|
if(env_mods)
|
||||||
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION ${lsan_options})
|
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION "${env_mods}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ set_target_properties(${exe} PROPERTIES ENABLE_EXPORTS ON)
|
|||||||
set(test "${testsuite}.${name}")
|
set(test "${testsuite}.${name}")
|
||||||
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${exe})
|
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${exe})
|
||||||
set_tests_properties(${test} PROPERTIES TIMEOUT 30)
|
set_tests_properties(${test} PROPERTIES TIMEOUT 30)
|
||||||
if(lsan_options)
|
# (the previous `if(lsan_options)` here could never fire -- that variable
|
||||||
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION ${lsan_options})
|
# only ever existed in the add_example() function scope)
|
||||||
|
if(env_mods)
|
||||||
|
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION "${env_mods}")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
2
extern/googletest
vendored
2
extern/googletest
vendored
Submodule extern/googletest updated: 7d76a231b0...973323ed64
@@ -176,6 +176,9 @@ if(BUILD_FAIRMQ)
|
|||||||
FAIRMQ_HAS_STD_FILESYSTEM=${FAIRMQ_HAS_STD_FILESYSTEM}
|
FAIRMQ_HAS_STD_FILESYSTEM=${FAIRMQ_HAS_STD_FILESYSTEM}
|
||||||
FAIRMQ_HAS_STD_PMR=${FAIRMQ_HAS_STD_PMR}
|
FAIRMQ_HAS_STD_PMR=${FAIRMQ_HAS_STD_PMR}
|
||||||
)
|
)
|
||||||
|
if(FAIRMQ_BOOST_PROCESS_V1_HEADER)
|
||||||
|
target_compile_definitions(${target} PRIVATE FAIRMQ_BOOST_PROCESS_V1_HEADER)
|
||||||
|
endif()
|
||||||
if(DEFINED FAIRMQ_CHANNEL_DEFAULT_AUTOBIND)
|
if(DEFINED FAIRMQ_CHANNEL_DEFAULT_AUTOBIND)
|
||||||
# translate CMake boolean (TRUE, FALSE, 0, 1, OFF, ON) into C++ boolean literal (true, false)
|
# translate CMake boolean (TRUE, FALSE, 0, 1, OFF, ON) into C++ boolean literal (true, false)
|
||||||
if(FAIRMQ_CHANNEL_DEFAULT_AUTOBIND)
|
if(FAIRMQ_CHANNEL_DEFAULT_AUTOBIND)
|
||||||
|
|||||||
@@ -181,7 +181,8 @@ try {
|
|||||||
|
|
||||||
// validate channel name
|
// validate channel name
|
||||||
smatch m;
|
smatch m;
|
||||||
if (regex_search(fName, m, regex("[^a-zA-Z0-9\\-_\\[\\]#]"))) {
|
static regex const invalidName(R"([^a-zA-Z0-9\-_\[\]#])");
|
||||||
|
if (regex_search(fName, m, invalidName)) {
|
||||||
ss << "INVALID";
|
ss << "INVALID";
|
||||||
LOG(debug) << ss.str();
|
LOG(debug) << ss.str();
|
||||||
LOG(error) << "channel name contains illegal character: '" << m.str(0) << "', allowed characters are: a-z, A-Z, 0-9, -, _, [, ], #";
|
LOG(error) << "channel name contains illegal character: '" << m.str(0) << "', allowed characters are: a-z, A-Z, 0-9, -, _, [, ], #";
|
||||||
|
|||||||
@@ -513,7 +513,8 @@ void Device::HandleMultipleTransportInput()
|
|||||||
fMultitransportProceed = true;
|
fMultitransportProceed = true;
|
||||||
|
|
||||||
for (const auto& i : fMultitransportInputs) {
|
for (const auto& i : fMultitransportInputs) {
|
||||||
threads.emplace_back(thread(&Device::PollForTransport, this, fTransports.at(i.first).get(), i.second));
|
threads.emplace_back(
|
||||||
|
&Device::PollForTransport, this, fTransports.at(i.first).get(), i.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (thread& t : threads) {
|
for (thread& t : threads) {
|
||||||
|
|||||||
@@ -66,10 +66,13 @@ bool DeviceRunner::HandleGeneralOptions(const fair::mq::ProgOptions& config, boo
|
|||||||
if (printLogo) {
|
if (printLogo) {
|
||||||
LOG(info) << endl
|
LOG(info) << endl
|
||||||
<< " ______ _ _______ _________ " << endl
|
<< " ______ _ _______ _________ " << endl
|
||||||
<< " / ____/___ _(_)_______ |/ /_ __ \\ version " << FAIRMQ_GIT_VERSION << endl
|
<< " / ____/___ _(_)_______ |/ /_ __ \\ version "
|
||||||
<< " / /_ / __ `/ / ___/__ /|_/ /_ / / / build " << FAIRMQ_BUILD_TYPE << endl
|
<< FAIRMQ_GIT_VERSION << endl
|
||||||
|
<< " / /_ / __ `/ / ___/__ /|_/ /_ / / / build " << FAIRMQ_BUILD_TYPE
|
||||||
|
<< endl
|
||||||
<< " / __/ / /_/ / / / _ / / / / /_/ / " << FAIRMQ_REPO_URL << endl
|
<< " / __/ / /_/ / / / _ / / / / /_/ / " << FAIRMQ_REPO_URL << endl
|
||||||
<< " /_/ \\__,_/_/_/ /_/ /_/ \\___\\_\\ " << FAIRMQ_LICENSE << " © " << FAIRMQ_COPYRIGHT << endl;
|
<< R"( /_/ \__,_/_/_/ /_/ /_/ \___\_\ )" << FAIRMQ_LICENSE
|
||||||
|
<< " © " << FAIRMQ_COPYRIGHT << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ struct Parts
|
|||||||
const_iterator end() const noexcept { return fParts.end(); }
|
const_iterator end() const noexcept { return fParts.end(); }
|
||||||
const_iterator cend() const noexcept { return fParts.cend(); }
|
const_iterator cend() const noexcept { return fParts.cend(); }
|
||||||
|
|
||||||
container fParts{};
|
container fParts;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fair::mq
|
} // namespace fair::mq
|
||||||
|
|||||||
@@ -32,12 +32,9 @@ const std::string fair::mq::PluginManager::fgkLibPrefixAlt = "FairMQPlugin_";
|
|||||||
std::vector<boost::dll::shared_library> fair::mq::PluginManager::fgDLLKeepAlive =
|
std::vector<boost::dll::shared_library> fair::mq::PluginManager::fgDLLKeepAlive =
|
||||||
std::vector<boost::dll::shared_library>();
|
std::vector<boost::dll::shared_library>();
|
||||||
|
|
||||||
fair::mq::PluginManager::PluginManager()
|
fair::mq::PluginManager::PluginManager() {}
|
||||||
: fPluginServices()
|
|
||||||
{}
|
|
||||||
|
|
||||||
fair::mq::PluginManager::PluginManager(const vector<string>& args)
|
fair::mq::PluginManager::PluginManager(const vector<string>& args)
|
||||||
: fPluginServices()
|
|
||||||
{
|
{
|
||||||
// Parse command line options
|
// Parse command line options
|
||||||
auto options = ProgramOptions();
|
auto options = ProgramOptions();
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ auto PluginServices::ChangeDeviceState(const string& controller, const DeviceSta
|
|||||||
{
|
{
|
||||||
lock_guard<mutex> lock{fDeviceControllerMutex};
|
lock_guard<mutex> lock{fDeviceControllerMutex};
|
||||||
|
|
||||||
if (!fDeviceController) fDeviceController = controller;
|
if (!fDeviceController) {
|
||||||
|
fDeviceController = controller;
|
||||||
|
}
|
||||||
|
|
||||||
if (fDeviceController == controller) {
|
if (fDeviceController == controller) {
|
||||||
return fDevice.ChangeState(next);
|
return fDevice.ChangeState(next);
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ vector<string> ProgOptions::GetPropertyKeys() const
|
|||||||
vector<string> keys;
|
vector<string> keys;
|
||||||
|
|
||||||
for (const auto& it : fVarMap) {
|
for (const auto& it : fVarMap) {
|
||||||
keys.push_back(it.first.c_str());
|
keys.emplace_back(it.first.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return keys;
|
return keys;
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ Properties SuboptParser(const vector<string>& channelConfig, const string& devic
|
|||||||
|
|
||||||
ptree channelsArray;
|
ptree channelsArray;
|
||||||
|
|
||||||
for (auto token : channelConfig) {
|
for (const auto& token : channelConfig) {
|
||||||
string channelName;
|
string channelName;
|
||||||
ptree channelProperties;
|
ptree channelProperties;
|
||||||
|
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ struct RegionConfig
|
|||||||
int64_t userFlags = 0; /// custom flags that have no effect on the transport, but can be retrieved from the region by the user
|
int64_t userFlags = 0; /// custom flags that have no effect on the transport, but can be retrieved from the region by the user
|
||||||
uint64_t size = 0; /// region size
|
uint64_t size = 0; /// region size
|
||||||
uint64_t rcSegmentSize = 100000000; /// size of the segment that stores reference counts when "soft"-copying the messages
|
uint64_t rcSegmentSize = 100000000; /// size of the segment that stores reference counts when "soft"-copying the messages
|
||||||
std::string path = ""; /// file path, if the region is backed by a file
|
std::string path; /// file path, if the region is backed by a file
|
||||||
std::optional<uint16_t> id = std::nullopt; /// region id
|
std::optional<uint16_t> id = std::nullopt; /// region id
|
||||||
uint32_t linger = 100; /// delay in ms before region destruction to collect outstanding events
|
uint32_t linger = 100; /// delay in ms before region destruction to collect outstanding events
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -180,7 +180,6 @@ struct RegionInfo
|
|||||||
, fUserFlags(userFlags)
|
, fUserFlags(userFlags)
|
||||||
, fSize(size)
|
, fSize(size)
|
||||||
, fRCSegmentSize(rcSegmentSize)
|
, fRCSegmentSize(rcSegmentSize)
|
||||||
, fDestroyed(false)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Str fPath;
|
Str fPath;
|
||||||
@@ -188,7 +187,7 @@ struct RegionInfo
|
|||||||
uint64_t fUserFlags;
|
uint64_t fUserFlags;
|
||||||
uint64_t fSize;
|
uint64_t fSize;
|
||||||
uint64_t fRCSegmentSize;
|
uint64_t fRCSegmentSize;
|
||||||
bool fDestroyed;
|
bool fDestroyed{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
using Uint16RegionInfoPairAlloc = boost::interprocess::allocator<std::pair<const uint16_t, RegionInfo>, SegmentManager>;
|
using Uint16RegionInfoPairAlloc = boost::interprocess::allocator<std::pair<const uint16_t, RegionInfo>, SegmentManager>;
|
||||||
@@ -340,4 +339,13 @@ struct SegmentBufferShrink
|
|||||||
|
|
||||||
} // namespace fair::mq::shmem
|
} // namespace fair::mq::shmem
|
||||||
|
|
||||||
|
namespace fair::mq { class TransportFactory; }
|
||||||
|
|
||||||
|
namespace fair::mq::shmem {
|
||||||
|
// Resolve a MetaHeader (received over a side channel) to the local data pointer.
|
||||||
|
// The caller is responsible for ensuring the backing buffer remains alive for the
|
||||||
|
// duration of access; FairMQ provides no refcount protection for this path.
|
||||||
|
char* GetDataAddressFromHandle(fair::mq::TransportFactory& factory, const MetaHeader& meta);
|
||||||
|
} // namespace fair::mq::shmem
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SHMEM_COMMON_H_ */
|
#endif /* FAIR_MQ_SHMEM_COMMON_H_ */
|
||||||
|
|||||||
@@ -7,11 +7,18 @@
|
|||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include "Manager.h"
|
#include "Manager.h"
|
||||||
|
#include "TransportFactory.h"
|
||||||
|
|
||||||
// Needed to compile-firewall the <boost/process/async.hpp> header because it
|
// Needed to compile-firewall the <boost/process/async.hpp> header because it
|
||||||
// interferes with the <asio/buffer.hpp> header. So, let's factor
|
// interferes with the <asio/buffer.hpp> header. So, let's factor
|
||||||
// the whole dependency to Boost.Process out of the header.
|
// the whole dependency to Boost.Process out of the header.
|
||||||
|
#ifdef FAIRMQ_BOOST_PROCESS_V1_HEADER
|
||||||
|
#include <boost/process/v1.hpp>
|
||||||
|
namespace bp = boost::process::v1;
|
||||||
|
#else
|
||||||
#include <boost/process.hpp>
|
#include <boost/process.hpp>
|
||||||
|
namespace bp = boost::process;
|
||||||
|
#endif
|
||||||
#include <fairlogger/Logger.h>
|
#include <fairlogger/Logger.h>
|
||||||
|
|
||||||
namespace fair::mq::shmem {
|
namespace fair::mq::shmem {
|
||||||
@@ -28,7 +35,7 @@ bool Manager::SpawnShmMonitor(const std::string& id)
|
|||||||
path.emplace(path.begin(), env.at(fairmq_path_key).to_string());
|
path.emplace(path.begin(), env.at(fairmq_path_key).to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto exe(boost::process::search_path(shmmonitor_exe_name, path));
|
auto exe(bp::search_path(shmmonitor_exe_name, path));
|
||||||
if (exe.empty()) {
|
if (exe.empty()) {
|
||||||
LOG(warn) << "could not find " << shmmonitor_exe_name << " in \"$" << fairmq_path_key
|
LOG(warn) << "could not find " << shmmonitor_exe_name << " in \"$" << fairmq_path_key
|
||||||
<< ":$PATH\"";
|
<< ":$PATH\"";
|
||||||
@@ -39,10 +46,18 @@ bool Manager::SpawnShmMonitor(const std::string& id)
|
|||||||
bool verbose(env.count(shmmonitor_verbose_key)
|
bool verbose(env.count(shmmonitor_verbose_key)
|
||||||
&& env.at(shmmonitor_verbose_key).to_string() == "true");
|
&& env.at(shmmonitor_verbose_key).to_string() == "true");
|
||||||
|
|
||||||
boost::process::spawn(
|
bp::spawn(
|
||||||
exe, "-x", "-m", "--shmid", id, "-d", "-t", "2000", (verbose ? "--verbose" : ""), env);
|
exe, "-x", "-m", "--shmid", id, "-d", "-t", "2000", (verbose ? "--verbose" : ""), env);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* GetDataAddressFromHandle(fair::mq::TransportFactory& factory, const MetaHeader& meta)
|
||||||
|
{
|
||||||
|
if (factory.GetType() != fair::mq::Transport::SHM) {
|
||||||
|
throw SharedMemoryError("GetDataAddressFromHandle called on a non-shmem transport");
|
||||||
|
}
|
||||||
|
return static_cast<TransportFactory&>(factory).GetDataAddressFromHandle(meta);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace fair::mq::shmem
|
} // namespace fair::mq::shmem
|
||||||
|
|||||||
@@ -390,8 +390,10 @@ class Manager
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto* lRegion = GetRegion(id);
|
auto* lRegion = GetRegion(id);
|
||||||
fTlRegionCache.fRegionsTLCache.emplace_back(std::make_tuple(lRegion, id, fShmId64));
|
if (lRegion) {
|
||||||
|
fTlRegionCache.fRegionsTLCache.emplace_back(lRegion, id, fShmId64);
|
||||||
fTlRegionCache.fRegionsTLCacheGen = fRegionsGen;
|
fTlRegionCache.fRegionsTLCacheGen = fRegionsGen;
|
||||||
|
}
|
||||||
return lRegion;
|
return lRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -776,6 +778,30 @@ class Manager
|
|||||||
|
|
||||||
auto GetMetadataMsgSize() const noexcept { return fMetadataMsgSize; }
|
auto GetMetadataMsgSize() const noexcept { return fMetadataMsgSize; }
|
||||||
|
|
||||||
|
// Resolve a MetaHeader (received over a side channel) to the local data pointer.
|
||||||
|
// The caller is responsible for ensuring the backing buffer remains alive for the
|
||||||
|
// duration of access; FairMQ provides no refcount protection for this path.
|
||||||
|
char* GetDataAddressFromHandle(const MetaHeader& meta)
|
||||||
|
{
|
||||||
|
if (meta.fManaged) {
|
||||||
|
if (meta.fSize == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
GetSegment(meta.fSegmentId);
|
||||||
|
auto it = fSegments.find(meta.fSegmentId);
|
||||||
|
if (it == fSegments.end()) {
|
||||||
|
throw SharedMemoryError(tools::ToString("GetDataAddressFromHandle: cannot open segment with id ", meta.fSegmentId));
|
||||||
|
}
|
||||||
|
return ShmHeader::UserPtr(GetAddressFromHandle(meta.fHandle, meta.fSegmentId));
|
||||||
|
} else {
|
||||||
|
UnmanagedRegion* region = GetRegionFromCache(meta.fRegionId);
|
||||||
|
if (!region) {
|
||||||
|
throw SharedMemoryError(tools::ToString("GetDataAddressFromHandle: cannot get unmanaged region with id ", meta.fRegionId));
|
||||||
|
}
|
||||||
|
return reinterpret_cast<char*>(region->GetData()) + meta.fHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~Manager()
|
~Manager()
|
||||||
{
|
{
|
||||||
fRegionsGen += 1; // signal TL cache invalidation
|
fRegionsGen += 1; // signal TL cache invalidation
|
||||||
|
|||||||
@@ -77,7 +77,12 @@ class Message final : public fair::mq::Message
|
|||||||
fManager.IncrementMsgCounter();
|
fManager.IncrementMsgCounter();
|
||||||
}
|
}
|
||||||
|
|
||||||
Message(Manager& manager, UnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0, fair::mq::TransportFactory* factory = nullptr)
|
Message(Manager& manager,
|
||||||
|
UnmanagedRegionPtr& region,
|
||||||
|
void* data,
|
||||||
|
const size_t size,
|
||||||
|
void* hint = nullptr,
|
||||||
|
fair::mq::TransportFactory* factory = nullptr)
|
||||||
: fair::mq::Message(factory)
|
: fair::mq::Message(factory)
|
||||||
, fManager(manager)
|
, fManager(manager)
|
||||||
, fLocalPtr(static_cast<char*>(data))
|
, fLocalPtr(static_cast<char*>(data))
|
||||||
@@ -162,6 +167,11 @@ class Message final : public fair::mq::Message
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaHeader GetMeta() const
|
||||||
|
{
|
||||||
|
return {fSize, fHint, fHandle, fShared, fRegionId, fSegmentId, fManaged};
|
||||||
|
}
|
||||||
|
|
||||||
void* GetData() const override
|
void* GetData() const override
|
||||||
{
|
{
|
||||||
if (!fLocalPtr) {
|
if (!fLocalPtr) {
|
||||||
|
|||||||
@@ -59,12 +59,18 @@ void signalHandler(int signal)
|
|||||||
gSignalStatus = signal;
|
gSignalStatus = signal;
|
||||||
}
|
}
|
||||||
|
|
||||||
Monitor::Monitor(string shmId, bool selfDestruct, bool interactive, bool viewOnly, unsigned int timeoutInMS, unsigned int intervalInMS, bool monitor, bool cleanOnExit)
|
Monitor::Monitor(string shmId,
|
||||||
|
bool selfDestruct,
|
||||||
|
bool interactive,
|
||||||
|
bool viewOnly,
|
||||||
|
unsigned int timeoutInMS,
|
||||||
|
unsigned int intervalInMS,
|
||||||
|
bool monitor,
|
||||||
|
bool cleanOnExit)
|
||||||
: fSelfDestruct(selfDestruct)
|
: fSelfDestruct(selfDestruct)
|
||||||
, fInteractive(interactive)
|
, fInteractive(interactive)
|
||||||
, fViewOnly(viewOnly)
|
, fViewOnly(viewOnly)
|
||||||
, fMonitor(monitor)
|
, fMonitor(monitor)
|
||||||
, fSeenOnce(false)
|
|
||||||
, fCleanOnExit(cleanOnExit)
|
, fCleanOnExit(cleanOnExit)
|
||||||
, fTimeoutInMS(timeoutInMS)
|
, fTimeoutInMS(timeoutInMS)
|
||||||
, fIntervalInMS(intervalInMS)
|
, fIntervalInMS(intervalInMS)
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ class Monitor
|
|||||||
bool fInteractive; // running in interactive mode
|
bool fInteractive; // running in interactive mode
|
||||||
bool fViewOnly; // view only mode
|
bool fViewOnly; // view only mode
|
||||||
bool fMonitor;
|
bool fMonitor;
|
||||||
bool fSeenOnce; // true is segment has been opened successfully at least once
|
bool fSeenOnce{false}; // true is segment has been opened successfully at least once
|
||||||
bool fCleanOnExit;
|
bool fCleanOnExit;
|
||||||
unsigned int fTimeoutInMS;
|
unsigned int fTimeoutInMS;
|
||||||
unsigned int fIntervalInMS;
|
unsigned int fIntervalInMS;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class Poller final : public fair::mq::Poller
|
|||||||
try {
|
try {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
// calculate offsets and the total size of the poll item set
|
// calculate offsets and the total size of the poll item set
|
||||||
for (std::string channel : channelList) {
|
for (const std::string& channel : channelList) {
|
||||||
fOffsetMap[channel] = offset;
|
fOffsetMap[channel] = offset;
|
||||||
offset += channelsMap.at(channel).size();
|
offset += channelsMap.at(channel).size();
|
||||||
fNumItems += channelsMap.at(channel).size();
|
fNumItems += channelsMap.at(channel).size();
|
||||||
@@ -80,7 +80,7 @@ class Poller final : public fair::mq::Poller
|
|||||||
fItems = new zmq_pollitem_t[fNumItems];
|
fItems = new zmq_pollitem_t[fNumItems];
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (std::string channel : channelList) {
|
for (const std::string& channel : channelList) {
|
||||||
for (unsigned int i = 0; i < channelsMap.at(channel).size(); ++i) {
|
for (unsigned int i = 0; i < channelsMap.at(channel).size(); ++i) {
|
||||||
index = fOffsetMap[channel] + i;
|
index = fOffsetMap[channel] + i;
|
||||||
|
|
||||||
|
|||||||
@@ -39,18 +39,19 @@ namespace fair::mq::shmem
|
|||||||
class Socket final : public fair::mq::Socket
|
class Socket final : public fair::mq::Socket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Socket(Manager& manager, const std::string& type, const std::string& name, const std::string& id, void* context, fair::mq::TransportFactory* fac = nullptr)
|
Socket(Manager& manager,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& name,
|
||||||
|
const std::string& id,
|
||||||
|
void* context,
|
||||||
|
fair::mq::TransportFactory* fac = nullptr)
|
||||||
: fair::mq::Socket(fac)
|
: fair::mq::Socket(fac)
|
||||||
, fManager(manager)
|
, fManager(manager)
|
||||||
, fId(id + "." + name + "." + type)
|
, fId(id + "." + name + "." + type)
|
||||||
, fSocket(nullptr)
|
|
||||||
, fMonitorSocket(nullptr)
|
|
||||||
, fBytesTx(0)
|
, fBytesTx(0)
|
||||||
, fBytesRx(0)
|
, fBytesRx(0)
|
||||||
, fMessagesTx(0)
|
, fMessagesTx(0)
|
||||||
, fMessagesRx(0)
|
, fMessagesRx(0)
|
||||||
, fTimeout(100)
|
|
||||||
, fConnectedPeersCount(0)
|
|
||||||
, fMetadataMsgSize(manager.GetMetadataMsgSize())
|
, fMetadataMsgSize(manager.GetMetadataMsgSize())
|
||||||
{
|
{
|
||||||
assert(context);
|
assert(context);
|
||||||
@@ -456,15 +457,15 @@ class Socket final : public fair::mq::Socket
|
|||||||
private:
|
private:
|
||||||
Manager& fManager;
|
Manager& fManager;
|
||||||
std::string fId;
|
std::string fId;
|
||||||
void* fSocket;
|
void* fSocket{nullptr};
|
||||||
void* fMonitorSocket;
|
void* fMonitorSocket{nullptr};
|
||||||
std::atomic<unsigned long> fBytesTx;
|
std::atomic<unsigned long> fBytesTx;
|
||||||
std::atomic<unsigned long> fBytesRx;
|
std::atomic<unsigned long> fBytesRx;
|
||||||
std::atomic<unsigned long> fMessagesTx;
|
std::atomic<unsigned long> fMessagesTx;
|
||||||
std::atomic<unsigned long> fMessagesRx;
|
std::atomic<unsigned long> fMessagesRx;
|
||||||
|
|
||||||
int fTimeout;
|
int fTimeout{100};
|
||||||
mutable unsigned long fConnectedPeersCount;
|
mutable unsigned long fConnectedPeersCount{0};
|
||||||
std::size_t fMetadataMsgSize;
|
std::size_t fMetadataMsgSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,10 @@ class TransportFactory final : public fair::mq::TransportFactory
|
|||||||
return std::make_unique<Message>(*fManager, data, size, ffn, hint, this);
|
return std::make_unique<Message>(*fManager, data, size, ffn, hint, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessagePtr CreateMessage(UnmanagedRegionPtr& region, void* data, size_t size, void* hint = 0) override
|
MessagePtr CreateMessage(UnmanagedRegionPtr& region,
|
||||||
|
void* data,
|
||||||
|
size_t size,
|
||||||
|
void* hint = nullptr) override
|
||||||
{
|
{
|
||||||
return std::make_unique<Message>(*fManager, region, data, size, hint, this);
|
return std::make_unique<Message>(*fManager, region, data, size, hint, this);
|
||||||
}
|
}
|
||||||
@@ -198,6 +201,8 @@ class TransportFactory final : public fair::mq::TransportFactory
|
|||||||
void Resume() override { fManager->Resume(); }
|
void Resume() override { fManager->Resume(); }
|
||||||
void Reset() override { fManager->Reset(); }
|
void Reset() override { fManager->Reset(); }
|
||||||
|
|
||||||
|
char* GetDataAddressFromHandle(const MetaHeader& meta) { return fManager->GetDataAddressFromHandle(meta); }
|
||||||
|
|
||||||
~TransportFactory() override
|
~TransportFactory() override
|
||||||
{
|
{
|
||||||
LOG(debug) << "Destroying Shared Memory transport...";
|
LOG(debug) << "Destroying Shared Memory transport...";
|
||||||
|
|||||||
@@ -63,9 +63,7 @@ struct UnmanagedRegion
|
|||||||
, fName(MakeShmName(shmId, "rg", cfg.id.value()))
|
, fName(MakeShmName(shmId, "rg", cfg.id.value()))
|
||||||
, fQueueName(MakeShmName(shmId, "rgq", cfg.id.value()))
|
, fQueueName(MakeShmName(shmId, "rgq", cfg.id.value()))
|
||||||
, fRefCountSegmentName(MakeShmName(shmId, "rrc", cfg.id.value()))
|
, fRefCountSegmentName(MakeShmName(shmId, "rrc", cfg.id.value()))
|
||||||
, fShmemObject()
|
|
||||||
, fFile(nullptr)
|
, fFile(nullptr)
|
||||||
, fFileMapping()
|
|
||||||
, fRcSegmentSize(cfg.rcSegmentSize)
|
, fRcSegmentSize(cfg.rcSegmentSize)
|
||||||
, fQueue(nullptr)
|
, fQueue(nullptr)
|
||||||
, fCallback(nullptr)
|
, fCallback(nullptr)
|
||||||
@@ -102,7 +100,7 @@ struct UnmanagedRegion
|
|||||||
}
|
}
|
||||||
fFileMapping = file_mapping(fName.c_str(), read_write);
|
fFileMapping = file_mapping(fName.c_str(), read_write);
|
||||||
LOG(debug) << "UnmanagedRegion(): initialized file: " << fName;
|
LOG(debug) << "UnmanagedRegion(): initialized file: " << fName;
|
||||||
fRegion = mapped_region(fFileMapping, read_write, 0, size, 0, cfg.creationFlags);
|
fRegion = mapped_region(fFileMapping, read_write, 0, size, nullptr, cfg.creationFlags);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
// if opening fails, create
|
// if opening fails, create
|
||||||
@@ -126,7 +124,7 @@ struct UnmanagedRegion
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fRegion = mapped_region(fShmemObject, read_write, 0, 0, 0, cfg.creationFlags);
|
fRegion = mapped_region(fShmemObject, read_write, 0, 0, nullptr, cfg.creationFlags);
|
||||||
if (size != 0 && size != fRegion.get_size()) {
|
if (size != 0 && size != fRegion.get_size()) {
|
||||||
LOG(error) << "Created/opened region size (" << fRegion.get_size() << ") does not match configured size (" << size << ")";
|
LOG(error) << "Created/opened region size (" << fRegion.get_size() << ") does not match configured size (" << size << ")";
|
||||||
throw TransportError(tools::ToString("Created/opened region size (", fRegion.get_size(), ") does not match configured size (", size, ")"));
|
throw TransportError(tools::ToString("Created/opened region size (", fRegion.get_size(), ") does not match configured size (", size, ")"));
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ class UnmanagedRegionImpl final : public fair::mq::UnmanagedRegion
|
|||||||
fair::mq::TransportFactory* factory)
|
fair::mq::TransportFactory* factory)
|
||||||
: fair::mq::UnmanagedRegion(factory)
|
: fair::mq::UnmanagedRegion(factory)
|
||||||
, fManager(manager)
|
, fManager(manager)
|
||||||
, fRegion(nullptr)
|
|
||||||
, fRegionId(0)
|
|
||||||
{
|
{
|
||||||
auto [regionPtr, regionId] = fManager.CreateRegion(size, callback, bulkCallback, std::move(cfg));
|
auto [regionPtr, regionId] = fManager.CreateRegion(size, callback, bulkCallback, std::move(cfg));
|
||||||
fRegion = regionPtr;
|
fRegion = regionPtr;
|
||||||
@@ -62,8 +60,8 @@ class UnmanagedRegionImpl final : public fair::mq::UnmanagedRegion
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Manager& fManager;
|
Manager& fManager;
|
||||||
shmem::UnmanagedRegion* fRegion;
|
shmem::UnmanagedRegion* fRegion{nullptr};
|
||||||
uint16_t fRegionId;
|
uint16_t fRegionId{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fair::mq::shmem
|
} // namespace fair::mq::shmem
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ string getDefaultRouteNetworkInterface()
|
|||||||
string interfaceName;
|
string interfaceName;
|
||||||
|
|
||||||
#ifdef __APPLE__ // MacOS
|
#ifdef __APPLE__ // MacOS
|
||||||
unique_ptr<FILE, decltype(pclose)*> file(
|
unique_ptr<FILE, int (*)(FILE*)> file(
|
||||||
popen("route -n get default | grep interface | cut -d \":\" -f 2", "r"), pclose);
|
popen("route -n get default | grep interface | cut -d \":\" -f 2", "r"), pclose);
|
||||||
#else // Linux
|
#else // Linux
|
||||||
ifstream is("/proc/net/route");
|
ifstream is("/proc/net/route");
|
||||||
@@ -128,7 +128,7 @@ string getDefaultRouteNetworkInterface()
|
|||||||
LOG(debug) << "could not get network interface of the default route from /proc/net/route, "
|
LOG(debug) << "could not get network interface of the default route from /proc/net/route, "
|
||||||
"going to try via 'ip route'";
|
"going to try via 'ip route'";
|
||||||
|
|
||||||
unique_ptr<FILE, decltype(pclose)*> file(
|
unique_ptr<FILE, int (*)(FILE*)> file(
|
||||||
popen("ip route | grep default | cut -d \" \" -f 5 | head -n 1", "r"), pclose);
|
popen("ip route | grep default | cut -d \" \" -f 5 | head -n 1", "r"), pclose);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -10,17 +10,26 @@
|
|||||||
#include <fairmq/tools/Strings.h>
|
#include <fairmq/tools/Strings.h>
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#ifdef FAIRMQ_BOOST_PROCESS_V1_HEADER
|
||||||
|
#include <boost/process/v1.hpp>
|
||||||
|
#else
|
||||||
#include <boost/process.hpp>
|
#include <boost/process.hpp>
|
||||||
|
#endif
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <csignal> // kill, signals
|
#include <csignal> // kill, signals
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
#ifdef FAIRMQ_BOOST_PROCESS_V1_HEADER
|
||||||
|
namespace bp = boost::process::v1;
|
||||||
|
#else
|
||||||
namespace bp = boost::process;
|
namespace bp = boost::process;
|
||||||
|
#endif
|
||||||
namespace ba = boost::asio;
|
namespace ba = boost::asio;
|
||||||
namespace bs = boost::system;
|
namespace bs = boost::system;
|
||||||
|
|
||||||
@@ -32,10 +41,18 @@ class LinePrinter
|
|||||||
, fPrefix(std::move(prefix))
|
, fPrefix(std::move(prefix))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// prints line with prefix on both cout (thread-safe) and output stream
|
// prints line with prefix on both cout and output stream
|
||||||
void Print(const string& line)
|
void Print(const string& line)
|
||||||
{
|
{
|
||||||
|
// Serialize: the standard allows concurrent insertion on std::cout,
|
||||||
|
// but libstdc++ maintains the formatted-output state (e.g.
|
||||||
|
// ios_base::width) with plain reads and writes that constitute data
|
||||||
|
// races; the lock also keeps whole lines from interleaving.
|
||||||
|
static mutex sCoutMutex;
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lock(sCoutMutex);
|
||||||
cout << fair::mq::tools::ToString(fPrefix, line, "\n") << flush;
|
cout << fair::mq::tools::ToString(fPrefix, line, "\n") << flush;
|
||||||
|
}
|
||||||
fOut << fPrefix << line << endl;
|
fOut << fPrefix << line << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ class Context
|
|||||||
Context(int numIoThreads)
|
Context(int numIoThreads)
|
||||||
: fZmqCtx(zmq_ctx_new())
|
: fZmqCtx(zmq_ctx_new())
|
||||||
, fInterrupted(false)
|
, fInterrupted(false)
|
||||||
, fRegionCounter(1)
|
|
||||||
{
|
{
|
||||||
if (!fZmqCtx) {
|
if (!fZmqCtx) {
|
||||||
throw ContextError(tools::ToString("failed creating context, reason: ", zmq_strerror(errno)));
|
throw ContextError(tools::ToString("failed creating context, reason: ", zmq_strerror(errno)));
|
||||||
@@ -180,7 +179,7 @@ class Context
|
|||||||
mutable std::mutex fMtx;
|
mutable std::mutex fMtx;
|
||||||
std::atomic<bool> fInterrupted;
|
std::atomic<bool> fInterrupted;
|
||||||
|
|
||||||
uint16_t fRegionCounter;
|
uint16_t fRegionCounter{1};
|
||||||
std::condition_variable fRegionEventsCV;
|
std::condition_variable fRegionEventsCV;
|
||||||
std::vector<RegionInfo> fRegionInfos;
|
std::vector<RegionInfo> fRegionInfos;
|
||||||
std::queue<RegionInfo> fRegionEvents;
|
std::queue<RegionInfo> fRegionEvents;
|
||||||
|
|||||||
@@ -107,7 +107,11 @@ class Message final : public fair::mq::Message
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Message(UnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0, fair::mq::TransportFactory* factory = nullptr)
|
Message(UnmanagedRegionPtr& region,
|
||||||
|
void* data,
|
||||||
|
const size_t size,
|
||||||
|
void* hint = nullptr,
|
||||||
|
fair::mq::TransportFactory* factory = nullptr)
|
||||||
: fair::mq::Message(factory)
|
: fair::mq::Message(factory)
|
||||||
, fMsg(std::make_unique<zmq_msg_t>())
|
, fMsg(std::make_unique<zmq_msg_t>())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class Poller final : public fair::mq::Poller
|
|||||||
fItems = new zmq_pollitem_t[fNumItems];
|
fItems = new zmq_pollitem_t[fNumItems];
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (std::string channel : channelList) {
|
for (const std::string& channel : channelList) {
|
||||||
for (unsigned int i = 0; i < channelsMap.at(channel).size(); ++i) {
|
for (unsigned int i = 0; i < channelsMap.at(channel).size(); ++i) {
|
||||||
index = fOffsetMap[channel] + i;
|
index = fOffsetMap[channel] + i;
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ class Socket final : public fair::mq::Socket
|
|||||||
, fBytesRx(0)
|
, fBytesRx(0)
|
||||||
, fMessagesTx(0)
|
, fMessagesTx(0)
|
||||||
, fMessagesRx(0)
|
, fMessagesRx(0)
|
||||||
, fTimeout(100)
|
|
||||||
, fConnectedPeersCount(0)
|
|
||||||
{
|
{
|
||||||
if (fSocket == nullptr) {
|
if (fSocket == nullptr) {
|
||||||
LOG(error) << "Failed creating socket " << fId << ", reason: " << zmq_strerror(errno);
|
LOG(error) << "Failed creating socket " << fId << ", reason: " << zmq_strerror(errno);
|
||||||
@@ -405,8 +404,8 @@ class Socket final : public fair::mq::Socket
|
|||||||
std::atomic<unsigned long> fMessagesTx;
|
std::atomic<unsigned long> fMessagesTx;
|
||||||
std::atomic<unsigned long> fMessagesRx;
|
std::atomic<unsigned long> fMessagesRx;
|
||||||
|
|
||||||
int fTimeout;
|
int fTimeout{100};
|
||||||
mutable unsigned long fConnectedPeersCount;
|
mutable unsigned long fConnectedPeersCount{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fair::mq::zmq
|
} // namespace fair::mq::zmq
|
||||||
|
|||||||
@@ -73,7 +73,10 @@ class TransportFactory final : public fair::mq::TransportFactory
|
|||||||
return std::make_unique<Message>(data, size, ffn, hint, this);
|
return std::make_unique<Message>(data, size, ffn, hint, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessagePtr CreateMessage(UnmanagedRegionPtr& region, void* data, size_t size, void* hint = 0) override
|
MessagePtr CreateMessage(UnmanagedRegionPtr& region,
|
||||||
|
void* data,
|
||||||
|
size_t size,
|
||||||
|
void* hint = nullptr) override
|
||||||
{
|
{
|
||||||
return std::make_unique<Message>(region, data, size, hint, this);
|
return std::make_unique<Message>(region, data, size, hint, this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,18 +16,33 @@ if(FairLogger_VERSION VERSION_LESS 1.9.0 AND FairLogger_VERSION VERSION_GREATER_
|
|||||||
LIST(APPEND definitions FAIR_MIN_SEVERITY=trace)
|
LIST(APPEND definitions FAIR_MIN_SEVERITY=trace)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(FAIRMQ_BOOST_PROCESS_V1_HEADER)
|
||||||
|
LIST(APPEND definitions FAIRMQ_BOOST_PROCESS_V1_HEADER)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(definitions)
|
if(definitions)
|
||||||
set(definitions DEFINITIONS ${definitions})
|
set(definitions DEFINITIONS ${definitions})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(test_environment)
|
||||||
if(ENABLE_SANITIZER_LEAK)
|
if(ENABLE_SANITIZER_LEAK)
|
||||||
get_filename_component(lsan_supps "${CMAKE_CURRENT_SOURCE_DIR}/leak_sanitizer_suppressions.txt" ABSOLUTE)
|
get_filename_component(lsan_supps "${CMAKE_CURRENT_SOURCE_DIR}/leak_sanitizer_suppressions.txt" ABSOLUTE)
|
||||||
set(environment ENVIRONMENT "LSAN_OPTIONS=set:suppressions=${lsan_supps}")
|
list(APPEND test_environment "LSAN_OPTIONS=set:suppressions=${lsan_supps}")
|
||||||
|
endif()
|
||||||
|
# Run the tests against an alternative runtime library directory, e.g. a
|
||||||
|
# tsan-instrumented libstdc++. Set per test (not at the job level), because
|
||||||
|
# such a library must only be loaded into instrumented executables.
|
||||||
|
if(FAIRMQ_TEST_LD_LIBRARY_PATH)
|
||||||
|
list(APPEND test_environment "LD_LIBRARY_PATH=path_list_prepend:${FAIRMQ_TEST_LD_LIBRARY_PATH}")
|
||||||
|
endif()
|
||||||
|
if(test_environment)
|
||||||
|
set(environment ENVIRONMENT ${test_environment})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_testhelper(runTestDevice
|
add_testhelper(runTestDevice
|
||||||
SOURCES
|
SOURCES
|
||||||
helper/runTestDevice.cxx
|
helper/runTestDevice.cxx
|
||||||
|
helper/LocaleWarmup.h
|
||||||
helper/devices/TestPairLeft.h
|
helper/devices/TestPairLeft.h
|
||||||
helper/devices/TestPairRight.h
|
helper/devices/TestPairRight.h
|
||||||
helper/devices/TestPollIn.h
|
helper/devices/TestPollIn.h
|
||||||
@@ -134,6 +149,7 @@ add_testsuite(Device
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/device
|
${CMAKE_CURRENT_SOURCE_DIR}/device
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
TIMEOUT 20
|
TIMEOUT 20
|
||||||
|
${definitions}
|
||||||
${environment}
|
${environment}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
ARG VERSION=latest
|
|
||||||
FROM fedora:${VERSION}
|
|
||||||
ARG VERSION=latest
|
|
||||||
LABEL org.opencontainers.image.source "https://github.com/FairRootGroup/FairMQ"
|
|
||||||
LABEL org.opencontainers.image.description "FairMQ development environment"
|
|
||||||
RUN dnf -y update
|
|
||||||
# https://git.gsi.de/SDE/packages/builder
|
|
||||||
RUN dnf -y install https://alfa-ci.gsi.de/packages/rpm/fedora-$VERSION-x86_64/fairsoft-release-dev.rpm
|
|
||||||
RUN dnf -y install clang cli11-devel ninja-build 'dnf-command(builddep)' libasan liblsan libtsan libubsan clang-tools-extra
|
|
||||||
RUN dnf -y builddep fairmq
|
|
||||||
RUN dnf -y clean all
|
|
||||||
|
|
||||||
# buildah build --build-arg "VERSION=36" -t "ghcr.io/fairrootgroup/fairmq-dev/fedora-36:latest" -f test/ci/Containerfile.fedora .
|
|
||||||
# echo $GH_PAT | buildah login -u dennisklein --password-stdin ghcr.io
|
|
||||||
# buildah push ghcr.io/fairrootgroup/fairmq-dev/fedora-36:latest
|
|
||||||
|
|
||||||
# apptainer pull docker://ghcr.io/fairrootgroup/fairmq-dev/fedora-36:latest
|
|
||||||
# echo $GH_PAT | apptainer remote login -u dennisklein --password-stdin oras://ghcr.io
|
|
||||||
# apptainer push ./fedora-36_latest.sif oras://ghcr.io/fairrootgroup/fairmq-dev/fedora-36-sif:latest
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
ARG VERSION=latest
|
|
||||||
FROM ubuntu:${VERSION}
|
|
||||||
ARG VERSION=latest
|
|
||||||
LABEL org.opencontainers.image.source "https://github.com/FairRootGroup/FairMQ"
|
|
||||||
LABEL org.opencontainers.image.description "FairMQ development environment"
|
|
||||||
|
|
||||||
RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
|
|
||||||
RUN apt-get update
|
|
||||||
RUN apt-get -y upgrade
|
|
||||||
RUN apt-get -y install ca-certificates patch cmake git libboost-dev libboost-log-dev libboost-system-dev libboost-regex-dev libboost-filesystem-dev libboost-container-dev libboost-thread-dev libboost-date-time-dev libboost-program-options-dev g++ libfmt-dev ninja-build wget libczmq-dev libxml2-utils libfabric-dev libfabric-bin pkg-config
|
|
||||||
RUN apt-get -y clean
|
|
||||||
|
|
||||||
RUN cd /tmp
|
|
||||||
|
|
||||||
RUN git clone -b v1.19.2 --recurse-submodules https://github.com/FairRootGroup/asio
|
|
||||||
RUN cmake -GNinja -S asio -B asio_build -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
|
|
||||||
RUN cmake --build asio_build --target install
|
|
||||||
RUN rm -rf asio asio_build
|
|
||||||
|
|
||||||
RUN git clone -b v1.0.0 https://github.com/FairRootGroup/FairCMakeModules
|
|
||||||
RUN cmake -GNinja -S FairCMakeModules -B FairCMakeModules_build -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
|
|
||||||
RUN cmake --build FairCMakeModules_build --target install
|
|
||||||
RUN rm -rf FairCMakeModules FairCMakeModules_build
|
|
||||||
|
|
||||||
RUN git clone -b v1.11.0 https://github.com/FairRootGroup/FairLogger
|
|
||||||
RUN cmake -GNinja -S FairLogger -B FairLogger_build -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DUSE_EXTERNAL_FMT=ON
|
|
||||||
RUN cmake --build FairLogger_build --target install
|
|
||||||
RUN rm -rf FairLogger FairLogger_build
|
|
||||||
|
|
||||||
# buildah build --build-arg "VERSION=22.04" -t "ghcr.io/fairrootgroup/fairmq-dev/ubuntu-22.04:latest" -f test/ci/Containerfile.ubuntu .
|
|
||||||
# echo $GH_PAT | buildah login -u dennisklein --password-stdin ghcr.io
|
|
||||||
# buildah push ghcr.io/fairrootgroup/fairmq-dev/ubuntu-22.04:latest
|
|
||||||
|
|
||||||
# apptainer pull docker://ghcr.io/fairrootgroup/fairmq-dev/ubuntu-22.04:latest
|
|
||||||
# echo $GH_PAT | apptainer remote login -u dennisklein --password-stdin oras://ghcr.io
|
|
||||||
# apptainer push ./ubuntu-22.04_latest.sif oras://ghcr.io/fairrootgroup/fairmq-dev/ubuntu-22.04-sif:latest
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#! /bin/bash
|
|
||||||
|
|
||||||
label="$1"
|
|
||||||
jobsh="$2"
|
|
||||||
|
|
||||||
if [ -z "$ALFACI_SLURM_CPUS" ]
|
|
||||||
then
|
|
||||||
ALFACI_SLURM_CPUS=20
|
|
||||||
fi
|
|
||||||
CPUS_PER_JOB=$(($ALFACI_SLURM_CPUS / 2))
|
|
||||||
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 $CPUS_PER_JOB -n 1 \
|
|
||||||
-t $ALFACI_SLURM_TIMEOUT \
|
|
||||||
--job-name="${label}" \
|
|
||||||
${ALFACI_SLURM_EXTRA_OPTS} \
|
|
||||||
bash "${jobsh}"
|
|
||||||
)
|
|
||||||
retval=$?
|
|
||||||
echo "*** Exit Code ............: $retval"
|
|
||||||
exit "$retval"
|
|
||||||
21
test/ci/spack-boost187.yaml
Normal file
21
test/ci/spack-boost187.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
spack:
|
||||||
|
specs:
|
||||||
|
- "fairlogger@2.2.0 ^fmt@:11"
|
||||||
|
- "boost@1.87 +container +program_options +filesystem +date_time +regex"
|
||||||
|
- "libzmq@4.1.4:"
|
||||||
|
- ninja
|
||||||
|
- "cmake@3.15:"
|
||||||
|
|
||||||
|
concretizer:
|
||||||
|
targets:
|
||||||
|
granularity: generic
|
||||||
|
|
||||||
|
packages:
|
||||||
|
all:
|
||||||
|
require:
|
||||||
|
- target=x86_64_v3
|
||||||
|
|
||||||
|
mirrors:
|
||||||
|
ghcr-buildcache:
|
||||||
|
url: oci://ghcr.io/fairrootgroup/fairmq-spack-buildcache
|
||||||
|
signed: false
|
||||||
21
test/ci/spack-latest.yaml
Normal file
21
test/ci/spack-latest.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
spack:
|
||||||
|
specs:
|
||||||
|
- "fairlogger@2.2.0 ^fmt@:11"
|
||||||
|
- "boost@1.66: +container +program_options +filesystem +date_time +regex"
|
||||||
|
- "libzmq@4.1.4:"
|
||||||
|
- ninja
|
||||||
|
- "cmake@3.15:"
|
||||||
|
|
||||||
|
concretizer:
|
||||||
|
targets:
|
||||||
|
granularity: generic
|
||||||
|
|
||||||
|
packages:
|
||||||
|
all:
|
||||||
|
require:
|
||||||
|
- target=x86_64_v3
|
||||||
|
|
||||||
|
mirrors:
|
||||||
|
ghcr-buildcache:
|
||||||
|
url: oci://ghcr.io/fairrootgroup/fairmq-spack-buildcache
|
||||||
|
signed: false
|
||||||
47
test/ci/spack-tsan.yaml
Normal file
47
test/ci/spack-tsan.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
spack:
|
||||||
|
specs:
|
||||||
|
# fairlogger and boost are left uninstrumented on purpose: no tsan report
|
||||||
|
# has ever implicated them. Should that change, instrument them with
|
||||||
|
# per-node flags like libzmq below.
|
||||||
|
- "fairlogger@2.2.0 ^fmt@:11"
|
||||||
|
- "boost@1.66: +container +program_options +filesystem +date_time +regex"
|
||||||
|
# libzmq (and the libsodium it links) are built with ThreadSanitizer
|
||||||
|
# instrumentation so tsan can observe the happens-before edges that
|
||||||
|
# libzmq's lock-free queues establish between user and I/O threads.
|
||||||
|
# Flags are set per node on purpose: the propagating '==' operator could
|
||||||
|
# reach the gcc node (the compiler is a dependency since spack 1.0) and
|
||||||
|
# trigger a full compiler rebuild.
|
||||||
|
- "libzmq@4.1.4: cflags='-g -fno-omit-frame-pointer -fsanitize=thread'
|
||||||
|
cxxflags='-g -fno-omit-frame-pointer -fsanitize=thread'
|
||||||
|
ldflags='-fsanitize=thread'
|
||||||
|
^libsodium cflags='-g -fno-omit-frame-pointer -fsanitize=thread'
|
||||||
|
ldflags='-fsanitize=thread'"
|
||||||
|
# ThreadSanitizer-instrumented libstdc++ (from test/ci/spack_repo), a
|
||||||
|
# drop-in runtime replacement injected per test via LD_LIBRARY_PATH (see
|
||||||
|
# FAIRMQ_TEST_LD_LIBRARY_PATH in test/CMakeLists.txt).
|
||||||
|
# Keep the major version in lockstep with the gcc used by the tsan job.
|
||||||
|
- "libstdcxx-tsan@15"
|
||||||
|
- ninja
|
||||||
|
# the per-test env injection uses ctest's ENVIRONMENT_MODIFICATION,
|
||||||
|
# which needs cmake >= 3.22
|
||||||
|
- "cmake@3.22:"
|
||||||
|
|
||||||
|
concretizer:
|
||||||
|
targets:
|
||||||
|
granularity: generic
|
||||||
|
reuse:
|
||||||
|
# always re-concretize libstdcxx-tsan from the recipe in
|
||||||
|
# test/ci/spack_repo: spec reuse would keep resurrecting previously
|
||||||
|
# built (and cached) variants after the recipe changed; unchanged
|
||||||
|
# recipes still hit the buildcache because the hash is identical
|
||||||
|
exclude: ["libstdcxx-tsan"]
|
||||||
|
|
||||||
|
packages:
|
||||||
|
all:
|
||||||
|
require:
|
||||||
|
- target=x86_64_v3
|
||||||
|
|
||||||
|
mirrors:
|
||||||
|
ghcr-buildcache:
|
||||||
|
url: oci://ghcr.io/fairrootgroup/fairmq-spack-buildcache
|
||||||
|
signed: false
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from spack_repo.builtin.build_systems.generic import Package
|
||||||
|
|
||||||
|
from spack.package import *
|
||||||
|
|
||||||
|
|
||||||
|
class LibstdcxxTsan(Package):
|
||||||
|
"""ThreadSanitizer-instrumented build of GCC's libstdc++.
|
||||||
|
|
||||||
|
GCC ships no supported way to produce a tsan-instrumented libstdc++ (and
|
||||||
|
spack's gcc package offers no hook into the target-library flags), so this
|
||||||
|
package builds only the libstdc++-v3 subtree from the GCC release tarball
|
||||||
|
matching the toolchain, with -fsanitize=thread. The result is a drop-in
|
||||||
|
runtime replacement for the compiler's own libstdc++ (same soname and
|
||||||
|
symbol versions) that lets tsan observe the synchronization inside the
|
||||||
|
C++ standard library (e.g. std::locale/std::regex lazy initialization).
|
||||||
|
|
||||||
|
Select it via LD_LIBRARY_PATH in the environment of the instrumented
|
||||||
|
executables only. Like any shared library built with gcc
|
||||||
|
-fsanitize=thread it carries unresolved __tsan_* symbols satisfied by the
|
||||||
|
executable's libtsan, so loading it into an uninstrumented executable
|
||||||
|
fails.
|
||||||
|
|
||||||
|
Recipe modeled on https://iree.dev/developers/debugging/sanitizers/.
|
||||||
|
"""
|
||||||
|
|
||||||
|
homepage = "https://gcc.gnu.org/onlinedocs/libstdc++/"
|
||||||
|
url = "https://ftp.gnu.org/gnu/gcc/gcc-15.2.0/gcc-15.2.0.tar.xz"
|
||||||
|
|
||||||
|
# Keep in lockstep with the gcc version used by the tsan CI job: a
|
||||||
|
# libstdc++ older than the compiler may lack GLIBCXX symbol versions
|
||||||
|
# that binaries built by that compiler reference. Checksums match the
|
||||||
|
# version() directives in spack's gcc package.
|
||||||
|
version("15.2.0", sha256="438fd996826b0c82485a29da03a72d71d6e3541a83ec702df4271f6fe025d24e")
|
||||||
|
version("14.3.0", sha256="e0dc77297625631ac8e50fa92fffefe899a4eb702592da5c32ef04e2293aca3a")
|
||||||
|
|
||||||
|
depends_on("c", type="build")
|
||||||
|
depends_on("cxx", type="build")
|
||||||
|
depends_on("gmake", type="build")
|
||||||
|
|
||||||
|
def install(self, spec, prefix):
|
||||||
|
# gthr-default.h only materializes in a configured libgcc build dir;
|
||||||
|
# on POSIX targets it is a verbatim copy of gthr-posix.h. Providing it
|
||||||
|
# up front spares building libgcc (and the in-tree compiler).
|
||||||
|
gthr_include = join_path(self.stage.source_path, "spack-gthr")
|
||||||
|
mkdirp(gthr_include)
|
||||||
|
copy(
|
||||||
|
join_path(self.stage.source_path, "libgcc", "gthr-posix.h"),
|
||||||
|
join_path(gthr_include, "gthr-default.h"),
|
||||||
|
)
|
||||||
|
|
||||||
|
flags = f"-I{gthr_include} -O2 -g -fno-omit-frame-pointer -fsanitize=thread"
|
||||||
|
build_dir = join_path(self.stage.source_path, "spack-build")
|
||||||
|
mkdirp(build_dir)
|
||||||
|
with working_dir(build_dir):
|
||||||
|
configure = Executable(
|
||||||
|
join_path(self.stage.source_path, "libstdc++-v3", "configure")
|
||||||
|
)
|
||||||
|
configure(
|
||||||
|
f"--prefix={prefix}",
|
||||||
|
f"--libdir={prefix.lib}",
|
||||||
|
"--disable-multilib",
|
||||||
|
"--disable-libstdcxx-pch",
|
||||||
|
"--enable-libstdcxx-threads=yes",
|
||||||
|
"--with-default-libstdcxx-abi=new",
|
||||||
|
f"CFLAGS={flags}",
|
||||||
|
f"CXXFLAGS={flags}",
|
||||||
|
"LDFLAGS=-fsanitize=thread",
|
||||||
|
)
|
||||||
|
make()
|
||||||
|
make("install")
|
||||||
|
|
||||||
|
# The runtime libraries land in the multilib os dir (lib64 on
|
||||||
|
# x86_64), --libdir notwithstanding (--with-toolexeclibdir only
|
||||||
|
# applies to cross builds); normalize to lib/ for the consumer.
|
||||||
|
if os.path.isdir(prefix.lib64):
|
||||||
|
mkdirp(prefix.lib)
|
||||||
|
for entry in os.listdir(prefix.lib64):
|
||||||
|
shutil.move(join_path(prefix.lib64, entry), join_path(prefix.lib, entry))
|
||||||
|
os.rmdir(prefix.lib64)
|
||||||
|
|
||||||
|
# Only the runtime library is consumed -- compilation uses the
|
||||||
|
# compiler's own (identical) headers. Drop the rest to keep the
|
||||||
|
# buildcache entry small.
|
||||||
|
for directory in ("include", "share"):
|
||||||
|
path = join_path(prefix, directory)
|
||||||
|
if os.path.isdir(path):
|
||||||
|
shutil.rmtree(path)
|
||||||
3
test/ci/spack_repo/fairmq_ci/repo.yaml
Normal file
3
test/ci/spack_repo/fairmq_ci/repo.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
repo:
|
||||||
|
namespace: fairmq_ci
|
||||||
|
api: v2.0
|
||||||
@@ -9,7 +9,11 @@
|
|||||||
#include "runner.h"
|
#include "runner.h"
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#ifdef FAIRMQ_BOOST_PROCESS_V1_HEADER
|
||||||
|
#include <boost/process/v1.hpp>
|
||||||
|
#else
|
||||||
#include <boost/process.hpp>
|
#include <boost/process.hpp>
|
||||||
|
#endif
|
||||||
#include <fairmq/tools/Process.h>
|
#include <fairmq/tools/Process.h>
|
||||||
#include <fairmq/tools/Unique.h>
|
#include <fairmq/tools/Unique.h>
|
||||||
#include <fairmq/Device.h>
|
#include <fairmq/Device.h>
|
||||||
|
|||||||
@@ -9,7 +9,11 @@
|
|||||||
#include "runner.h"
|
#include "runner.h"
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#ifdef FAIRMQ_BOOST_PROCESS_V1_HEADER
|
||||||
|
#include <boost/process/v1.hpp>
|
||||||
|
#else
|
||||||
#include <boost/process.hpp>
|
#include <boost/process.hpp>
|
||||||
|
#endif
|
||||||
#include <fairmq/tools/Process.h>
|
#include <fairmq/tools/Process.h>
|
||||||
#include <fairmq/tools/Unique.h>
|
#include <fairmq/tools/Unique.h>
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,11 @@
|
|||||||
#include "runner.h"
|
#include "runner.h"
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#ifdef FAIRMQ_BOOST_PROCESS_V1_HEADER
|
||||||
|
#include <boost/process/v1.hpp>
|
||||||
|
#else
|
||||||
#include <boost/process.hpp>
|
#include <boost/process.hpp>
|
||||||
|
#endif
|
||||||
#include <fairmq/tools/Unique.h>
|
#include <fairmq/tools/Unique.h>
|
||||||
#include <fairmq/tools/Process.h>
|
#include <fairmq/tools/Process.h>
|
||||||
|
|
||||||
|
|||||||
@@ -29,13 +29,17 @@ TEST(EventManager, Basics)
|
|||||||
std::function<void(typename TestEvent::KeyType, int)> callback{
|
std::function<void(typename TestEvent::KeyType, int)> callback{
|
||||||
[&](TestEvent::KeyType key, int newValue){
|
[&](TestEvent::KeyType key, int newValue){
|
||||||
++call_counter;
|
++call_counter;
|
||||||
if (key == "test") value = newValue;
|
if (key == "test") {
|
||||||
|
value = newValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
std::function<void(typename TestEvent::KeyType, string)> callback2{
|
std::function<void(typename TestEvent::KeyType, string)> callback2{
|
||||||
[&](TestEvent::KeyType key, string newValue){
|
[&](TestEvent::KeyType key, string newValue){
|
||||||
++call_counter2;
|
++call_counter2;
|
||||||
if (key == "test") value2 = newValue;
|
if (key == "test") {
|
||||||
|
value2 = newValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
63
test/helper/LocaleWarmup.h
Normal file
63
test/helper/LocaleWarmup.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2026 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_TEST_LOCALEWARMUP_H
|
||||||
|
#define FAIR_MQ_TEST_LOCALEWARMUP_H
|
||||||
|
|
||||||
|
#include <locale>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace fair::mq::test {
|
||||||
|
|
||||||
|
/// libstdc++'s std::ctype<char> caches narrow()/widen() results per character
|
||||||
|
/// in plain char arrays of the global classic-locale facet -- by design with
|
||||||
|
/// unsynchronized writes, emitted from header-inlined code (locale_facets.h).
|
||||||
|
/// Whenever two threads exercise an uncached character concurrently (e.g. by
|
||||||
|
/// compiling a std::regex), ThreadSanitizer rightfully reports the write as a
|
||||||
|
/// data race. The stores are real and unsynchronized, so instrumenting
|
||||||
|
/// libstdc++ cannot help; instead, fill the caches before any thread exists,
|
||||||
|
/// which turns every later access into a pure read.
|
||||||
|
inline void WarmUpLocaleCaches()
|
||||||
|
{
|
||||||
|
auto const& ct = std::use_facet<std::ctype<char>>(std::locale::classic());
|
||||||
|
for (int c = 1; c < 256; ++c) {
|
||||||
|
auto const ch = static_cast<char>(c);
|
||||||
|
ct.narrow(ch, '\0');
|
||||||
|
ct.widen(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only the range overload runs _M_narrow_init(), which sets the
|
||||||
|
// all-cached flag (_M_narrow_ok); the single-char loop above fills the
|
||||||
|
// cache without it. (widen() needs no equivalent: the single-char
|
||||||
|
// overload already runs _M_widen_init().)
|
||||||
|
char from[256];
|
||||||
|
char to[256];
|
||||||
|
for (int c = 0; c < 256; ++c) {
|
||||||
|
from[c] = static_cast<char>(c);
|
||||||
|
}
|
||||||
|
ct.narrow(from, from + 256, '?', to);
|
||||||
|
|
||||||
|
// num_put/num_get caches used by stream insertion/extraction
|
||||||
|
std::ostringstream os;
|
||||||
|
os << 4711 << ' ' << 3.14;
|
||||||
|
std::istringstream is("42 3.14");
|
||||||
|
int i = 0;
|
||||||
|
double d = 0.;
|
||||||
|
is >> i >> d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For binaries that do not own main(): define a namespace-scope instance to
|
||||||
|
/// run the warm-up during static initialization, before main().
|
||||||
|
struct LocaleWarmup
|
||||||
|
{
|
||||||
|
LocaleWarmup() { WarmUpLocaleCaches(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fair::mq::test
|
||||||
|
|
||||||
|
#endif /* FAIR_MQ_TEST_LOCALEWARMUP_H */
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
* copied verbatim in the file "LICENSE" *
|
* copied verbatim in the file "LICENSE" *
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
|
#include "LocaleWarmup.h"
|
||||||
#include "devices/TestPairLeft.h"
|
#include "devices/TestPairLeft.h"
|
||||||
#include "devices/TestPairRight.h"
|
#include "devices/TestPairRight.h"
|
||||||
#include "devices/TestPollIn.h"
|
#include "devices/TestPollIn.h"
|
||||||
@@ -30,6 +31,10 @@
|
|||||||
|
|
||||||
namespace bpo = boost::program_options;
|
namespace bpo = boost::program_options;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
[[maybe_unused]] fair::mq::test::LocaleWarmup const gLocaleWarmup{};
|
||||||
|
}
|
||||||
|
|
||||||
auto addCustomOptions(bpo::options_description& options) -> void
|
auto addCustomOptions(bpo::options_description& options) -> void
|
||||||
{
|
{
|
||||||
options.add_options()
|
options.add_options()
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
leak:zmq_msg_init_size
|
leak:zmq_msg_init_size
|
||||||
|
leak:zmq::msg_t::init_size
|
||||||
|
|||||||
@@ -453,6 +453,46 @@ TEST(EmptyMessage, shmem_expanded_metadata) // NOLINT
|
|||||||
EmptyMessage("shmem", "ipc://test_empty_message", true);
|
EmptyMessage("shmem", "ipc://test_empty_message", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMeta() + GetDataAddressFromHandle() round-trip: simulates a consumer device that
|
||||||
|
// receives message metadata over a side channel and resolves it to a local pointer.
|
||||||
|
// Uses a second factory on the same session to exercise the open_only segment attach path.
|
||||||
|
auto SideChannel(bool expandedShmMetadata = false) -> void
|
||||||
|
{
|
||||||
|
const string session = tools::Uuid();
|
||||||
|
|
||||||
|
ProgOptions producerConfig;
|
||||||
|
producerConfig.SetProperty<string>("session", session);
|
||||||
|
producerConfig.SetProperty<size_t>("shm-segment-size", 100000000);
|
||||||
|
producerConfig.SetProperty<bool>("shm-monitor", true);
|
||||||
|
if (expandedShmMetadata) {
|
||||||
|
producerConfig.SetProperty<size_t>("shm-metadata-msg-size", 2048);
|
||||||
|
}
|
||||||
|
auto producerFactory(TransportFactory::CreateTransportFactory("shmem", tools::Uuid(), &producerConfig));
|
||||||
|
|
||||||
|
ProgOptions consumerConfig;
|
||||||
|
consumerConfig.SetProperty<string>("session", session);
|
||||||
|
consumerConfig.SetProperty<size_t>("shm-segment-size", 100000000);
|
||||||
|
consumerConfig.SetProperty<bool>("shm-monitor", true);
|
||||||
|
auto consumerFactory(TransportFactory::CreateTransportFactory("shmem", tools::Uuid(), &consumerConfig));
|
||||||
|
|
||||||
|
const size_t size = 2;
|
||||||
|
MessagePtr msg(producerFactory->CreateMessage(size));
|
||||||
|
memcpy(msg->GetData(), "AB", size);
|
||||||
|
|
||||||
|
// producer side: extract metadata to send over the side channel
|
||||||
|
const auto meta = static_cast<const shmem::Message&>(*msg).GetMeta();
|
||||||
|
EXPECT_EQ(meta.fSize, size);
|
||||||
|
EXPECT_TRUE(meta.fManaged);
|
||||||
|
|
||||||
|
// consumer side: resolve via a different factory — exercises open_only segment attach.
|
||||||
|
// The virtual address differs between factory mappings; only the content must match.
|
||||||
|
char* ptr = shmem::GetDataAddressFromHandle(*consumerFactory, meta);
|
||||||
|
|
||||||
|
ASSERT_NE(ptr, nullptr);
|
||||||
|
EXPECT_EQ(ptr[0], 'A');
|
||||||
|
EXPECT_EQ(ptr[1], 'B');
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ZeroCopy, shmem) // NOLINT
|
TEST(ZeroCopy, shmem) // NOLINT
|
||||||
{
|
{
|
||||||
ZeroCopy();
|
ZeroCopy();
|
||||||
@@ -463,6 +503,93 @@ TEST(ZeroCopy, shmem_expanded_metadata) // NOLINT
|
|||||||
ZeroCopy(true);
|
ZeroCopy(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uses a second factory on the same session to exercise the remote region lookup path.
|
||||||
|
auto SideChannelUnmanaged() -> void
|
||||||
|
{
|
||||||
|
const string session = tools::Uuid();
|
||||||
|
|
||||||
|
ProgOptions producerConfig;
|
||||||
|
producerConfig.SetProperty<string>("session", session);
|
||||||
|
producerConfig.SetProperty<size_t>("shm-segment-size", 100000000);
|
||||||
|
producerConfig.SetProperty<bool>("shm-monitor", true);
|
||||||
|
auto producerFactory(TransportFactory::CreateTransportFactory("shmem", tools::Uuid(), &producerConfig));
|
||||||
|
|
||||||
|
ProgOptions consumerConfig;
|
||||||
|
consumerConfig.SetProperty<string>("session", session);
|
||||||
|
consumerConfig.SetProperty<size_t>("shm-segment-size", 100000000);
|
||||||
|
consumerConfig.SetProperty<bool>("shm-monitor", true);
|
||||||
|
auto consumerFactory(TransportFactory::CreateTransportFactory("shmem", tools::Uuid(), &consumerConfig));
|
||||||
|
|
||||||
|
const size_t regionSize = 1000000;
|
||||||
|
tools::Semaphore blocker;
|
||||||
|
auto region = producerFactory->CreateUnmanagedRegion(regionSize, [&blocker](void*, size_t, void*) {
|
||||||
|
blocker.Signal();
|
||||||
|
});
|
||||||
|
|
||||||
|
const size_t size = 2;
|
||||||
|
auto msg(producerFactory->CreateMessage(region, static_cast<char*>(region->GetData()), size, nullptr));
|
||||||
|
memcpy(msg->GetData(), "AB", size);
|
||||||
|
|
||||||
|
const auto meta = static_cast<const shmem::Message&>(*msg).GetMeta();
|
||||||
|
EXPECT_EQ(meta.fSize, size);
|
||||||
|
EXPECT_FALSE(meta.fManaged);
|
||||||
|
|
||||||
|
// consumer resolves via its own factory — exercises remote region lookup.
|
||||||
|
// The virtual address differs between factory mappings; only the content must match.
|
||||||
|
char* ptr = shmem::GetDataAddressFromHandle(*consumerFactory, meta);
|
||||||
|
|
||||||
|
ASSERT_NE(ptr, nullptr);
|
||||||
|
EXPECT_EQ(ptr[0], 'A');
|
||||||
|
EXPECT_EQ(ptr[1], 'B');
|
||||||
|
|
||||||
|
msg.reset();
|
||||||
|
blocker.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SideChannelErrors() -> void
|
||||||
|
{
|
||||||
|
ProgOptions config;
|
||||||
|
config.SetProperty<string>("session", tools::Uuid());
|
||||||
|
config.SetProperty<size_t>("shm-segment-size", 100000000);
|
||||||
|
config.SetProperty<bool>("shm-monitor", true);
|
||||||
|
auto shmFactory(TransportFactory::CreateTransportFactory("shmem", tools::Uuid(), &config));
|
||||||
|
auto zmqFactory(TransportFactory::CreateTransportFactory("zeromq", tools::Uuid(), &config));
|
||||||
|
|
||||||
|
// non-shmem factory must throw
|
||||||
|
shmem::MetaHeader meta{};
|
||||||
|
meta.fManaged = true;
|
||||||
|
EXPECT_THROW(shmem::GetDataAddressFromHandle(*zmqFactory, meta), shmem::SharedMemoryError);
|
||||||
|
|
||||||
|
// bad segment id must throw
|
||||||
|
meta.fSize = 1;
|
||||||
|
meta.fSegmentId = 999;
|
||||||
|
EXPECT_THROW(shmem::GetDataAddressFromHandle(*shmFactory, meta), shmem::SharedMemoryError);
|
||||||
|
|
||||||
|
// zero-size managed message must return nullptr (mirrors Message::GetData())
|
||||||
|
meta.fSize = 0;
|
||||||
|
EXPECT_EQ(shmem::GetDataAddressFromHandle(*shmFactory, meta), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SideChannel, shmem) // NOLINT
|
||||||
|
{
|
||||||
|
SideChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SideChannel, shmem_expanded_metadata) // NOLINT
|
||||||
|
{
|
||||||
|
SideChannel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SideChannel, shmem_unmanaged) // NOLINT
|
||||||
|
{
|
||||||
|
SideChannelUnmanaged();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SideChannel, errors) // NOLINT
|
||||||
|
{
|
||||||
|
SideChannelErrors();
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ZeroCopyFromUnmanaged, shmem) // NOLINT
|
TEST(ZeroCopyFromUnmanaged, shmem) // NOLINT
|
||||||
{
|
{
|
||||||
ZeroCopyFromUnmanaged("ipc://test_zerocopy_unmanaged", false, 10000000);
|
ZeroCopyFromUnmanaged("ipc://test_zerocopy_unmanaged", false, 10000000);
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ TEST_F(PluginServices, SubscriptionThreadSafety)
|
|||||||
std::array<std::unique_ptr<std::thread>, subscribers> threads;
|
std::array<std::unique_ptr<std::thread>, subscribers> threads;
|
||||||
auto id = 0;
|
auto id = 0;
|
||||||
for (auto& thread : threads) {
|
for (auto& thread : threads) {
|
||||||
thread = std::make_unique<std::thread>([&](){
|
thread = std::make_unique<std::thread>([&, id](){
|
||||||
auto const subscriber = fair::mq::tools::ToString("subscriber_", id);
|
auto const subscriber = fair::mq::tools::ToString("subscriber_", id);
|
||||||
for (auto i = 0; i < attempts; ++i) {
|
for (auto i = 0; i < attempts; ++i) {
|
||||||
mServices.SubscribeToDeviceStateChange(subscriber, [](DeviceState){});
|
mServices.SubscribeToDeviceStateChange(subscriber, [](DeviceState){});
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <TestEnvironment.h>
|
#include <TestEnvironment.h>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#include <helper/LocaleWarmup.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ string runTestDevice = "@RUN_TEST_DEVICE@";
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
fair::mq::test::WarmUpLocaleCaches();
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||||
setenv("FAIRMQ_PATH", FAIRMQ_TEST_ENVIRONMENT, 0);
|
setenv("FAIRMQ_PATH", FAIRMQ_TEST_ENVIRONMENT, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user