ci: add tsan spack environment with instrumented libzmq

- mirror spack-latest.yaml, with -fsanitize=thread on the libzmq and
  libsodium nodes so tsan can observe the happens-before edges established
  inside libzmq's lock-free queues, plus the libstdcxx-tsan root spec
- flags are applied per node instead of via the propagating '==' operator,
  which could reach the gcc node and trigger a compiler rebuild
- unchanged roots (fairlogger, boost, ninja, cmake) keep their spec hashes,
  so they are shared with the regular buildcache entries; the instrumented
  nodes hash differently and coexist in the content-addressed cache
- exclude libstdcxx-tsan from concretizer reuse so recipe changes always
  take effect; unchanged recipes still hit the buildcache because the spec
  hash is identical
- add the tsan env to the buildcache matrix (rebuilding also on spack_repo
  changes) so the instrumented binaries are cached instead of rebuilt on
  every CI run
This commit is contained in:
Dennis Klein
2026-06-10 16:15:31 +02:00
committed by Dennis Klein
parent 331c50ab0e
commit add85cb18d
3 changed files with 51 additions and 1 deletions

View File

@@ -6,7 +6,7 @@ inputs:
description: 'GCC version to use'
required: true
env:
description: 'Spack environment name (latest, boost187)'
description: 'Spack environment name (latest, boost187, tsan)'
default: 'latest'
fresh:
description: 'Use fresh concretization'

View File

@@ -8,6 +8,7 @@ on:
branches: [dev, master]
paths:
- 'test/ci/spack-*.yaml'
- 'test/ci/spack_repo/**'
- '.github/workflows/buildcache.yml'
- '.github/actions/setup-deps/**'
@@ -30,6 +31,8 @@ jobs:
include:
- gcc: '15'
env: 'boost187'
- gcc: '15'
env: 'tsan'
steps:
- uses: actions/checkout@v6

47
test/ci/spack-tsan.yaml Normal file
View 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