diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c73d242e1..578a07702 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,9 @@ name: CI +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + on: push: pull_request: diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index c702c448f..c3af2e4c6 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -1,5 +1,9 @@ name: Static analysis +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + on: [pull_request] jobs: @@ -27,4 +31,5 @@ jobs: cmake --build build --parallel - name: Run clang-tidy run: | - clang-tidy app/**/*.cpp src/**/*.cpp -format-style=file -header-filter="($PWD/include/.*|$PWD/src/.*|$PWD/app/.*)" -p build + mapfile -t sources < <(find app src -path 'app/SYCL' -prune -o -name '*.cpp' -print) + clang-tidy "${sources[@]}" -format-style=file -header-filter="($PWD/include/.*|$PWD/src/.*|$PWD/app/.*)" -p build diff --git a/.github/workflows/sycl-ci.yml b/.github/workflows/sycl-ci.yml new file mode 100644 index 000000000..0b3241d11 --- /dev/null +++ b/.github/workflows/sycl-ci.yml @@ -0,0 +1,190 @@ +name: SYCL CI + +on: + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + INTEL_LLVM_TAG: nightly-2026-03-17 + INTEL_OPENCL_CPU_RUNTIME_URL: https://registrationcenter-download.intel.com/akdlm/IRC_NAS/ad824c04-01c8-4ae5-b5e8-164a04f67609/w_opencl_runtime_p_2025.3.1.762.exe + ADAPTIVECPP_TAG: v25.10.0 + +jobs: + prepare-sycl-linux-x86-toolchain: + name: prepare-linux-x86_64-toolchain + runs-on: ubuntu-latest + timeout-minutes: 360 + + defaults: + run: + shell: bash + + steps: + - uses: actions/checkout@v4 + + - name: Setup Ninja + uses: seanmiddleditch/gha-setup-ninja@v6 + + - name: Setup ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ccache-${{ github.job }}-${{ env.INTEL_LLVM_TAG }} + max-size: 8G + + - name: Restore Intel toolchain cache + uses: actions/cache@v4 + with: + path: ${{ runner.temp }}/intel-nativecpu-toolchain/build + key: intel-nativecpu-toolchain-${{ env.INTEL_LLVM_TAG }}-v4 + + - name: Prepare Intel native_cpu toolchain + run: python3 ./scripts/ci/sycl_x86_setup.py linux-x86_64 + + build-sycl-linux-x86: + name: linux-x86_64 / ${{ matrix.build_type }} + runs-on: ubuntu-latest + needs: prepare-sycl-linux-x86-toolchain + timeout-minutes: 360 + strategy: + fail-fast: true + matrix: + build_type: + - Debug + - Release + + defaults: + run: + shell: bash + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Setup Ninja + uses: seanmiddleditch/gha-setup-ninja@v6 + + - name: Setup ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ccache-${{ github.job }}-${{ matrix.build_type }} + max-size: 2G + + - name: Restore Intel toolchain cache + uses: actions/cache@v4 + with: + path: ${{ runner.temp }}/intel-nativecpu-toolchain/build + key: intel-nativecpu-toolchain-${{ env.INTEL_LLVM_TAG }}-v4 + + - name: Prepare platform settings + run: python3 ./scripts/ci/sycl_x86_setup.py linux-x86_64 + + - name: Configure + run: python3 ./scripts/ci/sycl_configure.py "${{ matrix.build_type }}" "${ITLABAI_ENABLE_OPENCV_APPS}" + + - name: Build + run: cmake --build build --parallel + + - name: Test + run: | + if [ -n "${DEVICE_SELECTOR}" ]; then + ONEAPI_DEVICE_SELECTOR="${DEVICE_SELECTOR}" ctest --test-dir build --output-on-failure --parallel + else + ctest --test-dir build --output-on-failure --parallel + fi + + build-sycl-windows-x86: + name: windows-x86_64 / ${{ matrix.build_type }} + runs-on: windows-2025 + timeout-minutes: 360 + strategy: + fail-fast: true + matrix: + build_type: + - Debug + - Release + + defaults: + run: + shell: bash + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Setup Ninja + uses: seanmiddleditch/gha-setup-ninja@v6 + + - name: Setup ccache + uses: Chocobo1/setup-ccache-action@v1 + with: + windows_compile_environment: msvc + + - name: Setup MSVC environment + uses: ilammy/msvc-dev-cmd@v1 + + - name: Prepare platform settings + run: python3 ./scripts/ci/sycl_x86_setup.py windows-x86_64 + + - name: Configure + run: python3 ./scripts/ci/sycl_configure.py "${{ matrix.build_type }}" "${ITLABAI_ENABLE_OPENCV_APPS}" + + - name: Build + run: cmake --build build --parallel + + - name: Test + run: | + if [ -n "${DEVICE_SELECTOR}" ]; then + ONEAPI_DEVICE_SELECTOR="${DEVICE_SELECTOR}" ctest --test-dir build --output-on-failure --parallel + else + ctest --test-dir build --output-on-failure --parallel + fi + + build-sycl-adaptivecpp-arm64: + name: ${{ matrix.platform }} / ${{ matrix.build_type }} + runs-on: ${{ matrix.platform == 'linux-arm64' && 'ubuntu-24.04-arm' || 'macos-15' }} + timeout-minutes: 360 + strategy: + fail-fast: true + matrix: + platform: + - linux-arm64 + - macos-arm64 + build_type: + - Debug + - Release + + defaults: + run: + shell: bash + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Setup Ninja + uses: seanmiddleditch/gha-setup-ninja@v6 + + - name: Setup ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ccache-${{ github.job }}-${{ matrix.platform }}-${{ matrix.build_type }} + max-size: 2G + + - name: Install AdaptiveCpp prerequisites + run: python3 ./scripts/ci/sycl_adaptivecpp_setup.py + + - name: Configure + run: python3 ./scripts/ci/sycl_configure.py "${{ matrix.build_type }}" "${ITLABAI_ENABLE_OPENCV_APPS}" + + - name: Build + run: cmake --build build --parallel + + - name: Test + run: ctest --test-dir build --output-on-failure --parallel diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index afa1a1b66..67735c083 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -1,15 +1,22 @@ add_subdirectory(googletest) +if(WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") + foreach(itlabai_gtest_target IN ITEMS gtest gtest_main gmock gmock_main) + if(TARGET ${itlabai_gtest_target}) + target_compile_options(${itlabai_gtest_target} PRIVATE -Wno-character-conversion) + endif() + endforeach() +endif() + set(DNNL_CPU_RUNTIME "TBB" CACHE STRING "oneDNN CPU threading runtime") add_subdirectory(oneDNN) -# Unified TBB Configuration +# Unified TBB configuration for the vendored fallback. option(TBB_TEST "Build TBB tests" OFF) option(TBB_EXAMPLES "Build TBB examples" OFF) set(TBB_STRICT OFF CACHE BOOL "Treat compiler warnings as errors") -# Configure TBB with unified settings add_subdirectory(TBB) # Create a unified TBB interface target @@ -20,17 +27,8 @@ if(NOT TARGET TBB_unified) $ ) - # Platform-specific runtime library handling for Windows + # Platform-specific runtime library handling for Windows. if(WIN32) - # Get the TBB library directory based on build type - if(CMAKE_BUILD_TYPE) - string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build) - set(TBB_LIB_DIR "${CMAKE_SOURCE_DIR}/3rdparty/TBB/build/tbb_${lower_build}") - else() - set(TBB_LIB_DIR "${CMAKE_SOURCE_DIR}/3rdparty/TBB/build/tbb_debug") - endif() - - # Create a custom target to copy TBB runtime libraries add_custom_target(copy_tbb_runtime ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin" COMMAND ${CMAKE_COMMAND} -E copy_if_different diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cb6861de..9cd2fa3e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,19 @@ cmake_minimum_required(VERSION 3.20) -project(ITLabAI) +project(ITLabAI LANGUAGES CXX) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE) +option(ITLABAI_ENABLE_SYCL "Build SYCL example and helper targets" OFF) +option(ITLABAI_ENABLE_OPENCV_APPS "Build OpenCV-dependent apps" ON) +option(ITLABAI_BUILD_TESTS "Build unit tests" ON) +set(ITLABAI_SYCL_IMPLEMENTATION "" CACHE STRING + "SYCL implementation to use: IntelLLVM or AdaptiveCpp") +set_property(CACHE ITLABAI_SYCL_IMPLEMENTATION PROPERTY STRINGS + IntelLLVM AdaptiveCpp) +set(ITLABAI_SYCL_TARGETS "" CACHE STRING + "Optional SYCL targets; forwarded to AdaptiveCpp as ACPP_TARGETS or IntelLLVM as -fsycl-targets") +set(ITLABAI_SYCL_ROOT "" CACHE PATH + "Optional root directory of the SYCL toolchain; used to expose SYCL headers to host-only sources") option(ENABLE_STATISTIC_TENSORS "Enable statistic tensors" OFF) @@ -21,44 +32,127 @@ option(ENABLE_STATISTIC_WEIGHTS "Enable statistic weights" OFF) if(ENABLE_STATISTIC_WEIGHTS) add_definitions(-DENABLE_STATISTIC_WEIGHTS) endif() - set(CMAKE_CXX_STANDARD 20) enable_testing() -find_package(OpenMP REQUIRED) +find_package(OpenMP REQUIRED COMPONENTS CXX) if(OpenMP_FOUND) message(STATUS "OpenMP found - enabling parallel support") - add_definitions(-DHAS_OPENMP) - link_libraries(OpenMP::OpenMP_CXX) else() message(STATUS "OpenMP not found - parallel features disabled") endif() +set(ITLABAI_OPENMP_INCLUDE_DIR "" CACHE PATH + "Optional extra include directory for the OpenMP runtime headers") +if(ITLABAI_OPENMP_INCLUDE_DIR AND TARGET OpenMP::OpenMP_CXX) + set_property(TARGET OpenMP::OpenMP_CXX APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES "${ITLABAI_OPENMP_INCLUDE_DIR}" + ) +endif() + +if(ITLABAI_ENABLE_SYCL) + if(NOT ITLABAI_SYCL_IMPLEMENTATION) + message(FATAL_ERROR + "ITLABAI_ENABLE_SYCL=ON requires ITLABAI_SYCL_IMPLEMENTATION " + "to be set to IntelLLVM or AdaptiveCpp") + endif() + + if(ITLABAI_SYCL_IMPLEMENTATION STREQUAL "AdaptiveCpp") + if(ITLABAI_SYCL_TARGETS) + set(ACPP_TARGETS "${ITLABAI_SYCL_TARGETS}" CACHE STRING + "AdaptiveCpp targets" FORCE) + endif() + find_package(AdaptiveCpp CONFIG REQUIRED) + function(itlabai_add_sycl_to_target) + add_sycl_to_target(${ARGN}) + endfunction() + elseif(ITLABAI_SYCL_IMPLEMENTATION STREQUAL "IntelLLVM") + set(ITLABAI_INTEL_SYCL_INCLUDE_DIRS "") + if(ITLABAI_SYCL_ROOT AND EXISTS "${ITLABAI_SYCL_ROOT}/include") + list(APPEND ITLABAI_INTEL_SYCL_INCLUDE_DIRS "${ITLABAI_SYCL_ROOT}/include") + endif() + function(itlabai_add_sycl_to_target) + set(options) + set(one_value_keywords TARGET) + set(multi_value_keywords SOURCES) + cmake_parse_arguments(ITLABAI_SYCL + "${options}" + "${one_value_keywords}" + "${multi_value_keywords}" + ${ARGN} + ) + + if(NOT ITLABAI_SYCL_TARGET) + message(FATAL_ERROR "itlabai_add_sycl_to_target requires TARGET") + endif() + + if(ITLABAI_INTEL_SYCL_INCLUDE_DIRS) + target_include_directories(${ITLABAI_SYCL_TARGET} PRIVATE + ${ITLABAI_INTEL_SYCL_INCLUDE_DIRS} + ) + endif() + + target_link_options(${ITLABAI_SYCL_TARGET} PRIVATE -fsycl) + + if(ITLABAI_SYCL_SOURCES) + foreach(ITLABAI_SYCL_SOURCE IN LISTS ITLABAI_SYCL_SOURCES) + set_property(SOURCE ${ITLABAI_SYCL_SOURCE} APPEND PROPERTY + COMPILE_OPTIONS -fsycl + ) + if(ITLABAI_SYCL_TARGETS) + set_property(SOURCE ${ITLABAI_SYCL_SOURCE} APPEND PROPERTY + COMPILE_OPTIONS -fsycl-targets=${ITLABAI_SYCL_TARGETS} + ) + endif() + endforeach() + else() + target_compile_options(${ITLABAI_SYCL_TARGET} PRIVATE + $<$:-fsycl> + ) + if(ITLABAI_SYCL_TARGETS) + target_compile_options(${ITLABAI_SYCL_TARGET} PRIVATE + $<$:-fsycl-targets=${ITLABAI_SYCL_TARGETS}> + ) + endif() + endif() + + if(ITLABAI_SYCL_TARGETS) + target_link_options(${ITLABAI_SYCL_TARGET} PRIVATE + -fsycl-targets=${ITLABAI_SYCL_TARGETS} + ) + endif() + endfunction() + else() + message(FATAL_ERROR + "Unsupported ITLABAI_SYCL_IMPLEMENTATION=" + "${ITLABAI_SYCL_IMPLEMENTATION}") + endif() +endif() + include_directories("include") list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") add_subdirectory(3rdparty) -include(cmake/opencv_config.cmake) +if(ITLABAI_ENABLE_OPENCV_APPS) + include(cmake/opencv_config.cmake) +endif() include(cmake/kokkos_config.cmake) -include_directories("${KOKKOS_INSTALL_DIR}/include") +include_directories(SYSTEM "${KOKKOS_INSTALL_DIR}/include") add_library(Kokkos_imported INTERFACE) add_dependencies(Kokkos_imported kokkos_external) -target_include_directories(Kokkos_imported INTERFACE +target_include_directories(Kokkos_imported SYSTEM INTERFACE "${KOKKOS_INSTALL_DIR}/include" ) - -target_link_directories(Kokkos_imported INTERFACE +target_link_directories(Kokkos_imported INTERFACE "${KOKKOS_INSTALL_DIR}/lib" ) - - target_link_libraries(Kokkos_imported INTERFACE kokkoscore kokkoscontainers) @@ -66,7 +160,23 @@ if(MSVC) add_compile_options(/wd4267 /wd4244 /wd4127 /wd4324) endif() -if (NOT WIN32) +get_filename_component(ITLABAI_C_COMPILER_NAME "${CMAKE_C_COMPILER}" NAME) +get_filename_component(ITLABAI_CXX_COMPILER_NAME "${CMAKE_CXX_COMPILER}" NAME) +string(TOLOWER "${ITLABAI_C_COMPILER_NAME}" ITLABAI_C_COMPILER_NAME_LOWER) +string(TOLOWER "${ITLABAI_CXX_COMPILER_NAME}" ITLABAI_CXX_COMPILER_NAME_LOWER) + +set(ITLABAI_WINDOWS_USES_MSVC_FRONTEND OFF) +if(WIN32 AND ( + ITLABAI_C_COMPILER_NAME_LOWER MATCHES "(^|-)cl(\\.exe)?$" + OR ITLABAI_C_COMPILER_NAME_LOWER MATCHES "clang-cl(\\.exe)?$" + OR ITLABAI_C_COMPILER_NAME_LOWER MATCHES "icx-cl(\\.exe)?$" + OR ITLABAI_CXX_COMPILER_NAME_LOWER MATCHES "(^|-)cl(\\.exe)?$" + OR ITLABAI_CXX_COMPILER_NAME_LOWER MATCHES "clang-cl(\\.exe)?$" + OR ITLABAI_CXX_COMPILER_NAME_LOWER MATCHES "icx-cl(\\.exe)?$")) + set(ITLABAI_WINDOWS_USES_MSVC_FRONTEND ON) +endif() + +if(NOT WIN32 OR NOT ITLABAI_WINDOWS_USES_MSVC_FRONTEND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror") else() @@ -83,4 +193,7 @@ endforeach() add_subdirectory(app) add_subdirectory(include) add_subdirectory(src) -add_subdirectory(test) + +if(ITLABAI_BUILD_TESTS) + add_subdirectory(test) +endif() diff --git a/app/Accuracy/CMakeLists.txt b/app/Accuracy/CMakeLists.txt index ae3deee38..9622012c1 100644 --- a/app/Accuracy/CMakeLists.txt +++ b/app/Accuracy/CMakeLists.txt @@ -3,17 +3,16 @@ set(SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/acc.cpp") add_library(ACCLib STATIC ${INCLUDE_HEADERS} ${SRC_FILES}) set_target_properties(ReadLib PROPERTIES LINKER_LANGUAGE CXX) - -find_package( OpenCV REQUIRED PATHS "${OPENCV_BUILD_DIR}" ) -include_directories( ${OpenCV_INCLUDE_DIRS} ) -target_link_libraries( ACCLib ${OpenCV_LIBS} ) -target_link_libraries( ACCLib TBB_unified) -target_link_libraries( ACCLib layers_lib) -target_link_libraries( ACCLib gtest_main) -target_link_libraries( ACCLib Kokkos_imported) +target_link_libraries(ACCLib PUBLIC OpenCV_unified) +target_link_libraries(ACCLib PUBLIC TBB_unified) +target_link_libraries(ACCLib PUBLIC layers_lib) +target_link_libraries(ACCLib PUBLIC gtest_main) +target_link_libraries(ACCLib PUBLIC Kokkos_imported) +add_dependencies(ACCLib opencv_external) add_executable(Accuracy_Check accuracy_check.cpp) target_link_libraries(Accuracy_Check ACCLib) +add_dependencies(Accuracy_Check opencv_external) file(DOWNLOAD "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/lena.jpg" diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index e2914991a..531d575ef 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,4 +1,11 @@ -add_subdirectory(ReaderImage) -add_subdirectory(Accuracy) +if(ITLABAI_ENABLE_SYCL) + add_subdirectory(SYCL) +endif() + add_subdirectory(Converters) -add_subdirectory(Graph) + +if(ITLABAI_ENABLE_OPENCV_APPS) + add_subdirectory(ReaderImage) + add_subdirectory(Accuracy) + add_subdirectory(Graph) +endif() diff --git a/app/Graph/CMakeLists.txt b/app/Graph/CMakeLists.txt index 218e511bf..49c49a135 100644 --- a/app/Graph/CMakeLists.txt +++ b/app/Graph/CMakeLists.txt @@ -3,31 +3,30 @@ set(SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/build.cpp") add_library(BuildGraph STATIC ${INCLUDE_HEADERS} ${SRC_FILES}) set_target_properties(BuildGraph PROPERTIES LINKER_LANGUAGE CXX) - -find_package(OpenCV REQUIRED PATHS "${OPENCV_BUILD_DIR}") -include_directories(${OpenCV_INCLUDE_DIRS}) - -target_link_libraries(BuildGraph PUBLIC ${OpenCV_LIBS}) +target_link_libraries(BuildGraph PUBLIC OpenCV_unified) target_link_libraries(BuildGraph PUBLIC reader_lib) target_link_libraries(BuildGraph PUBLIC TBB_unified) target_link_libraries(BuildGraph PUBLIC layers_lib) target_link_libraries(BuildGraph PUBLIC layers_fused_lib) target_link_libraries(BuildGraph PUBLIC layers_oneDNN_lib) target_link_libraries(BuildGraph PUBLIC gtest_main) +add_dependencies(BuildGraph opencv_external) target_include_directories(BuildGraph PUBLIC ${CMAKE_SOURCE_DIR}/3rdparty/Json/include) add_executable(Graph_Build graph_build.cpp) target_link_libraries(Graph_Build BuildGraph) +add_dependencies(Graph_Build opencv_external) add_executable(ACC acc_check.cpp) target_link_libraries(ACC BuildGraph) +add_dependencies(ACC opencv_external) add_executable(onnx_subgraphs onnx_subgraphs.cpp) target_link_libraries(onnx_subgraphs BuildGraph) target_link_libraries(onnx_subgraphs OpenMP::OpenMP_CXX) -target_link_libraries(onnx_subgraphs ${OpenCV_LIBS}) target_link_libraries(onnx_subgraphs graphT_lib) +add_dependencies(onnx_subgraphs opencv_external) file(DOWNLOAD "https://raw.githubusercontent.com/DeepTrackAI/MNIST_dataset/main/mnist/test/1_000008.png" diff --git a/app/ReaderImage/CMakeLists.txt b/app/ReaderImage/CMakeLists.txt index 4a2ddb2ed..687cdba83 100644 --- a/app/ReaderImage/CMakeLists.txt +++ b/app/ReaderImage/CMakeLists.txt @@ -2,16 +2,14 @@ set(INCLUDE_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/reader_img.hpp") set(SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/reader_img_s.cpp") add_library(ReadLib STATIC ${INCLUDE_HEADERS} ${SRC_FILES}) - set_target_properties(ReadLib PROPERTIES LINKER_LANGUAGE CXX) - -find_package( OpenCV REQUIRED PATHS "${OPENCV_BUILD_DIR}" ) -include_directories( ${OpenCV_INCLUDE_DIRS} ) -target_link_libraries( ReadLib ${OpenCV_LIBS} ) -target_link_libraries( ReadLib TBB_unified) +target_link_libraries(ReadLib PUBLIC OpenCV_unified) +target_link_libraries(ReadLib PUBLIC TBB_unified) +add_dependencies(ReadLib opencv_external) add_executable(Reader reader_img.cpp) target_link_libraries(Reader ReadLib) +add_dependencies(Reader opencv_external) file(DOWNLOAD "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/lena.jpg" diff --git a/app/SYCL/.clang-tidy b/app/SYCL/.clang-tidy new file mode 100644 index 000000000..672969109 --- /dev/null +++ b/app/SYCL/.clang-tidy @@ -0,0 +1,2 @@ +Checks: '-*,misc-unused-parameters' +WarningsAsErrors: '' diff --git a/app/SYCL/CMakeLists.txt b/app/SYCL/CMakeLists.txt new file mode 100644 index 000000000..20b891783 --- /dev/null +++ b/app/SYCL/CMakeLists.txt @@ -0,0 +1,76 @@ +add_executable(SYCL_Example + sycl_example.cpp +) +target_link_libraries(SYCL_Example PRIVATE layers_lib) + +if(ITLABAI_SYCL_IMPLEMENTATION STREQUAL "AdaptiveCpp") + target_link_libraries(SYCL_Example PRIVATE AdaptiveCpp::acpp-rt) +elseif(ITLABAI_SYCL_IMPLEMENTATION STREQUAL "IntelLLVM" + AND ITLABAI_SYCL_ROOT + AND EXISTS "${ITLABAI_SYCL_ROOT}/include") + target_include_directories(SYCL_Example PRIVATE "${ITLABAI_SYCL_ROOT}/include") +endif() + +if(ITLABAI_SYCL_IMPLEMENTATION STREQUAL "IntelLLVM") + target_link_options(SYCL_Example PRIVATE -fsycl) + if(ITLABAI_SYCL_TARGETS) + target_link_options(SYCL_Example PRIVATE + -fsycl-targets=${ITLABAI_SYCL_TARGETS} + ) + endif() +endif() + +set_source_files_properties(sycl_example.cpp PROPERTIES + COMPILE_DEFINITIONS "SYCL_DISABLE_FSYCL_SYCLHPP_WARNING=1" + COMPILE_OPTIONS "-Wno-deprecated-declarations" +) + +if(WIN32 AND ITLABAI_SYCL_IMPLEMENTATION STREQUAL "IntelLLVM") + if(NOT ITLABAI_SYCL_ROOT OR NOT EXISTS "${ITLABAI_SYCL_ROOT}/bin/clang++.exe") + message(FATAL_ERROR + "Windows IntelLLVM SYCL build requires clang++.exe under ITLABAI_SYCL_ROOT") + endif() + + set(SYCL_EXAMPLE_KERNEL_OBJECT + "${CMAKE_CURRENT_BINARY_DIR}/SYCL_Example.sycl_kernel.obj") + set(SYCL_KERNEL_COMPILE_COMMAND + "${ITLABAI_SYCL_ROOT}/bin/clang++.exe" + -std=c++20 + -fsycl + -I"${CMAKE_SOURCE_DIR}/include" + -I"${ITLABAI_SYCL_ROOT}/include" + -c + "${CMAKE_CURRENT_SOURCE_DIR}/sycl_kernel.cpp" + -o + "${SYCL_EXAMPLE_KERNEL_OBJECT}" + ) + if(ITLABAI_SYCL_TARGETS) + list(APPEND SYCL_KERNEL_COMPILE_COMMAND + "-fsycl-targets=${ITLABAI_SYCL_TARGETS}" + ) + endif() + + add_custom_command( + OUTPUT "${SYCL_EXAMPLE_KERNEL_OBJECT}" + COMMAND ${SYCL_KERNEL_COMPILE_COMMAND} + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/sycl_kernel.cpp" + VERBATIM + ) + target_sources(SYCL_Example PRIVATE "${SYCL_EXAMPLE_KERNEL_OBJECT}") + set_source_files_properties("${SYCL_EXAMPLE_KERNEL_OBJECT}" PROPERTIES + EXTERNAL_OBJECT TRUE + GENERATED TRUE + ) +else() + add_library(SYCL_Example_kernel OBJECT sycl_kernel.cpp) + itlabai_add_sycl_to_target(TARGET SYCL_Example_kernel SOURCES + sycl_kernel.cpp + ) + target_sources(SYCL_Example PRIVATE $) +endif() + +add_test(NAME SYCL.Example COMMAND SYCL_Example) +set_tests_properties(SYCL.Example PROPERTIES + LABELS "sycl;smoke" + TIMEOUT 60 +) diff --git a/app/SYCL/sycl_example.cpp b/app/SYCL/sycl_example.cpp new file mode 100644 index 000000000..4967360ca --- /dev/null +++ b/app/SYCL/sycl_example.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include + +#include "graph/runtime_options.hpp" +#include "layers/EWLayer.hpp" +#include "layers/Tensor.hpp" + +namespace { + +bool almost_equal(float lhs, float rhs) { + return std::fabs(lhs - rhs) < 1.0e-6F; +} + +} // namespace + +void run_sycl_kernel(sycl::queue& queue, const float* input, float* output, + std::size_t count); + +int main() { + try { + using namespace it_lab_ai; + + std::vector input_values = {-2.0F, -1.0F, 0.0F, 1.0F, 2.0F}; + Tensor input = make_tensor(input_values); + std::vector inputs = {input}; + std::vector outputs(1); + + EWLayer relu("relu"); + RuntimeOptions options; + relu.run(inputs, outputs, options); + + const std::vector& relu_output = *outputs.front().as(); + const std::vector expected_relu = {0.0F, 0.0F, 0.0F, 1.0F, 2.0F}; + + if (relu_output != expected_relu) { + std::cerr << "ITLabAI EWLayer produced an unexpected result" << '\n'; + return 1; + } + + const std::size_t count = relu_output.size(); + sycl::queue queue(sycl::default_selector_v); + std::cout << "SYCL device: " + << queue.get_device().get_info() + << '\n'; + + std::vector sycl_output(count); + run_sycl_kernel(queue, relu_output.data(), sycl_output.data(), count); + + const std::vector expected_sycl = {1.0F, 1.0F, 1.0F, 3.0F, 5.0F}; + for (std::size_t i = 0; i < count; ++i) { + if (!almost_equal(sycl_output[i], expected_sycl[i])) { + std::cerr << "SYCL kernel verification failed at index " << i << '\n'; + return 1; + } + } + + std::cout << "SYCL example completed successfully" << '\n'; + return 0; + } catch (const std::exception& exception) { + std::cerr << "Error: " << exception.what() << '\n'; + return 1; + } +} diff --git a/app/SYCL/sycl_kernel.cpp b/app/SYCL/sycl_kernel.cpp new file mode 100644 index 000000000..93ac6e239 --- /dev/null +++ b/app/SYCL/sycl_kernel.cpp @@ -0,0 +1,20 @@ +#include +#include +class SyclExampleTransformKernel; + +void run_sycl_kernel(sycl::queue& queue, const float* input, float* output, + std::size_t count) { + sycl::buffer input_buffer(input, sycl::range<1>(count)); + sycl::buffer output_buffer(output, sycl::range<1>(count)); + + queue.submit([&](sycl::handler& handler) { + auto input_acc = input_buffer.get_access(handler); + auto output_acc = + output_buffer.get_access(handler); + handler.parallel_for(sycl::range<1>(count), + [=](sycl::id<1> index) { + output_acc[index] = input_acc[index] * 2.0F + 1.0F; + }); + }); + queue.wait_and_throw(); +} diff --git a/cmake/opencv_config.cmake b/cmake/opencv_config.cmake index b5d20bc69..3d6264fc9 100644 --- a/cmake/opencv_config.cmake +++ b/cmake/opencv_config.cmake @@ -1,30 +1,216 @@ +include(ExternalProject) +include(GNUInstallDirs) + set(OPENCV_BUILD_DIR "${CMAKE_BINARY_DIR}/3rdparty/opencv_build") -file(MAKE_DIRECTORY "${OPENCV_BUILD_DIR}") - -execute_process( - COMMAND ${CMAKE_COMMAND} - -S "${CMAKE_SOURCE_DIR}/3rdparty/opencv" - -B "${OPENCV_BUILD_DIR}" - -G "${CMAKE_GENERATOR}" - -DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER} - -DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER} - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} - -DBUILD_PERF_TESTS=OFF - -DBUILD_TESTS=OFF - -DBUILD_opencv_apps=OFF - -DBUILD_JAVA=OFF - WORKING_DIRECTORY "${OPENCV_BUILD_DIR}" -) +set(OPENCV_INSTALL_DIR "${CMAKE_BINARY_DIR}/3rdparty/opencv_install") + +set(OPENCV_C_COMPILER "${CMAKE_C_COMPILER}") +set(OPENCV_CXX_COMPILER "${CMAKE_CXX_COMPILER}") + +get_filename_component(OPENCV_CXX_COMPILER_NAME "${CMAKE_CXX_COMPILER}" NAME) +string(TOLOWER "${OPENCV_CXX_COMPILER_NAME}" OPENCV_CXX_COMPILER_NAME_LOWER) + +if(WIN32) + if(OPENCV_CXX_COMPILER_NAME_LOWER MATCHES "^(clang-cl|clang\\+\\+|clang|icx|icx-cl|icpx)(\\.exe)?$") + find_program(OPENCV_HOST_MSVC_CL NAMES cl) + if(OPENCV_HOST_MSVC_CL) + set(OPENCV_C_COMPILER "${OPENCV_HOST_MSVC_CL}") + set(OPENCV_CXX_COMPILER "${OPENCV_HOST_MSVC_CL}") + endif() + endif() +elseif(OPENCV_CXX_COMPILER_NAME_LOWER STREQUAL "acpp" + OR OPENCV_CXX_COMPILER_NAME_LOWER STREQUAL "syclcc") + get_filename_component(OPENCV_HOST_COMPILER_DIR "${CMAKE_C_COMPILER}" DIRECTORY) + unset(OPENCV_CXX_COMPILER) + find_program(OPENCV_CXX_COMPILER + NAMES clang++ + PATHS "${OPENCV_HOST_COMPILER_DIR}" + NO_DEFAULT_PATH + ) + + if(NOT OPENCV_CXX_COMPILER) + find_program(OPENCV_CXX_COMPILER NAMES clang++) + endif() + + if(NOT OPENCV_CXX_COMPILER) + message(FATAL_ERROR + "Unable to locate a host C++ compiler for the OpenCV external build") + endif() +endif() -execute_process( - COMMAND ${CMAKE_COMMAND} --build "${OPENCV_BUILD_DIR}" --config "${CMAKE_BUILD_TYPE}" - WORKING_DIRECTORY "${OPENCV_BUILD_DIR}" +set(OPENCV_INITIAL_CACHE "${CMAKE_BINARY_DIR}/3rdparty/opencv_initial_cache.cmake") +file(WRITE "${OPENCV_INITIAL_CACHE}" "") +file(APPEND "${OPENCV_INITIAL_CACHE}" + "set(CMAKE_C_COMPILER \"${OPENCV_C_COMPILER}\" CACHE FILEPATH \"\" FORCE)\n") +file(APPEND "${OPENCV_INITIAL_CACHE}" + "set(CMAKE_CXX_COMPILER \"${OPENCV_CXX_COMPILER}\" CACHE FILEPATH \"\" FORCE)\n") +file(APPEND "${OPENCV_INITIAL_CACHE}" + "set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS}\" CACHE STRING \"\" FORCE)\n") +file(APPEND "${OPENCV_INITIAL_CACHE}" + "set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\" CACHE STRING \"\" FORCE)\n") + +set(OPENCV_CMAKE_ARGS + -C "${OPENCV_INITIAL_CACHE}" + -G "${CMAKE_GENERATOR}" + -DCMAKE_C_COMPILER:FILEPATH=${OPENCV_C_COMPILER} + -DCMAKE_CXX_COMPILER:FILEPATH=${OPENCV_CXX_COMPILER} + -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} + -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${OPENCV_INSTALL_DIR} + -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} + -DBUILD_PERF_TESTS=OFF + -DBUILD_TESTS=OFF + -DBUILD_opencv_apps=OFF + -DBUILD_opencv_java=OFF + -DBUILD_opencv_js=OFF + -DBUILD_opencv_objc=OFF + -DBUILD_opencv_python2=OFF + -DBUILD_opencv_python3=OFF + -DBUILD_JAVA=OFF + -DBUILD_opencv_world=ON + -DWITH_OPENMP=OFF + -DWITH_FFMPEG=OFF + -DWITH_EIGEN=OFF ) +if(APPLE) + list(APPEND OPENCV_CMAKE_ARGS + -DWITH_AVIF=OFF + -DWITH_OPENEXR=OFF + ) +endif() + +if(CMAKE_C_COMPILER_LAUNCHER) + list(APPEND OPENCV_CMAKE_ARGS + -DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER}) +endif() + +if(CMAKE_CXX_COMPILER_LAUNCHER) + list(APPEND OPENCV_CMAKE_ARGS + -DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER}) +endif() + +set(OPENCV_VERSION_FILE + "${CMAKE_SOURCE_DIR}/3rdparty/opencv/modules/core/include/opencv2/core/version.hpp") +file(STRINGS "${OPENCV_VERSION_FILE}" OPENCV_VERSION_PARTS + REGEX "#define CV_VERSION_[A-Z]+[ ]+") +string(REGEX REPLACE ".+CV_VERSION_MAJOR[ ]+([0-9]+).*" "\\1" + OPENCV_VERSION_MAJOR "${OPENCV_VERSION_PARTS}") +string(REGEX REPLACE ".+CV_VERSION_MINOR[ ]+([0-9]+).*" "\\1" + OPENCV_VERSION_MINOR "${OPENCV_VERSION_PARTS}") +string(REGEX REPLACE ".+CV_VERSION_REVISION[ ]+([0-9]+).*" "\\1" + OPENCV_VERSION_PATCH "${OPENCV_VERSION_PARTS}") + +set(OPENCV_WORLD_TARGET_NAME "opencv_world") +set(OPENCV_WORLD_IMPORT_NAME "${OPENCV_WORLD_TARGET_NAME}") +set(OPENCV_WORLD_RUNTIME_NAME "${OPENCV_WORLD_TARGET_NAME}") +set(OPENCV_INSTALL_BINARIES_PREFIX "") + if(WIN32) - file(GLOB OPENCV_DLLS "${OPENCV_BUILD_DIR}/bin/*.dll") - if(OPENCV_DLLS) - file(COPY ${OPENCV_DLLS} DESTINATION "${CMAKE_BINARY_DIR}/bin") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(OPENCV_ARCH x64) + else() + set(OPENCV_ARCH x86) endif() + + if(MSVC) + if(MSVC_VERSION GREATER_EQUAL 1930) + set(OPENCV_RUNTIME vc17) + elseif(MSVC_VERSION GREATER_EQUAL 1920) + set(OPENCV_RUNTIME vc16) + elseif(MSVC_VERSION GREATER_EQUAL 1910) + set(OPENCV_RUNTIME vc15) + else() + set(OPENCV_RUNTIME vc14) + endif() + elseif(MINGW) + set(OPENCV_RUNTIME mingw) + endif() + + if(DEFINED OPENCV_ARCH AND DEFINED OPENCV_RUNTIME) + set(OPENCV_INSTALL_BINARIES_PREFIX "${OPENCV_ARCH}/${OPENCV_RUNTIME}/") + endif() + + set(OPENCV_WORLD_IMPORT_NAME + "${OPENCV_WORLD_TARGET_NAME}${OPENCV_VERSION_MAJOR}${OPENCV_VERSION_MINOR}${OPENCV_VERSION_PATCH}") + set(OPENCV_WORLD_RUNTIME_NAME "${OPENCV_WORLD_IMPORT_NAME}") + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + string(APPEND OPENCV_WORLD_IMPORT_NAME "d") + string(APPEND OPENCV_WORLD_RUNTIME_NAME "d") + endif() +endif() + +set(OPENCV_LIBRARY_DIR + "${OPENCV_INSTALL_DIR}/${OPENCV_INSTALL_BINARIES_PREFIX}${CMAKE_INSTALL_LIBDIR}") +set(OPENCV_RUNTIME_DIR + "${OPENCV_INSTALL_DIR}/${OPENCV_INSTALL_BINARIES_PREFIX}${CMAKE_INSTALL_BINDIR}") +set(OPENCV_INCLUDE_DIRS + "${OPENCV_INSTALL_DIR}/include" + "${OPENCV_INSTALL_DIR}/include/opencv4" +) + +if(WIN32) + set(OPENCV_WORLD_IMPLIB + "${OPENCV_LIBRARY_DIR}/${OPENCV_WORLD_IMPORT_NAME}${CMAKE_IMPORT_LIBRARY_SUFFIX}") + set(OPENCV_WORLD_RUNTIME + "${OPENCV_RUNTIME_DIR}/${OPENCV_WORLD_RUNTIME_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}") +else() + set(OPENCV_WORLD_IMPLIB + "${OPENCV_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${OPENCV_WORLD_IMPORT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}") + set(OPENCV_WORLD_RUNTIME "${OPENCV_WORLD_IMPLIB}") +endif() + +set(OPENCV_INSTALL_BYPRODUCTS "${OPENCV_WORLD_IMPLIB}") +if(NOT OPENCV_WORLD_RUNTIME STREQUAL OPENCV_WORLD_IMPLIB) + list(APPEND OPENCV_INSTALL_BYPRODUCTS "${OPENCV_WORLD_RUNTIME}") +endif() + +ExternalProject_Add( + opencv_external + SOURCE_DIR "${CMAKE_SOURCE_DIR}/3rdparty/opencv" + BINARY_DIR "${OPENCV_BUILD_DIR}" + INSTALL_DIR "${OPENCV_INSTALL_DIR}" + CMAKE_ARGS ${OPENCV_CMAKE_ARGS} + INSTALL_BYPRODUCTS ${OPENCV_INSTALL_BYPRODUCTS} + BUILD_ALWAYS OFF + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON +) + +add_library(opencv_world_external SHARED IMPORTED GLOBAL) +add_dependencies(opencv_world_external opencv_external) +set_target_properties(opencv_world_external PROPERTIES + IMPORTED_LOCATION "${OPENCV_WORLD_RUNTIME}" + INTERFACE_INCLUDE_DIRECTORIES "${OPENCV_INCLUDE_DIRS}" +) + +if(WIN32) + set_target_properties(opencv_world_external PROPERTIES + IMPORTED_IMPLIB "${OPENCV_WORLD_IMPLIB}" + ) +endif() + +add_library(OpenCV_unified INTERFACE) +add_dependencies(OpenCV_unified opencv_external) +target_include_directories(OpenCV_unified INTERFACE ${OPENCV_INCLUDE_DIRS}) +target_link_libraries(OpenCV_unified INTERFACE opencv_world_external) + +if(CMAKE_BUILD_RPATH) + set(CMAKE_BUILD_RPATH "${OPENCV_LIBRARY_DIR};${CMAKE_BUILD_RPATH}") +else() + set(CMAKE_BUILD_RPATH "${OPENCV_LIBRARY_DIR}") +endif() + +if(WIN32) + add_custom_target(copy_opencv_runtime ALL + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${OPENCV_WORLD_RUNTIME}" + "${CMAKE_BINARY_DIR}/bin/" + DEPENDS opencv_external + COMMENT "Copying OpenCV runtime library" + ) + add_dependencies(OpenCV_unified copy_opencv_runtime) endif() diff --git a/include/graph/runtime_options.hpp b/include/graph/runtime_options.hpp index be05344e6..80ebb99d0 100644 --- a/include/graph/runtime_options.hpp +++ b/include/graph/runtime_options.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include #include "parallel/parallel.hpp" diff --git a/include/layers/ConcatLayer.hpp b/include/layers/ConcatLayer.hpp index a648fb0db..ee665beab 100644 --- a/include/layers/ConcatLayer.hpp +++ b/include/layers/ConcatLayer.hpp @@ -1,5 +1,6 @@ #pragma once -#include +#include + #include #include #include diff --git a/include/layers/InputLayer.hpp b/include/layers/InputLayer.hpp index e0de8e6e0..54d8904ad 100644 --- a/include/layers/InputLayer.hpp +++ b/include/layers/InputLayer.hpp @@ -1,7 +1,8 @@ #pragma once +#include + #include #include -#include #include "layers/Layer.hpp" diff --git a/include/layers/Layer.hpp b/include/layers/Layer.hpp index e6e453797..e1b6ab5b7 100644 --- a/include/layers/Layer.hpp +++ b/include/layers/Layer.hpp @@ -1,6 +1,5 @@ #pragma once #include -#include #include #include #include diff --git a/include/layers/ReduceLayer.hpp b/include/layers/ReduceLayer.hpp index 9d13d7668..384081267 100644 --- a/include/layers/ReduceLayer.hpp +++ b/include/layers/ReduceLayer.hpp @@ -1,5 +1,6 @@ #pragma once -#include +#include + #include #include diff --git a/include/layers/Tensor.hpp b/include/layers/Tensor.hpp index 464236c00..f587a2f5b 100644 --- a/include/layers/Tensor.hpp +++ b/include/layers/Tensor.hpp @@ -1,6 +1,7 @@ #pragma once -#include +#include + #include #include #include diff --git a/include/layers_oneDNN/ReduceLayer.hpp b/include/layers_oneDNN/ReduceLayer.hpp index 7b53099d4..def294888 100644 --- a/include/layers_oneDNN/ReduceLayer.hpp +++ b/include/layers_oneDNN/ReduceLayer.hpp @@ -1,5 +1,6 @@ #pragma once -#include +#include + #include #include #include diff --git a/include/parallel/backends.hpp b/include/parallel/backends.hpp index 6c5bcd996..963639602 100644 --- a/include/parallel/backends.hpp +++ b/include/parallel/backends.hpp @@ -1,12 +1,14 @@ #pragma once +// clang-format off +#include #include #include #include +// clang-format on // NOLINTNEXTLINE(misc-header-include-cycle) #include #include -#include #include #include #include @@ -15,7 +17,7 @@ namespace it_lab_ai { namespace parallel { -enum class Backend : std::uint8_t { +enum class Backend : uint8_t { kSeq = 0, kThreads = 1, kTbb = 2, @@ -92,7 +94,7 @@ inline void impl_tbb(std::size_t count, }, oneapi::tbb::auto_partitioner()); } -#ifdef HAS_OPENMP +#ifdef _OPENMP inline void impl_omp(std::size_t count, const std::function& func, const Options& opt) { @@ -119,7 +121,7 @@ inline void impl_omp(std::size_t count, #else inline void impl_omp(std::size_t count, const std::function& func, - const Options& opt) { + const Options& opt [[maybe_unused]]) { impl_seq(count, func); } #endif diff --git a/include/parallel/parallel.hpp b/include/parallel/parallel.hpp index 66851fd28..ced5bca55 100644 --- a/include/parallel/parallel.hpp +++ b/include/parallel/parallel.hpp @@ -5,7 +5,7 @@ namespace it_lab_ai { namespace parallel { constexpr bool kHasOmp = -#ifdef HAS_OPENMP +#ifdef _OPENMP true; #else false; @@ -16,7 +16,7 @@ inline Backend resolve_default_backend(std::size_t n, const Options& opt) { return Backend::kSeq; } -#ifdef HAS_OPENMP +#ifdef _OPENMP return Backend::kOmp; #else return Backend::kTbb; diff --git a/include/perf/benchmarking.hpp b/include/perf/benchmarking.hpp index e63b57c6e..c8dafac46 100644 --- a/include/perf/benchmarking.hpp +++ b/include/perf/benchmarking.hpp @@ -1,7 +1,10 @@ // Using chrono for good measurements and parallelism support #pragma once +// clang-format off +#include #include +// clang-format on #include #include diff --git a/scripts/ci/common.py b/scripts/ci/common.py new file mode 100644 index 000000000..86b4a4c56 --- /dev/null +++ b/scripts/ci/common.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import os +import shutil +import subprocess +import sys +import tarfile +import urllib.request +from pathlib import Path + + +def run(command: list[str], *, input_text: str | None = None) -> None: + print("+", " ".join(command), flush=True) + subprocess.run(command, check=True, text=True, input=input_text) + + +def capture(command: list[str]) -> str: + return subprocess.check_output(command, text=True).strip() + + +def require_env(name: str) -> str: + value = os.environ.get(name) + if not value: + raise SystemExit(f"Missing required environment variable: {name}") + return value + + +def write_env(name: str, value: str) -> None: + github_env = os.environ.get("GITHUB_ENV") + if github_env: + with open(github_env, "a", encoding="utf-8") as handle: + handle.write(f"{name}={value}\n") + os.environ[name] = value + + +def append_path(value: str) -> None: + github_path = os.environ.get("GITHUB_PATH") + if github_path: + with open(github_path, "a", encoding="utf-8") as handle: + handle.write(f"{value}\n") + + +def prepend_env_path(name: str, value: str) -> None: + current = os.environ.get(name, "") + write_env(name, f"{value}:{current}" if current else value) + + +def download(url: str, destination: Path) -> None: + destination.parent.mkdir(parents=True, exist_ok=True) + with urllib.request.urlopen(url) as response, open(destination, "wb") as handle: + shutil.copyfileobj(response, handle) + + +def extract_tarball(archive: Path, destination: Path) -> None: + destination.mkdir(parents=True, exist_ok=True) + with tarfile.open(archive, "r:gz") as tar_handle: + tar_handle.extractall(destination) + + +def cygpath(mode: str, path: str | Path) -> str: + return capture(["cygpath", f"-{mode}", str(path)]) + + +def find_first_existing(paths: list[Path]) -> Path: + for path in paths: + if path.exists(): + return path + raise SystemExit(f"Unable to locate any of: {', '.join(str(path) for path in paths)}") + + +def find_file(root_candidates: list[Path], filename: str) -> Path | None: + for root in root_candidates: + if not root.exists(): + continue + for current_root, _, files in os.walk(root): + if filename in files: + return Path(current_root) / filename + return None + + +def repo_root() -> Path: + return Path(__file__).resolve().parents[2] + + +def main_error(message: str) -> None: + print(message, file=sys.stderr) + raise SystemExit(1) diff --git a/scripts/ci/sycl_adaptivecpp_setup.py b/scripts/ci/sycl_adaptivecpp_setup.py new file mode 100644 index 000000000..3778cf1e8 --- /dev/null +++ b/scripts/ci/sycl_adaptivecpp_setup.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +from pathlib import Path + +from common import append_path, capture, prepend_env_path, require_env, run, write_env + + +def set_common_env(prefixes: list[str], clang_path: str, clangxx_path: str) -> None: + prefix_path = ";".join(prefixes) + write_env("ITLABAI_CC", clang_path) + write_env("ITLABAI_CXX", clangxx_path) + write_env("ITLABAI_CMAKE_PREFIX_PATH", prefix_path) + write_env("ITLABAI_SYCL_IMPLEMENTATION", "AdaptiveCpp") + write_env("ITLABAI_ENABLE_OPENCV_APPS", "ON") + write_env("ACPP_TARGETS", "omp.library-only") + append_path(f"{prefixes[0]}/bin") + + +def setup_macos() -> None: + run(["brew", "install", "adaptivecpp", "libomp"]) + + adaptivecpp_prefix = capture(["brew", "--prefix", "adaptivecpp"]) + libomp_prefix = capture(["brew", "--prefix", "libomp"]) + clang_path = capture(["xcrun", "--find", "clang"]) + clangxx_path = capture(["xcrun", "--find", "clang++"]) + + write_env("ITLABAI_OPENMP_ROOT", libomp_prefix) + set_common_env([adaptivecpp_prefix, libomp_prefix], clang_path, clangxx_path) + + +def setup_linux() -> None: + run(["sudo", "apt-get", "update"]) + run( + [ + "sudo", + "apt-get", + "install", + "-y", + "build-essential", + "clang-18", + "cmake", + "git", + "libboost-context-dev", + "libboost-fiber-dev", + "libboost-filesystem-dev", + "libboost-system-dev", + "libboost-test-dev", + "libclang-18-dev", + "libomp-18-dev", + "llvm-18-dev", + "python3", + ] + ) + + runner_temp = Path(require_env("RUNNER_TEMP")) + source_dir = runner_temp / "AdaptiveCpp" + build_dir = runner_temp / "AdaptiveCpp-build" + install_dir = runner_temp / "adaptivecpp-install" + tag = require_env("ADAPTIVECPP_TAG") + + run( + [ + "git", + "clone", + "--branch", + tag, + "--depth", + "1", + "https://github.com/AdaptiveCpp/AdaptiveCpp.git", + str(source_dir), + ] + ) + run( + [ + "cmake", + "-S", + str(source_dir), + "-B", + str(build_dir), + "-G", + "Ninja", + "-DCMAKE_BUILD_TYPE=Release", + f"-DCMAKE_INSTALL_PREFIX={install_dir}", + "-DCMAKE_C_COMPILER=clang-18", + "-DCMAKE_CXX_COMPILER=clang++-18", + "-DLLVM_DIR=/usr/lib/llvm-18/lib/cmake/llvm", + "-DClang_DIR=/usr/lib/llvm-18/lib/cmake/clang", + ] + ) + run(["cmake", "--build", str(build_dir), "--target", "install", "--parallel"]) + + set_common_env([str(install_dir)], "/usr/bin/clang-18", "/usr/bin/clang++-18") + prepend_env_path("LD_LIBRARY_PATH", f"{install_dir}/lib") + prepend_env_path("LD_LIBRARY_PATH", "/usr/lib/llvm-18/lib") + + +def main() -> None: + runner_os = require_env("RUNNER_OS") + if runner_os == "macOS": + setup_macos() + elif runner_os == "Linux": + setup_linux() + else: + raise SystemExit(f"Unsupported RUNNER_OS for AdaptiveCpp setup: {runner_os}") + + +if __name__ == "__main__": + main() diff --git a/scripts/ci/sycl_configure.py b/scripts/ci/sycl_configure.py new file mode 100644 index 000000000..4f2d34c3f --- /dev/null +++ b/scripts/ci/sycl_configure.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import os +import sys + +from common import main_error, require_env, run + + +def main() -> None: + if len(sys.argv) != 3: + main_error("Usage: sycl_configure.py ") + + build_type, opencv_apps = sys.argv[1:] + + cmake_args = [] + if require_env("RUNNER_OS") != "Windows": + cmake_args.extend( + [ + "-DCMAKE_C_COMPILER_LAUNCHER=ccache", + "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache", + ] + ) + + openmp_flags = os.environ.get("ITLABAI_OPENMP_FLAGS", "") + if openmp_flags: + cmake_args.append(f"-DOpenMP_CXX_FLAGS={openmp_flags}") + + openmp_library_name = os.environ.get("ITLABAI_OPENMP_LIBRARY_NAME", "") + openmp_library = os.environ.get("ITLABAI_OPENMP_LIBRARY", "") + if openmp_library: + if not openmp_library_name: + main_error("ITLABAI_OPENMP_LIBRARY is set without ITLABAI_OPENMP_LIBRARY_NAME") + cmake_args.extend( + [ + f"-DOpenMP_CXX_LIB_NAMES={openmp_library_name}", + f"-DOpenMP_{openmp_library_name}_LIBRARY={openmp_library}", + ] + ) + + openmp_include_dir = os.environ.get("ITLABAI_OPENMP_INCLUDE_DIR", "") + if openmp_include_dir: + cmake_args.append(f"-DITLABAI_OPENMP_INCLUDE_DIR={openmp_include_dir}") + + openmp_root = os.environ.get("ITLABAI_OPENMP_ROOT", "") + if openmp_root: + cmake_args.append(f"-DOpenMP_ROOT={openmp_root}") + + acpp_targets = os.environ.get("ACPP_TARGETS", "") + if acpp_targets: + cmake_args.append(f"-DACPP_TARGETS={acpp_targets}") + + itlabai_sycl_targets = os.environ.get("ITLABAI_SYCL_TARGETS", "") + if itlabai_sycl_targets: + cmake_args.append(f"-DITLABAI_SYCL_TARGETS={itlabai_sycl_targets}") + + itlabai_sycl_root = os.environ.get("SYCL_ROOT", "") + if itlabai_sycl_root: + cmake_args.append(f"-DITLABAI_SYCL_ROOT={itlabai_sycl_root}") + + c_flags = os.environ.get("ITLABAI_C_FLAGS", "") + cxx_flags = os.environ.get("ITLABAI_CXX_FLAGS", "") + gcc_install_dir = os.environ.get("ITLABAI_GCC_INSTALL_DIR", "") + if gcc_install_dir: + gcc_toolchain_flag = f"--gcc-install-dir={gcc_install_dir}" + cmake_args.append(f"-DCMAKE_C_FLAGS={gcc_toolchain_flag} {c_flags}".strip()) + cmake_args.append(f"-DCMAKE_CXX_FLAGS={gcc_toolchain_flag} {cxx_flags}".strip()) + else: + if c_flags: + cmake_args.append(f"-DCMAKE_C_FLAGS={c_flags}") + if cxx_flags: + cmake_args.append(f"-DCMAKE_CXX_FLAGS={cxx_flags}") + + run( + [ + "cmake", + "-S", + ".", + "-B", + "build", + "-G", + "Ninja", + *cmake_args, + f"-DCMAKE_C_COMPILER={require_env('ITLABAI_CC')}", + f"-DCMAKE_CXX_COMPILER={require_env('ITLABAI_CXX')}", + f"-DCMAKE_BUILD_TYPE={build_type}", + f"-DCMAKE_PREFIX_PATH={require_env('ITLABAI_CMAKE_PREFIX_PATH')}", + f"-DITLABAI_ENABLE_OPENCV_APPS={opencv_apps}", + "-DITLABAI_BUILD_TESTS=ON", + "-DITLABAI_ENABLE_SYCL=ON", + f"-DITLABAI_SYCL_IMPLEMENTATION={require_env('ITLABAI_SYCL_IMPLEMENTATION')}", + ] + ) + + +if __name__ == "__main__": + main() diff --git a/scripts/ci/sycl_x86_setup.py b/scripts/ci/sycl_x86_setup.py new file mode 100644 index 000000000..51486ed56 --- /dev/null +++ b/scripts/ci/sycl_x86_setup.py @@ -0,0 +1,378 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import os +import shutil +import sys +from pathlib import Path + +from common import ( + append_path, + capture, + cygpath, + download, + extract_tarball, + find_file, + find_first_existing, + main_error, + require_env, + run, + write_env, +) + + +def linux_native_cpu_toolchain_root() -> Path: + return Path(require_env("RUNNER_TEMP")) / "intel-nativecpu-toolchain" / "build" + + +def linux_native_cpu_toolchain_ready(toolchain_root: Path) -> bool: + if not toolchain_root.exists(): + return False + compiler_candidates = [ + toolchain_root / "bin" / "clang++", + toolchain_root / "bin" / "compiler" / "clang++", + ] + has_compiler = any(path.exists() for path in compiler_candidates) + has_runtime = find_file([toolchain_root], "libsycl.so") is not None or find_file( + [toolchain_root], "libsycl.so.9" + ) is not None + has_native_cpu_libspirv = ( + find_file([toolchain_root], "remangled-l64-signed_char.libspirv.bc") + is not None + ) + return has_compiler and has_runtime and has_native_cpu_libspirv + + +def configure_platform(platform: str) -> None: + settings = { + "linux-x86_64": { + "toolchain_asset": "", + "device_selector": "native_cpu:cpu", + "opencv_apps": "ON", + "sycl_targets": "native_cpu", + }, + "windows-x86_64": { + "toolchain_asset": "sycl_windows.tar.gz", + "device_selector": "opencl:cpu", + "opencv_apps": "ON", + "sycl_targets": "spir64_x86_64", + }, + }.get(platform) + + if settings is None: + main_error(f"Unsupported platform: {platform}") + + write_env("TOOLCHAIN_ASSET", settings["toolchain_asset"]) + write_env("DEVICE_SELECTOR", settings["device_selector"]) + write_env("ITLABAI_ENABLE_OPENCV_APPS", settings["opencv_apps"]) + write_env("ITLABAI_SYCL_IMPLEMENTATION", "IntelLLVM") + write_env("ITLABAI_SYCL_TARGETS", settings["sycl_targets"]) + + +def setup_linux_runtime() -> None: + command_prefix = [] if os.geteuid() == 0 else ["sudo"] + run([*command_prefix, "apt-get", "update"]) + run( + [ + *command_prefix, + "apt-get", + "install", + "-y", + "build-essential", + "ccache", + "cmake", + "g++-13", + "gcc-13", + "git", + "libzstd-dev", + "ninja-build", + "python3", + "zstd", + ] + ) + write_env("ITLABAI_GCC_INSTALL_DIR", "/usr/lib/gcc/x86_64-linux-gnu/13") + + +def build_linux_native_cpu_toolchain() -> Path: + toolchain_root = linux_native_cpu_toolchain_root() + if linux_native_cpu_toolchain_ready(toolchain_root): + write_env("SYCL_ROOT", str(toolchain_root)) + return toolchain_root + + toolchain_base = toolchain_root.parent + source_dir = toolchain_base / "src" + build_dir = toolchain_root + llvm_tag = require_env("INTEL_LLVM_TAG") + + toolchain_base.mkdir(parents=True, exist_ok=True) + if not (source_dir / ".git").exists(): + run( + [ + "git", + "clone", + "--depth", + "1", + "--branch", + llvm_tag, + "https://github.com/intel/llvm.git", + str(source_dir), + ] + ) + + configure_stamp = build_dir / "CMakeCache.txt" + if not configure_stamp.exists(): + build_dir.mkdir(parents=True, exist_ok=True) + run( + [ + "python3", + str(source_dir / "buildbot" / "configure.py"), + "-w", + str(toolchain_base), + "-s", + str(source_dir), + "-o", + str(build_dir), + "-t", + "Release", + "--ci-defaults", + "--native_cpu", + "--cmake-gen", + "Ninja", + "--use-zstd", + "--cmake-opt=-DLLVM_ENABLE_RUNTIMES=compiler-rt;openmp", + "-DCMAKE_C_COMPILER=gcc-13", + "-DCMAKE_CXX_COMPILER=g++-13", + "-DCMAKE_C_COMPILER_LAUNCHER=ccache", + "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache", + "-DSYCL_ENABLE_BACKENDS=native_cpu", + "-DSYCL_INCLUDE_TESTS=OFF", + "-DLLVM_INSTALL_UTILS=ON", + "-DSYCL_UR_FORCE_FETCH_LEVEL_ZERO=ON", + ] + ) + + run(["cmake", "--build", str(build_dir), "--target", "sycl-toolchain", "--parallel"]) + + if not linux_native_cpu_toolchain_ready(toolchain_root): + main_error( + "Intel SYCL native_cpu toolchain build completed, but required files " + "were not produced in the build tree" + ) + + write_env("SYCL_ROOT", str(toolchain_root)) + return toolchain_root + + +def prepare_sycl_toolchain() -> Path: + if require_env("RUNNER_OS") == "Linux" and not os.environ.get("TOOLCHAIN_ASSET"): + return build_linux_native_cpu_toolchain() + + runner_os = require_env("RUNNER_OS") + runner_temp = require_env("RUNNER_TEMP") + runner_temp_dir = Path(cygpath("u", runner_temp) if runner_os == "Windows" else runner_temp) + toolchain_asset = require_env("TOOLCHAIN_ASSET") + llvm_tag = require_env("INTEL_LLVM_TAG") + + sycl_extract_root = runner_temp_dir / "intel-sycl" + archive_path = runner_temp_dir / toolchain_asset + download( + f"https://github.com/intel/llvm/releases/download/{llvm_tag}/{toolchain_asset}", + archive_path, + ) + extract_tarball(archive_path, sycl_extract_root) + + sycl_root = sycl_extract_root + if (sycl_root / "sycl_windows" / "bin").is_dir(): + sycl_root = sycl_root / "sycl_windows" + elif (sycl_root / "sycl_linux" / "bin").is_dir(): + sycl_root = sycl_root / "sycl_linux" + + write_env("SYCL_ROOT", str(sycl_root)) + return sycl_root + + +def setup_windows_compilers(sycl_root: Path) -> None: + runner_temp_dir = Path(cygpath("u", require_env("RUNNER_TEMP"))) + runtime_archive = runner_temp_dir / "intel-opencl-runtime.exe" + runtime_extract_dir = runner_temp_dir / "intel-opencl-runtime" + runtime_msi = runtime_extract_dir / "w_opencl_runtime_p_2025.3.1.762.msi" + + download(require_env("INTEL_OPENCL_CPU_RUNTIME_URL"), runtime_archive) + run(["7z", "x", "-y", f"-o{runtime_extract_dir}", str(runtime_archive)]) + run( + [ + "powershell", + "-NoProfile", + "-Command", + ( + "Start-Process msiexec.exe -Wait -ArgumentList " + f"'/i', '{cygpath('w', runtime_msi)}', '/qn', '/norestart'" + ), + ] + ) + + cc_path = find_first_existing( + [ + sycl_root / "bin" / "icx.exe", + sycl_root / "bin" / "icx-cl.exe", + sycl_root / "bin" / "clang-cl.exe", + sycl_root / "bin" / "clang.exe", + ] + ) + cxx_path = find_first_existing( + [ + sycl_root / "bin" / "icpx.exe", + sycl_root / "bin" / "icx-cl.exe", + sycl_root / "bin" / "clang-cl.exe", + sycl_root / "bin" / "clang++.exe", + ] + ) + + write_env("ITLABAI_CC", cygpath("m", cc_path)) + write_env("ITLABAI_CXX", cygpath("m", cxx_path)) + write_env("ITLABAI_CMAKE_PREFIX_PATH", cygpath("m", sycl_root)) + append_path(cygpath("m", sycl_root / "bin")) + + +def setup_unix_compilers(sycl_root: Path) -> None: + cc_candidates = [sycl_root / "bin" / "icx", sycl_root / "bin" / "clang"] + cxx_candidates = [sycl_root / "bin" / "icpx", sycl_root / "bin" / "clang++"] + prefix_paths = [sycl_root] + library_roots = [sycl_root] + sycl_runtime_dirs: list[Path] = [] + + source_built_linux_toolchain = False + if require_env("RUNNER_OS") == "Linux": + compiler_root = Path(require_env("SYCL_ROOT")) + source_built_linux_toolchain = not os.environ.get("TOOLCHAIN_ASSET") + cc_candidates = [ + compiler_root / "bin" / "icx", + compiler_root / "bin" / "clang", + compiler_root / "bin" / "compiler" / "icx", + compiler_root / "bin" / "compiler" / "clang", + *cc_candidates, + ] + cxx_candidates = [ + compiler_root / "bin" / "icpx", + compiler_root / "bin" / "clang++", + compiler_root / "bin" / "compiler" / "icpx", + compiler_root / "bin" / "compiler" / "clang++", + *cxx_candidates, + ] + prefix_paths = [compiler_root] + library_roots = [compiler_root] + + cc_path = find_first_existing(cc_candidates) + cxx_path = find_first_existing(cxx_candidates) + + write_env("ITLABAI_CC", str(cc_path)) + write_env("ITLABAI_CXX", str(cxx_path)) + write_env( + "ITLABAI_CMAKE_PREFIX_PATH", + ":".join(str(path) for path in prefix_paths if path.exists()), + ) + append_path(str(cc_path.parent)) + append_path(str(sycl_root / "bin")) + + if require_env("RUNNER_OS") == "Linux": + export_openmp_include_dir = True + openmp_header = None + openmp_library = find_file([sycl_root, Path("/opt/intel/oneapi")], "libiomp5.so") + openmp_library_name = "iomp5" + openmp_flags = "-fopenmp=libiomp5" + if openmp_library is None: + openmp_library = find_file([sycl_root, Path("/opt/intel/oneapi")], "libomp.so") + openmp_library_name = "omp" + openmp_flags = "-fopenmp" + if openmp_library is None and source_built_linux_toolchain: + gcc_root = Path(require_env("ITLABAI_GCC_INSTALL_DIR")) + gcc_include_root = gcc_root / "include" + gcc_openmp_header = find_file([gcc_include_root], "omp.h") + gcc_openmp_library = Path(capture(["gcc-13", "-print-file-name=libgomp.so"])) + if gcc_openmp_header is not None and gcc_openmp_library.exists(): + staged_openmp_include_dir = Path(require_env("RUNNER_TEMP")) / "gcc-openmp-include" + staged_openmp_include_dir.mkdir(parents=True, exist_ok=True) + shutil.copy2(gcc_openmp_header, staged_openmp_include_dir / "omp.h") + openmp_library = gcc_openmp_library + openmp_library_name = "gomp" + openmp_flags = "-fopenmp=libgomp" + openmp_header = staged_openmp_include_dir / "omp.h" + if openmp_library is None and not source_built_linux_toolchain: + main_error("Unable to locate an Intel toolchain OpenMP runtime library") + + if openmp_library_name != "gomp": + resource_dir = Path(capture([str(cxx_path), "-print-resource-dir"])) + openmp_header = find_file( + [ + resource_dir / "include", + sycl_root, + Path("/opt/intel/oneapi"), + ], + "omp.h", + ) + if openmp_library_name != "gomp" and openmp_header is None and source_built_linux_toolchain: + gcc_root = Path(require_env("ITLABAI_GCC_INSTALL_DIR")) + openmp_header = find_file([gcc_root / "include"], "omp.h") + export_openmp_include_dir = False + if openmp_library_name != "gomp" and openmp_header is None and not source_built_linux_toolchain: + main_error( + "Unable to locate Intel-provided omp.h under the SYCL toolchain" + ) + + if openmp_library is not None: + write_env("ITLABAI_OPENMP_FLAGS", openmp_flags) + write_env("ITLABAI_OPENMP_LIBRARY_NAME", openmp_library_name) + write_env("ITLABAI_OPENMP_LIBRARY", str(openmp_library)) + if openmp_header is not None and export_openmp_include_dir: + write_env("ITLABAI_OPENMP_INCLUDE_DIR", str(openmp_header.parent)) + + libsycl = find_file(library_roots + [sycl_root], "libsycl.so.8") + if libsycl is None: + libsycl = find_file(library_roots + [sycl_root], "libsycl.so") + if libsycl is not None: + sycl_runtime_dirs.append(libsycl.parent) + + for root in library_roots: + for library_dir_name in ("lib", "lib64"): + library_dir = root / library_dir_name + if library_dir.is_dir(): + current = os.environ.get("LD_LIBRARY_PATH", "") + write_env( + "LD_LIBRARY_PATH", + f"{library_dir}:{current}" if current else str(library_dir), + ) + current = os.environ.get("DYLD_LIBRARY_PATH", "") + write_env( + "DYLD_LIBRARY_PATH", + f"{library_dir}:{current}" if current else str(library_dir), + ) + + for runtime_dir in sycl_runtime_dirs: + current = os.environ.get("LD_LIBRARY_PATH", "") + write_env( + "LD_LIBRARY_PATH", + f"{runtime_dir}:{current}" if current else str(runtime_dir), + ) + + +def main() -> None: + if len(sys.argv) != 2: + main_error("Usage: sycl_x86_setup.py ") + + platform = sys.argv[1] + configure_platform(platform) + + if require_env("RUNNER_OS") == "Linux": + setup_linux_runtime() + + sycl_root = prepare_sycl_toolchain() + + if require_env("RUNNER_OS") == "Windows": + setup_windows_compilers(sycl_root) + else: + setup_unix_compilers(sycl_root) + + +if __name__ == "__main__": + main() diff --git a/src/Weights_Reader/reader_weights.cpp b/src/Weights_Reader/reader_weights.cpp index 8b41bba0e..d4ceac3df 100644 --- a/src/Weights_Reader/reader_weights.cpp +++ b/src/Weights_Reader/reader_weights.cpp @@ -1,4 +1,4 @@ -#include "Weights_Reader/reader_weights.hpp" +#include "Weights_Reader/reader_weights.hpp" #include #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 142773ef3..e4d5294aa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,18 +1,24 @@ file(GLOB_RECURSE TEST_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +if(NOT ITLABAI_ENABLE_OPENCV_APPS) + list(REMOVE_ITEM TEST_SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/test_read/test_read.cpp") +endif() + add_executable(run_test ${TEST_SRC_FILES}) target_link_libraries(run_test PUBLIC OpenMP::OpenMP_CXX) target_link_libraries(run_test PUBLIC perf_lib layers_lib layers_oneDNN_lib layers_fused_lib) target_link_libraries(run_test PUBLIC gtest) -target_link_libraries(run_test PUBLIC ReadLib) target_link_libraries(run_test PUBLIC reader_lib) target_link_libraries(run_test PUBLIC graph_lib) target_link_libraries(run_test PUBLIC graphT_lib) +if(ITLABAI_ENABLE_OPENCV_APPS) + target_link_libraries(run_test PUBLIC ReadLib) + target_include_directories(run_test PRIVATE "${CMAKE_SOURCE_DIR}/app/ReaderImage") +endif() target_include_directories(run_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") -target_include_directories(run_test PRIVATE "${CMAKE_SOURCE_DIR}/app/ReaderImage") if (WIN32) add_custom_command(TARGET run_test POST_BUILD @@ -24,13 +30,15 @@ endif() add_test(UnitTests ${CMAKE_BINARY_DIR}/bin/run_test) -file(DOWNLOAD - "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/lena.jpg" - "${CMAKE_CURRENT_BINARY_DIR}/image.jpg" - SHOW_PROGRESS - STATUS status_code - LOG log_file -) +if(ITLABAI_ENABLE_OPENCV_APPS) + file(DOWNLOAD + "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/lena.jpg" + "${CMAKE_CURRENT_BINARY_DIR}/image.jpg" + SHOW_PROGRESS + STATUS status_code + LOG log_file + ) +endif() file(DOWNLOAD "https://raw.githubusercontent.com/bpinaya/AlexNetRT/master/data/alexnet/imagenet-labels.txt" diff --git a/test/main.cpp b/test/main.cpp index a4eba4de1..c8572711f 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,20 +1,20 @@ #include -#include #include #include +#include "utils/env.hpp" + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); - const char* flaky_disabled = std::getenv("DISABLE_FLAKY_TESTS"); - bool flaky_enabled = - (flaky_disabled == nullptr) || (std::strcmp(flaky_disabled, "1") != 0 && - std::strcmp(flaky_disabled, "true") != 0); + const std::string flaky_disabled = test_utils::get_env("DISABLE_FLAKY_TESTS"); + bool flaky_enabled = flaky_disabled.empty() || + (flaky_disabled != "1" && flaky_disabled != "true"); if (flaky_enabled) { - const char* retries = std::getenv("FLAKY_RETRIES"); - int retry_count = retries ? std::atoi(retries) : 10; + const std::string retries = test_utils::get_env("FLAKY_RETRIES"); + int retry_count = retries.empty() ? 10 : std::atoi(retries.c_str()); std::cout << "Flaky test support enabled. Max retries: " << retry_count << '\n'; std::cout << "Use FLAKY_TEST/FLAKY_TEST_F macros to create flaky tests." diff --git a/test/single_layer/test_batchnormalizationlayer.cpp b/test/single_layer/test_batchnormalizationlayer.cpp index 17370b539..7190569fb 100644 --- a/test/single_layer/test_batchnormalizationlayer.cpp +++ b/test/single_layer/test_batchnormalizationlayer.cpp @@ -1,5 +1,6 @@ -#include -#include +#include + +#include #include #include diff --git a/test/single_layer/test_matmullayer.cpp b/test/single_layer/test_matmullayer.cpp index f31c59ef1..889731304 100644 --- a/test/single_layer/test_matmullayer.cpp +++ b/test/single_layer/test_matmullayer.cpp @@ -1,4 +1,5 @@ -#include +#include + #include #include diff --git a/test/single_layer/test_tensor.cpp b/test/single_layer/test_tensor.cpp index 5054e460e..549f75a6e 100644 --- a/test/single_layer/test_tensor.cpp +++ b/test/single_layer/test_tensor.cpp @@ -1,4 +1,5 @@ -#include +#include + #include #include diff --git a/test/single_layer/test_transposelayer.cpp b/test/single_layer/test_transposelayer.cpp index c538a1303..be0b9cf39 100644 --- a/test/single_layer/test_transposelayer.cpp +++ b/test/single_layer/test_transposelayer.cpp @@ -1,4 +1,5 @@ -#include +#include + #include #include diff --git a/test/utils/env.hpp b/test/utils/env.hpp new file mode 100644 index 000000000..a91ed167e --- /dev/null +++ b/test/utils/env.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace test_utils { + +inline std::string get_env(const char* name) { +#ifdef _WIN32 + char* value = nullptr; + std::size_t size = 0; + if (_dupenv_s(&value, &size, name) != 0 || value == nullptr) { + return {}; + } + + std::string result(value); + free(value); + return result; +#else + const char* value = std::getenv(name); + return value == nullptr ? std::string() : std::string(value); +#endif +} + +} // namespace test_utils diff --git a/test/utils/flaky_test_runner.hpp b/test/utils/flaky_test_runner.hpp index 36aa19ad4..8c621af91 100644 --- a/test/utils/flaky_test_runner.hpp +++ b/test/utils/flaky_test_runner.hpp @@ -2,15 +2,16 @@ #include -#include #include #include +#include "env.hpp" + namespace test_utils { static int getFlakyRetries() { - const char* retry_env = std::getenv("FLAKY_RETRIES"); - if (retry_env != nullptr) { + const std::string retry_env = get_env("FLAKY_RETRIES"); + if (!retry_env.empty()) { try { int retries = std::stoi(retry_env); return std::max(1, std::min(retries, 100)); @@ -22,11 +23,11 @@ static int getFlakyRetries() { } static bool isFlakyTestsEnabled() { - const char* disabled = std::getenv("DISABLE_FLAKY_TESTS"); - if (disabled == nullptr) { + const std::string disabled = get_env("DISABLE_FLAKY_TESTS"); + if (disabled.empty()) { return true; } - return std::strcmp(disabled, "1") != 0 && std::strcmp(disabled, "true") != 0; + return disabled != "1" && disabled != "true"; } template