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)
82 lines
4.0 KiB
CMake
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)
|