--benchmark <path> reports cumulative CPU and wall time per node and names the node pacing the run. The pacing node is located from sampled channel occupancy, not from time-in-node: backpressure inflates time-in-node for everything downstream of the real bottleneck, so the obvious measure names the victim rather than the cause. Sampling starts with the network and stops before it is destroyed. Channel fill is instantaneous and everything has drained by shutdown, so a single read at the end reports an idle pipeline however congested it was. kill -USR1 dumps the table from a running or wedged process. Channel occupancy identifies a stalled node -- full input, empty output -- without a debug build or a debugger, which is the difference between diagnosing the AR-004 hang in seconds and reproducing it under gdb. Two knobs this exposes for measurement rather than sets: SAE_CV_THREADS, because OpenCV's TBB arena and KPN's thread-per-node are two schedulers unaware of each other on the same cores; and SAE_CUDA_BLOCKING_SYNC, because the default spin-wait held the embedder thread at 99.7% user time while nvidia-powerd cut the GPU's clock from 1005 to 210 MHz. Neither default changes until a measurement says it should. TRACES: VR-015 | PR-004
86 lines
3.7 KiB
CMake
86 lines
3.7 KiB
CMake
# ── Unit tests ────────────────────────────────────────────────────────────────
|
|
# Pure, GPU-free, model-free tests. The similarity tests compile the GEMM backend
|
|
# directly with SAE_GEMM_CPU so the suite builds and runs on a machine without a
|
|
# GPU regardless of the main build's SAE_GEMM_BACKEND selection.
|
|
|
|
find_package(Catch2 3 QUIET)
|
|
if(NOT Catch2_FOUND)
|
|
include(FetchContent)
|
|
FetchContent_Declare(
|
|
Catch2
|
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
|
GIT_TAG v3.5.3
|
|
)
|
|
FetchContent_MakeAvailable(Catch2)
|
|
endif()
|
|
|
|
add_executable(sae_tests
|
|
test_similarity.cpp
|
|
test_calibration.cpp
|
|
test_gallery_store.cpp
|
|
test_face_utils.cpp
|
|
test_track_gallery.cpp
|
|
test_face_tracker.cpp
|
|
test_track_registry.cpp
|
|
test_face_detector_node.cpp
|
|
test_scene_detector_node.cpp
|
|
test_replay_fixtures.cpp
|
|
test_embedding_dump.cpp
|
|
test_audio_signature.cpp
|
|
test_benchmark.cpp
|
|
${CMAKE_SOURCE_DIR}/src/backends/gemm_backend.cpp
|
|
${CMAKE_SOURCE_DIR}/src/gallery/gallery_store.cpp
|
|
${CMAKE_SOURCE_DIR}/src/audio_signature.cpp
|
|
${CMAKE_SOURCE_DIR}/src/gallery/embedder_stamp.cpp
|
|
)
|
|
target_include_directories(sae_tests PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
|
# SAE_GEMM_CPU: build the CPU reference GEMM regardless of the main backend.
|
|
# SAE_MODELS_DIR: config.hpp (pulled in by track_gallery.hpp) bakes model paths.
|
|
# SAE_TEST_FIXTURES_DIR: the audio golden vector is read from the source tree,
|
|
# not copied, so the file the plugin repo shares is the file under test.
|
|
# AR-026/AR-027: exercise the same kernel CI actually runs. Without this the
|
|
# suite compiles the scalar fallback while the CPU builder image links OpenBLAS,
|
|
# so the tested path and the shipped path would differ.
|
|
find_package(PkgConfig QUIET)
|
|
if(PkgConfig_FOUND)
|
|
pkg_check_modules(OPENBLAS_T QUIET openblas)
|
|
endif()
|
|
if(OPENBLAS_T_FOUND)
|
|
target_include_directories(sae_tests PRIVATE ${OPENBLAS_T_INCLUDE_DIRS})
|
|
target_link_libraries(sae_tests PRIVATE ${OPENBLAS_T_LINK_LIBRARIES})
|
|
elseif(NOT SAE_ALLOW_SCALAR_GEMM)
|
|
# Same rule as the CPU backend itself: testing the scalar loop while the
|
|
# shipped CPU path is OpenBLAS means the suite is not evidence about the
|
|
# kernel that runs.
|
|
message(FATAL_ERROR
|
|
"OpenBLAS not found, and the unit tests compile the CPU GEMM kernel "
|
|
"(AR-026). Install openblas-devel, or pass -DSAE_ALLOW_SCALAR_GEMM=ON "
|
|
"to test the scalar fallback deliberately.")
|
|
endif()
|
|
|
|
target_compile_definitions(sae_tests PRIVATE
|
|
$<$<BOOL:${OPENBLAS_T_FOUND}>:SAE_GEMM_CBLAS>
|
|
SAE_GEMM_CPU
|
|
SAE_MODELS_DIR="${SAE_MODELS_DIR}"
|
|
SAE_TEST_FIXTURES_DIR="${CMAKE_CURRENT_SOURCE_DIR}/fixtures")
|
|
# gallery_store.cpp + gallery_calibration.hpp use nlohmann/json and HDF5
|
|
# (galleries are HDF5-native, see src/gallery/gallery_store.cpp); face_utils.hpp
|
|
# and the calibration GEMM pull in OpenCV (calib3d/imgproc/core) via types.hpp.
|
|
# ffmpeg_libs: audio_signature.cpp decodes the golden fixture (avformat/avcodec/
|
|
# avutil/swresample). Still GPU-free — the audio path is pure CPU.
|
|
target_link_libraries(sae_tests PRIVATE
|
|
Catch2::Catch2WithMain
|
|
nlohmann_json::nlohmann_json
|
|
# VR-015: test_benchmark.cpp includes src/benchmark.hpp, which reads KPN's
|
|
# diagnostics structs. Header-only — no KPN network is constructed here, so
|
|
# the cost attribution stays testable on CI's GPU-free N100.
|
|
kpn
|
|
ffmpeg_libs
|
|
${OpenCV_LIBS}
|
|
${HDF5_CXX_LIBRARIES})
|
|
target_include_directories(sae_tests PRIVATE ${HDF5_INCLUDE_DIRS})
|
|
|
|
include(CTest)
|
|
include(Catch)
|
|
catch_discover_tests(sae_tests)
|