Files
Jungfraujoch/image_analysis/indexing/CMakeLists.txt
T
leonarski_f ea383f9e83 FFBIDXIndexerCPU: the fast-feedback indexer on the CPU, used where there is no GPU
A port of the fast-feedback indexer's CUDA kernels to plain C++/Eigen: the same half-sphere and
rotation samples, the same scores and the same 32 output cells for Refine(). The loops are
reorganised so the inner one runs over samples and vectorises (GCC/Clang, no intrinsics), and the
cell search separates the rotation about the candidate vector out of the per-spot terms. The
vector refinement reproduces the library's warp sums - partial sums its shuffle reduction leaves in
the other lanes carry into the next round - and its float arithmetic (FMA contraction, the
Fibonacci points in float), because the candidates searched depend on it: on the library's 27 test
spot lists and 4 synthetic stills the CPU and GPU best cells agree to ~1e-6 relative, the top-32
sets in 30 of 31 cases completely.

FFBIDX now resolves to the GPU library where a GPU is visible and to the CPU port otherwise (no
GPU, --no-gpu, or a build without CUDA); Auto takes FFBIDX for stills whenever a cell is known,
also without a GPU, instead of FFTW. With a GPU nothing changes (a stills set and a rotation set
reproduce the baseline exactly). Without a GPU the stills indexer pool gets one indexer per worker
instead of eight, since the CPU indexer holds no card memory.

Single core, synthetic still, loaded 5950X: ~8 ms per call at 30 spots, ~15 ms at 80, ~35 ms at
250; 16 threads ~1300/700/330 calls/s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
(cherry picked from commit 9a8eb8669d1be6c3ec16db6786280affd6830ee5)
2026-10-23 17:56:50 +02:00

82 lines
4.0 KiB
CMake

ADD_LIBRARY(JFJochIndexing STATIC
Indexer.h
Indexer.cpp
IndexerFactory.h
IndexerFactory.cpp
IndexerThreadPool.cpp
IndexerThreadPool.h
AnalyzeIndexing.cpp
AnalyzeIndexing.h
FitProfileRadius.cpp
FitProfileRadius.h
PostIndexingRefinement.h
FFTResult.h
FFTIndexer.cpp
FFTIndexer.h
PostIndexingRefinement.cpp
MultiLatticeSearch.cpp
MultiLatticeSearch.h
SpindleBlindFraction.cpp
SpindleBlindFraction.h
HarmonicContamination.cpp
HarmonicContamination.h
SpindleCuspLoss.cpp
SpindleCuspLoss.h
LeftoverLattices.cpp
LeftoverLattices.h)
TARGET_LINK_LIBRARIES(JFJochIndexing JFJochCommon JFJochLatticeSearch)
IF (JFJOCH_CUDA_AVAILABLE)
# A source archive carries no submodules, which is exactly what is wanted here: ffbidx's bundled
# eigen submodule must NOT be added, or it would add_subdirectory a second Eigen3::Eigen target.
# ffbidx instead resolves Eigen via the project-level Eigen3 (the find_package(Eigen3) at the top
# of image_analysis/CMakeLists.txt). The clone this replaces passed GIT_SUBMODULES "" to get the
# same tree.
FetchContent_Declare(
fast-indexer
URL https://github.com/paulscherrerinstitute/fast-feedback-indexer/archive/a94fd4f5c55289e70860feea358182d2072e02b5.tar.gz
URL_HASH SHA256=275590cb41db783b822b1c8403abc2b3c9986f3d98a1a7361fc0ad478ff466c0
)
FetchContent_MakeAvailable(fast-indexer)
TARGET_SOURCES(JFJochIndexing PRIVATE
CUDAMemHelpers.h
FFTIndexerGPU.cu FFTIndexerGPU.h
FFBIDXIndexer.cpp FFBIDXIndexer.h)
# Link cuFFT statically where a static cuFFT exists. It is the only CUDA component that was
# ever dynamic (cudart and the fast-feedback indexer are already static), and as a .so it forced
# every self-contained artifact to carry the library beside its executables and find it again
# through an $ORIGIN rpath -- machinery that silently failed for any executable that was not the
# one the rpath had been set on. Static, a Linux artifact is one file that runs, and a cross
# build has no alternative anyway: NVIDIA's cross-linux-sbsa packages ship libcufft_static.a and
# no libcufft.so at all.
#
# The Windows CUDA toolkit ships no cufft_static.lib, so CUDA::cufft_static does not exist there
# and the dynamic library is the only option; the top-level CMakeLists installs the DLL beside
# the executable for the self-contained builds. Test the target rather than the platform, so a
# toolkit that gains or loses the static library is handled without another special case.
# Both halves matter: the server build keeps the shared library (its .deb/.rpm take CUDA from the
# distro, and every executable there -- broker, tests, tools -- would otherwise need the device
# link below), and Windows has no static cuFFT to link even for the portable products.
IF (JFJOCH_PORTABLE_ONLY AND TARGET CUDA::cufft_static)
TARGET_LINK_LIBRARIES(JFJochIndexing fast_indexer_static CUDA::cufft_static)
ELSE()
TARGET_LINK_LIBRARIES(JFJochIndexing fast_indexer_static CUDA::cufft)
ENDIF()
ELSE()
MESSAGE(WARNING "CUDA is strongly recommended for image analysis." )
TARGET_LINK_LIBRARIES(JFJochIndexing Eigen3::Eigen)
ENDIF()
# The CPU fast-feedback indexer is always built. Without errno and FP traps to preserve, GCC and Clang
# vectorise its scoring loops (sqrt, rint, min/max); neither option changes a computed value.
TARGET_SOURCES(JFJochIndexing PRIVATE FFBIDXIndexerCPU.cpp FFBIDXIndexerCPU.h)
IF (NOT MSVC)
SET_SOURCE_FILES_PROPERTIES(FFBIDXIndexerCPU.cpp PROPERTIES COMPILE_OPTIONS "-fno-math-errno;-fno-trapping-math")
ENDIF()
# FFTW (fftw3f) is always available via FetchContent -> the CPU FFT indexer is always built.
TARGET_SOURCES(JFJochIndexing PRIVATE FFTIndexerCPU.cpp FFTIndexerCPU.h)
TARGET_LINK_LIBRARIES(JFJochIndexing fftw3f)