File: AddBenchmark.cmake

package info (click to toggle)
ispc 1.28.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 97,620 kB
  • sloc: cpp: 77,067; python: 8,303; yacc: 3,337; lex: 1,126; ansic: 631; sh: 475; makefile: 17
file content (210 lines) | stat: -rw-r--r-- 7,937 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#
#  Copyright (c) 2020-2025, Intel Corporation
#
#  SPDX-License-Identifier: BSD-3-Clause

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 sh "-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()
    elseif("${ARCH}" STREQUAL "aarch64")
        set(ISPC_ARCH "aarch64")
    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" "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})

        # Pass HAS_FP16 definition to ISPC compiler
        if(HAS_FP16_SUPPORT)
            set(ISPC_FP16_FLAG "-DHAS_FP16")
        else()
            set(ISPC_FP16_FLAG "")
        endif()
        set(INTRINSICS_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../../stdlib/include)

        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} ${ISPC_FP16_FLAG} -I${INTRINSICS_HEADERS} "$<JOIN:${FLAGS},;>"
            DEPENDS ${ISPC_EXECUTABLE} ${ISPC_DEPS}
            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})
    if (X86_HOST)
        target_compile_definitions(${ADD_ISPC_TARGET} PRIVATE IS_X86_ARCH)
    endif()
    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}\")

    if(${ISPC_ARCH} MATCHES "x86|x86-64")
        # 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()
    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)