Files
UnrealEngine/Engine/Source/ThirdParty/Intel/ISPC/ispc-1.17.0/benchmarks/cmake/AddBenchmark.cmake
2025-05-18 13:04:45 +08:00

223 lines
8.7 KiB
CMake

#
# Copyright (c) 2020-2021, Intel Corporation
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (ISPC_BUILD)
set (ISPC_EXECUTABLE $<TARGET_FILE:ispc>)
else()
find_program (ISPC_EXECUTABLE ispc)
if (NOT ISPC_EXECUTABLE)
message(FATAL_ERROR "Failed to find ispc" )
endif()
endif()
# Identify host arch
if(UNIX)
execute_process(COMMAND bash "-c" "uname -m | sed -e s/x86_64/x86/ -e s/i686/x86/ -e s/arm.*/arm/ -e s/sa110/arm/" OUTPUT_VARIABLE ARCH)
string(STRIP ${ARCH} ARCH)
execute_process(COMMAND getconf LONG_BIT OUTPUT_VARIABLE ARCH_BIT)
string(STRIP ${ARCH_BIT} ARCH_BIT)
if("${ARCH}" STREQUAL "x86")
if(${ARCH_BIT} EQUAL 32)
set(ISPC_ARCH "x86")
else()
set(ISPC_ARCH "x86-64")
endif()
elseif("${ARCH}" STREQUAL "arm")
if(${ARCH_BIT} EQUAL 32)
set(ISPC_ARCH "arm")
else()
set(ISPC_ARCH "aarch64")
endif()
else()
message(FATAL_ERROR "Cannot detect host architecture for benchamrks: ${ARCH}.")
endif()
else()
set(ARCH "x86")
if(CMAKE_SIZEOF_VOID_P EQUAL 8 )
set(ISPC_ARCH "x86-64")
else()
set(ISPC_ARCH "x86")
endif()
endif()
# Suffixes for multi-target compilation (x86 only)
set(ISPC_KNOWN_TARGETS "sse2" "sse4" "avx1" "avx2" "avx512knl" "avx512skx")
#######################
# add_ispc_to_target
#######################
#
# Adds a ISPC compilation custom command associated with an existing
# target and sets a dependancy on that new command.
#
# TARGET : Name of the target to add ISPC to.
# CPP_MAIN_FILE : Main cpp file which includes ispc headers
# SOURCES : List of ISPC source files.
#
function(add_ispc_to_target)
set(options)
set(one_value_args
TARGET
CPP_MAIN_FILE
)
set(multi_value_args
SOURCES
)
cmake_parse_arguments("ADD_ISPC"
"${options}"
"${one_value_args}"
"${multi_value_args}"
${ARGN}
)
set(ISPC_DST_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/CMakeFiles/ispc/")
file(TO_NATIVE_PATH "${ISPC_DST_DIR}" ISPC_DST_DIR)
file(MAKE_DIRECTORY ${ISPC_DST_DIR})
string(FIND ${BENCHMARKS_ISPC_TARGETS} "," MULTI_TARGET)
foreach(ISPC_SRC_FILE ${ADD_ISPC_SOURCES})
set(ISPC_TARGET_HEADERS "")
set(ISPC_TARGET_OBJS "")
# Full path to source file
get_filename_component(SRC_LOCATION "${ISPC_SRC_FILE}" ABSOLUTE "${CMAKE_CURRENT_SOURCE_DIR}")
# Construct names for header and object files
string(REPLACE ".ispc" "${CMAKE_CXX_OUTPUT_EXTENSION}" ISPC_OBJ "${ISPC_SRC_FILE}")
set(ISPC_OBJ "${ISPC_DST_DIR}${ISPC_OBJ}")
string(REPLACE ".ispc" "_ispc.h" ISPC_HEADER "${ISPC_SRC_FILE}")
set(ISPC_HEADER "${ISPC_DST_DIR}${ISPC_HEADER}")
list(APPEND ISPC_TARGET_OBJS "${ISPC_OBJ}")
list(APPEND ISPC_TARGET_HEADERS "${ISPC_HEADER}")
# Collect list of expected outputs in case of multiple targets
if(${MULTI_TARGET} GREATER -1)
foreach (ISPC_TARGET ${ISPC_KNOWN_TARGETS})
string(FIND ${BENCHMARKS_ISPC_TARGETS} ${ISPC_TARGET} FOUND_TARGET)
if(${FOUND_TARGET} GREATER -1)
set(OUTPUT_TARGET ${ISPC_TARGET})
if (${ISPC_TARGET} STREQUAL "avx1")
set(OUTPUT_TARGET "avx")
endif()
string(REPLACE ".ispc" "_${OUTPUT_TARGET}${CMAKE_CXX_OUTPUT_EXTENSION}" ISPC_TARGET_OBJ ${ISPC_SRC_FILE})
set(ISPC_TARGET_OBJ ${ISPC_DST_DIR}${ISPC_TARGET_OBJ})
list(APPEND ISPC_TARGET_OBJS ${ISPC_TARGET_OBJ})
string(REPLACE ".ispc" "_ispc_${OUTPUT_TARGET}.h" ISPC_TARGET_HEADER ${ISPC_SRC_FILE})
set(ISPC_TARGET_HEADER ${ISPC_DST_DIR}${ISPC_TARGET_HEADER})
list(APPEND ISPC_TARGET_HEADERS ${ISPC_TARGET_HEADER})
endif()
endforeach()
endif()
if(UNIX)
set(ISPC_PIC "--pic")
endif()
# Passing space separate string yields escaped spaces.
# So convert to a list and then use generator expression, i.e. "$<JOIN:${FLAGS},;>"
separate_arguments(FLAGS NATIVE_COMMAND ${BENCHMARKS_ISPC_FLAGS})
add_custom_command(
OUTPUT ${ISPC_TARGET_OBJS} ${ISPC_TARGET_HEADERS}
COMMENT "Compiling ${ISPC_SRC_FILE} for ${BENCHMARKS_ISPC_TARGETS} target(s)"
COMMAND ${ISPC_EXECUTABLE} ${SRC_LOCATION} -o ${ISPC_OBJ} -h ${ISPC_HEADER} --arch=${ISPC_ARCH} --target=${BENCHMARKS_ISPC_TARGETS} ${ISPC_PIC} "$<JOIN:${FLAGS},;>"
DEPENDS ${ISPC_EXECUTABLE}
DEPENDS ${ISPC_SRC_FILE}
COMMAND_EXPAND_LISTS
)
if(MSVC)
# Add .ispc file to VS solution.
target_sources(${ADD_ISPC_TARGET} PUBLIC ${SRC_LOCATION})
# Group .ispc files inside Visual Studio
source_group("ISPC" FILES ${SRC_LOCATION})
# Group benchmarks in "Benchmarks" folder
set_target_properties(${ADD_ISPC_TARGET} PROPERTIES FOLDER "Benchmarks")
endif()
set_source_files_properties(${ISPC_TARGET_OBJS} PROPERTIES GENERATED TRUE EXTERNAL_OBJECT TRUE)
set_source_files_properties(${ISPC_TARGET_HEADERS} PROPERTIES GENERATED TRUE EXTERNAL_OBJECT TRUE)
list(APPEND ISPC_HEADERS_LIST ${SRC_LOCATION} ${ISPC_TARGET_HEADERS})
list(APPEND ISPC_OBJS_LIST ${ISPC_TARGET_OBJS})
endforeach()
set_property (SOURCE ${ADD_ISPC_CPP_MAIN_FILE} PROPERTY OBJECT_DEPENDS ${ISPC_HEADERS_LIST})
target_include_directories(${ADD_ISPC_TARGET} PRIVATE ${ISPC_DST_DIR})
target_compile_definitions(${ADD_ISPC_TARGET} PRIVATE ISPC_ENABLED)
target_link_libraries(${ADD_ISPC_TARGET} PRIVATE ${ISPC_OBJS_LIST})
endfunction()
# A macro to add a benchmark
macro(compile_benchmark_test name)
add_executable(${name} "")
# aligned_alloc() requires C++17
set_target_properties(${name} PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED YES)
add_ispc_to_target(
TARGET ${name}
CPP_MAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp
SOURCES ${name}.ispc)
target_sources(
${name}
PRIVATE ${name}.cpp)
target_compile_definitions(
${name}
PRIVATE BENCHMARKS_ISPC_TARGETS=\"${BENCHMARKS_ISPC_TARGETS}\"
BENCHMARKS_ISPC_FLAGS=\"${BENCHMARKS_ISPC_FLAGS}\")
# Turn on AVX2 support in the C++ compiler to be able to use AVX2 intrinsics.
if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
add_compile_options(-mavx2)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
add_compile_options(/QxAVX2)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
add_compile_options(/arch:AVX2)
endif()
# To enable google benchmarks:
target_link_libraries(${name} PRIVATE benchmark)
get_filename_component(INSTALL_SUBFOLDER "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
install(
TARGETS ${name}
RUNTIME DESTINATION "benchmarks/${INSTALL_SUBFOLDER}")
add_test(NAME ${name}_test COMMAND ${name} --benchmark_min_time=0.01)
add_dependencies(${BENCHMARKS_PROJECT_NAME} ${name})
endmacro(compile_benchmark_test)