# SPDX-FileCopyrightText: The Eigen Authors
# SPDX-License-Identifier: MPL-2.0

# Benchmarks of the GPU kernels Eigen generates: the Tensor module's GpuDevice executor, its launches, and the
# hand-written and vendor baselines they are measured against. (contrib/benchmarks/GPU benchmarks the
# library-dispatch module contrib/Eigen/GPU, which maps expressions onto cuBLAS/cuSOLVER calls; nothing here
# depends on it.) Built when EIGEN_BENCH_CUDA is ON, see ../CMakeLists.txt.

# eigen_add_gpu_benchmark(name source [LIBRARIES lib ...] [DEFINITIONS def ...])
# Mirrors eigen_add_benchmark. The binary carries its own main() (gpu_bench_common.h), which prints the device it
# runs on and records it in the JSON context, so benchmark::benchmark_main is not linked. NDEBUG is defined, as for
# the CPU benchmarks; runtime failures are still caught, since GpuDevice and the harness check every call through
# EIGEN_GPU_RUNTIME_CHECK, which aborts under NDEBUG instead of asserting.
function(eigen_add_gpu_benchmark name source)
  cmake_parse_arguments(BENCH "" "" "LIBRARIES;DEFINITIONS" ${ARGN})
  if(NOT IS_ABSOLUTE "${source}")
    set(source "${CMAKE_CURRENT_SOURCE_DIR}/${source}")
  endif()
  add_executable(${name} ${source})
  target_include_directories(${name} PRIVATE ${EIGEN_SOURCE_DIR} ${CUDAToolkit_INCLUDE_DIRS})
  target_link_libraries(${name} PRIVATE benchmark::benchmark CUDA::cudart)
  if(BENCH_LIBRARIES)
    target_link_libraries(${name} PRIVATE ${BENCH_LIBRARIES})
  endif()
  # Every source here is a .cu compiled as CUDA.
  target_compile_options(${name} PRIVATE
    $<$<COMPILE_LANGUAGE:CUDA>:-O3>
    $<$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>:--expt-relaxed-constexpr;-lineinfo>)
  target_compile_definitions(${name} PRIVATE NDEBUG EIGEN_USE_GPU)
  if(BENCH_DEFINITIONS)
    target_compile_definitions(${name} PRIVATE ${BENCH_DEFINITIONS})
  endif()
endfunction()

# Elementwise expressions through the Tensor executor, float/half/bfloat16, aligned and unaligned maps, against a
# hand-written float4 kernel and the device-to-device copy roofline.
eigen_add_gpu_benchmark(bench_gpu_elementwise bench_gpu_elementwise.cu)
# Launch overhead: an executor launch of a tiny expression against a raw <<<>>> launch, LAUNCH_GPU_KERNEL and
# cudaLaunchKernel.
eigen_add_gpu_benchmark(bench_gpu_launch bench_gpu_launch.cu)
# Full and partial reductions against CUB, which nvcc compiles from the toolkit's own headers, so the CUDA 13
# relocation of CCCL is transparent here.
eigen_add_gpu_benchmark(bench_gpu_reduction bench_gpu_reduction.cu)
if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 13.0)
  # CUDA 13's CUB requires C++17, independently of Eigen's C++14 header contract.
  target_compile_features(bench_gpu_reduction PRIVATE cuda_std_17)
endif()
# Contraction against cuBLAS, which is the gap a library dispatch would close.
eigen_add_gpu_benchmark(bench_gpu_contraction bench_gpu_contraction.cu LIBRARIES CUDA::cublas)
# What a temporary costs: the device's synchronous allocation against the stream-ordered one.
eigen_add_gpu_benchmark(bench_gpu_alloc bench_gpu_alloc.cu)
