223 lines
8.7 KiB
CMake
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)
|