chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
# Format Style Options - Created with Clang Power Tools
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
ColumnLimit: 120
|
||||
...
|
||||
@@ -0,0 +1,39 @@
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts/
|
||||
.vscode/
|
||||
.vs/
|
||||
libnd4j.xcodeproj/
|
||||
runtests*/
|
||||
.csettings/
|
||||
.project
|
||||
*.so
|
||||
*.a
|
||||
*.dll
|
||||
*.dylib
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
cmake-build-debug/
|
||||
preprocessed/
|
||||
libnd4j.build/
|
||||
build
|
||||
*.ptx
|
||||
*.cubin
|
||||
cubinbuild
|
||||
pitxbuild
|
||||
blasbuild
|
||||
testbuild
|
||||
.idea/
|
||||
libnd4jtests
|
||||
runtests
|
||||
.DS_Store
|
||||
*.cbp
|
||||
CTestTestfile.cmake
|
||||
compile_commands.json
|
||||
CPackConfig.cmake
|
||||
CPackSourceConfig.cmake
|
||||
target
|
||||
minifier
|
||||
tests_cpu/layers_tests/minifier
|
||||
tests_cpu/layers_tests/minifier.dSYM/
|
||||
Executable
+236
@@ -0,0 +1,236 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
# ============================================================================
|
||||
# STALE MAKEFILE DETECTION AND CLEANUP
|
||||
# ============================================================================
|
||||
# CMake's progress tracking can become inconsistent when template-generated
|
||||
# files change between builds, causing build failures with "No rule to make target"
|
||||
# This check forces a clean reconfiguration if stale Makefiles are detected
|
||||
if(EXISTS "${CMAKE_BINARY_DIR}/CMakeFiles/progress.marks")
|
||||
file(READ "${CMAKE_BINARY_DIR}/CMakeFiles/progress.marks" PROGRESS_MARKS)
|
||||
string(STRIP "${PROGRESS_MARKS}" PROGRESS_MARKS)
|
||||
|
||||
# If progress marks is suspiciously low (99 or less), force reconfiguration
|
||||
# Real builds should have much higher counts with template instantiations
|
||||
if(PROGRESS_MARKS LESS 200)
|
||||
message(STATUS "⚠️ Detected stale CMake progress tracking (only ${PROGRESS_MARKS} marks)")
|
||||
message(STATUS " Forcing clean reconfiguration to fix Makefile consistency...")
|
||||
|
||||
# Delete all CMake-generated Makefiles and progress files
|
||||
file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/CMakeFiles/Makefile2")
|
||||
file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/CMakeFiles/progress.marks")
|
||||
file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/CMakeFiles/nd4jcpu_object.dir/progress.make")
|
||||
file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/CMakeFiles/nd4jcpu_object.dir/build.make")
|
||||
file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/CMakeCache.txt")
|
||||
|
||||
message(FATAL_ERROR "Stale Makefiles deleted. Please re-run cmake to regenerate build system.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ============================================================================
|
||||
# CCACHE SETUP - Must be before project() for proper compiler launcher setup
|
||||
# ============================================================================
|
||||
# NOTE: ccache is DISABLED for debug and functrace builds due to poor hit rates
|
||||
# Debug/functrace flags (-finstrument-functions, -fdebug-info-for-profiling, etc.)
|
||||
# cause constant cache invalidation, making ccache overhead > benefit
|
||||
# See: Build 265 analysis - 32% hit rate with 55% slower builds
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
if(CCACHE_PROGRAM)
|
||||
# Check if this is a debug or functrace build
|
||||
set(CCACHE_SKIP_REASON "")
|
||||
|
||||
# Note: CMAKE_BUILD_TYPE might not be set yet, so check cache variables too
|
||||
if(DEFINED SD_GCC_FUNCTRACE AND SD_GCC_FUNCTRACE)
|
||||
set(CCACHE_SKIP_REASON "functrace build (instrumentation flags hurt cache hit rate)")
|
||||
elseif(CMAKE_BUILD_TYPE MATCHES "Debug" OR CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
|
||||
set(CCACHE_SKIP_REASON "debug build (debug info flags hurt cache hit rate)")
|
||||
endif()
|
||||
|
||||
if(CCACHE_SKIP_REASON)
|
||||
message(STATUS "⚠️ Ccache DISABLED for ${CCACHE_SKIP_REASON}")
|
||||
message(STATUS " Reason: Debug/functrace flags cause 60-70% cache miss rate, making ccache slower than no cache")
|
||||
set(CMAKE_C_COMPILER_LAUNCHER "" CACHE STRING "C compiler launcher" FORCE)
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER "" CACHE STRING "C++ compiler launcher" FORCE)
|
||||
else()
|
||||
message(STATUS "✅ Found ccache: ${CCACHE_PROGRAM}")
|
||||
|
||||
# Configure ccache to avoid race conditions with directory creation
|
||||
execute_process(COMMAND ${CCACHE_PROGRAM} --set-config=compiler_check=mtime ERROR_QUIET)
|
||||
execute_process(COMMAND ${CCACHE_PROGRAM} --set-config=sloppiness=include_file_mtime,include_file_ctime ERROR_QUIET)
|
||||
|
||||
# Use FORCE to ensure cache is always updated and avoid inconsistent builds
|
||||
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" CACHE STRING "C compiler launcher" FORCE)
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" CACHE STRING "C++ compiler launcher" FORCE)
|
||||
# CUDA launcher will be set after project() if needed
|
||||
message(STATUS "✅ Ccache enabled - builds will be significantly faster after first compilation")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "ℹ️ Ccache not found - install with: sudo apt-get install ccache (or brew install ccache)")
|
||||
# Explicitly unset launcher if ccache not found
|
||||
set(CMAKE_C_COMPILER_LAUNCHER "" CACHE STRING "C compiler launcher" FORCE)
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER "" CACHE STRING "C++ compiler launcher" FORCE)
|
||||
endif()
|
||||
|
||||
if(WIN32 AND SD_CUDA)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)
|
||||
set(CMAKE_VERBOSE_MAKEFILE OFF)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CUDA_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||
|
||||
# Disable response files and dependencies
|
||||
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS OFF CACHE BOOL "" FORCE)
|
||||
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES OFF CACHE BOOL "" FORCE)
|
||||
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES OFF CACHE BOOL "" FORCE)
|
||||
set(CMAKE_CUDA_DEPFILE_FORMAT "" CACHE STRING "" FORCE)
|
||||
set(CMAKE_CUDA_DEPENDS_USE_COMPILER OFF CACHE BOOL "" FORCE)
|
||||
|
||||
set(CMAKE_CUDA_COMPILE_OBJECT
|
||||
"<CMAKE_CUDA_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE> --compiler-options \"/bigobj /EHsc /MD /D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH\""
|
||||
CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if(SD_CUDA)
|
||||
project(libnd4j LANGUAGES C CXX CUDA)
|
||||
else()
|
||||
project(libnd4j LANGUAGES C CXX)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CUDA_STANDARD 17)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
|
||||
# Configure ccache for CUDA if available
|
||||
if(CCACHE_PROGRAM AND SD_CUDA AND CMAKE_CUDA_COMPILER)
|
||||
set(CMAKE_CUDA_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" CACHE STRING "CUDA compiler launcher" FORCE)
|
||||
message(STATUS "✅ Enabled ccache for CUDA compilation")
|
||||
|
||||
# Configure ccache settings for optimal performance
|
||||
execute_process(COMMAND ${CCACHE_PROGRAM} --max-size=10G ERROR_QUIET)
|
||||
execute_process(COMMAND ${CCACHE_PROGRAM} --set-config=compression=true ERROR_QUIET)
|
||||
execute_process(COMMAND ${CCACHE_PROGRAM} --set-config=compression_level=6 ERROR_QUIET)
|
||||
|
||||
# Show ccache statistics
|
||||
execute_process(
|
||||
COMMAND ${CCACHE_PROGRAM} --show-stats
|
||||
OUTPUT_VARIABLE CCACHE_STATS
|
||||
ERROR_QUIET
|
||||
)
|
||||
message(STATUS "📊 Ccache statistics:\n${CCACHE_STATS}")
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT SD_CUDA)
|
||||
if(NOT SD_CPU)
|
||||
set(SD_CUDA FALSE)
|
||||
set(SD_CPU TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SD_CUDA)
|
||||
set(DEFAULT_ENGINE "samediff::ENGINE_CUDA")
|
||||
add_compile_definitions(DEFAULT_ENGINE=samediff::ENGINE_CUDA)
|
||||
else()
|
||||
set(DEFAULT_ENGINE "samediff::ENGINE_CPU")
|
||||
add_compile_definitions(DEFAULT_ENGINE=samediff::ENGINE_CPU)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED SD_LIBRARY_NAME)
|
||||
if(SD_CUDA)
|
||||
set(SD_LIBRARY_NAME nd4jcuda)
|
||||
else()
|
||||
set(SD_LIBRARY_NAME nd4jcpu)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(PrintingUtilities)
|
||||
include(Options)
|
||||
include(PlatformDetection)
|
||||
include(TypeSystem)
|
||||
include(TypeCombinationEngine)
|
||||
include(TypeValidation)
|
||||
include(TypeProfiles)
|
||||
include(SemanticTypeFiltering)
|
||||
include(SelectiveRenderingIntegration)
|
||||
include(Dependencies)
|
||||
include(CompilerOptimizations)
|
||||
include(PlatformOptimizations)
|
||||
|
||||
LIBND4J_SETUP_TYPE_VALIDATION()
|
||||
|
||||
message(STATUS "=== TYPE SETUP VERIFICATION ===")
|
||||
if(DEFINED SD_TYPES_LIST AND SD_TYPES_LIST)
|
||||
message(STATUS "SD_TYPES_LIST: ${SD_TYPES_LIST}")
|
||||
list(LENGTH SD_TYPES_LIST type_count)
|
||||
message(STATUS "Type count: ${type_count}")
|
||||
else()
|
||||
message(STATUS "SD_TYPES_LIST: Not defined (ALL TYPES mode)")
|
||||
endif()
|
||||
|
||||
if(DEFINED SD_TYPES_LIST_COUNT)
|
||||
message(STATUS "SD_TYPES_LIST_COUNT: ${SD_TYPES_LIST_COUNT}")
|
||||
endif()
|
||||
|
||||
get_directory_property(COMPILE_DEFS COMPILE_DEFINITIONS)
|
||||
message(STATUS "Some compile definitions: ${COMPILE_DEFS}")
|
||||
message(STATUS "==============================")
|
||||
|
||||
# Include JNI configuration BEFORE MainBuildFlow so JVM_LIBRARY is available for linking
|
||||
include(cmake/JNIConfiguration.cmake)
|
||||
|
||||
include(cmake/MainBuildFlow.cmake)
|
||||
|
||||
if(SD_CUDA)
|
||||
include(cmake/CudaConfiguration.cmake)
|
||||
setup_cuda_build()
|
||||
else()
|
||||
setup_cpu_environment()
|
||||
endif()
|
||||
|
||||
if(WIN32 AND SD_CUDA)
|
||||
function(apply_cuda_target_fixes)
|
||||
get_property(all_targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
|
||||
foreach(target ${all_targets})
|
||||
if(TARGET ${target})
|
||||
get_target_property(target_type ${target} TYPE)
|
||||
if(target_type STREQUAL "OBJECT_LIBRARY" OR target_type STREQUAL "SHARED_LIBRARY")
|
||||
get_target_property(compile_options ${target} COMPILE_OPTIONS)
|
||||
if(compile_options)
|
||||
list(FILTER compile_options EXCLUDE REGEX "/FS")
|
||||
list(FILTER compile_options EXCLUDE REGEX "/Fd")
|
||||
set_target_properties(${target} PROPERTIES COMPILE_OPTIONS "${compile_options}")
|
||||
endif()
|
||||
set_property(TARGET ${target} PROPERTY CUDA_FLAGS "")
|
||||
set_target_properties(${target} PROPERTIES
|
||||
CUDA_RESOLVE_DEVICE_SYMBOLS ON
|
||||
CUDA_SEPARABLE_COMPILATION ON
|
||||
MSVC_RUNTIME_LIBRARY "MultiThreadedDLL"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
||||
apply_cuda_target_fixes()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET analyze_types)
|
||||
add_custom_target(analyze_types
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Analyzing type usage..."
|
||||
COMMENT "Analyzing type usage patterns in codebase"
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
add_custom_target(verify_types
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Verifying type configuration..."
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Check build logs above for type setup verification"
|
||||
COMMENT "Verify that type definitions are properly set"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
if(BUILD_PPSTEP)
|
||||
include(cmake/Ppstep.cmake)
|
||||
endif()
|
||||
@@ -0,0 +1,53 @@
|
||||
# --- Start of Arm Compute Library Build Section ---
|
||||
|
||||
# Find CMake for install commands and get CPU count
|
||||
find_package(CMake REQUIRED)
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(CPU_COUNT)
|
||||
if(NOT CPU_COUNT GREATER 0)
|
||||
set(CPU_COUNT 1)
|
||||
endif()
|
||||
|
||||
# Define installation path within the build directory
|
||||
set(ARMCOMPUTE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/armcompute-install")
|
||||
message(STATUS "Arm Compute Library install prefix: ${ARMCOMPUTE_INSTALL_PREFIX}")
|
||||
|
||||
ExternalProject_Add(armcompute
|
||||
GIT_REPOSITORY https://github.com/ARM-software/ComputeLibrary.git
|
||||
GIT_TAG v25.04 # Or specific commit hash
|
||||
SOURCE_DIR "${CMAKE_BINARY_DIR}/armcompute-src"
|
||||
BINARY_DIR "${CMAKE_BINARY_DIR}/armcompute-build"
|
||||
INSTALL_DIR ${ARMCOMPUTE_INSTALL_PREFIX}
|
||||
|
||||
# --- Build Configuration ---
|
||||
# Adjust SCons options like arch, neon, opencl as needed for linux-arm64
|
||||
# Ensure scons, python, arm64 compiler are in the PATH
|
||||
BUILD_COMMAND scons
|
||||
Werror=0 debug=0 neon=1 opencl=0 embed_kernels=1 cppthreads=1
|
||||
os=linux arch=arm64-v8a build=native -j${CPU_COUNT}
|
||||
|
||||
# --- Installation ---
|
||||
# Copy required headers and libraries to install prefix
|
||||
INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${ARMCOMPUTE_INSTALL_PREFIX}/lib &&
|
||||
${CMAKE_COMMAND} -E make_directory ${ARMCOMPUTE_INSTALL_PREFIX}/include &&
|
||||
${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/armcompute-src/include ${ARMCOMPUTE_INSTALL_PREFIX}/include &&
|
||||
${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/armcompute-build/libarm_compute.so ${ARMCOMPUTE_INSTALL_PREFIX}/lib/ &&
|
||||
${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/armcompute-build/libarm_compute_core.so ${ARMCOMPUTE_INSTALL_PREFIX}/lib/
|
||||
# Add other .so files (e.g., libarm_compute_graph.so) if needed
|
||||
|
||||
# --- Housekeeping ---
|
||||
CONFIGURE_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
|
||||
# --- Create Imported Target ---
|
||||
# Use this target in target_link_libraries() and add_dependencies()
|
||||
add_library(arm_compute INTERFACE IMPORTED GLOBAL)
|
||||
set_property(TARGET arm_compute PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${ARMCOMPUTE_INSTALL_PREFIX}/include")
|
||||
set_property(TARGET arm_compute PROPERTY INTERFACE_LINK_LIBRARIES
|
||||
"${ARMCOMPUTE_INSTALL_PREFIX}/lib/libarm_compute.so;${ARMCOMPUTE_INSTALL_PREFIX}/lib/libarm_compute_core.so") # Adjust list as needed
|
||||
# Ensure targets using this depend on 'armcompute'
|
||||
# Example: add_dependencies(your_javacpp_target armcompute)
|
||||
# Example: target_link_libraries(your_javacpp_target PRIVATE arm_compute)
|
||||
|
||||
# --- End of Arm Compute Library Build Section ---
|
||||
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
|
||||
project(cpu_features-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(cpu_features
|
||||
GIT_REPOSITORY https://github.com/google/cpu_features.git
|
||||
GIT_TAG v0.9.0
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/cpu_features-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/cpu_features-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
CMAKE_ARGS "-DBUILD_PIC=ON"
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
|
||||
project(flatbuffers-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(flatbuffers
|
||||
GIT_REPOSITORY https://github.com/google/flatbuffers/
|
||||
GIT_TAG v25.2.10
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build"
|
||||
# Add quotes around the compiler paths
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER}"
|
||||
-DCMAKE_C_COMPILER="${CMAKE_C_COMPILER}"
|
||||
-DFLATBUFFERS_BUILD_FLATC=${FLATBUFFERS_BUILD_FLATC}
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
UPDATE_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
|
||||
project(onednn-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(onednn
|
||||
GIT_REPOSITORY https://github.com/KonduitAI/oneDNN.git
|
||||
GIT_TAG master
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/onednn-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/onednn-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND "${CMAKE_COMMAND}" -E echo "OneDNN cloned to: ${CMAKE_CURRENT_BINARY_DIR}/onednn-src"
|
||||
INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "Listing onednn-src contents:" && "${CMAKE_COMMAND}" -E ls "${CMAKE_CURRENT_BINARY_DIR}/onednn-src"
|
||||
TEST_COMMAND ""
|
||||
LOG_DOWNLOAD ON
|
||||
LOG_UPDATE ON
|
||||
)
|
||||
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"version": 2,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "base_cpu_onednn",
|
||||
"displayName": "Configure preset for the base",
|
||||
"description": "Sets generator, build and install directory",
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/blasbuild/cpu",
|
||||
"cacheVariables": {
|
||||
"CMAKE_TOOLCHAIN_FILE": "",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
|
||||
"SD_LIBRARY_NAME": "nd4jcpu",
|
||||
"SD_CPU": true,
|
||||
"HELPERS_onednn": "ON",
|
||||
"GENERATE_FLATC": "ON",
|
||||
"SD_ARCH": "x86-64",
|
||||
"SD_GCC_FUNCTRACE": "OFF",
|
||||
"PRINT_MATH": "ON",
|
||||
"PRINT_INDICES": "ON",
|
||||
"SD_ALL_OPS": true,
|
||||
"CMAKE_BUILD_TYPE" : "Debug",
|
||||
"OPENBLAS_PATH": "$env{HOME}/.javacpp/cache/openblas-0.3.19-1.5.7-linux-x86_64.jar/org/bytedeco/openblas/linux-x86_64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "base_cpu",
|
||||
"displayName": "Configure preset for the base",
|
||||
"description": "Sets generator, build and install directory",
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/blasbuild/cpu",
|
||||
"cacheVariables": {
|
||||
"CMAKE_TOOLCHAIN_FILE": "",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
|
||||
"SD_LIBRARY_NAME": "nd4jcpu",
|
||||
"SD_CPU": true,
|
||||
"GENERATE_FLATC": "ON",
|
||||
"SD_ARCH": "x86-64",
|
||||
"SD_GCC_FUNCTRACE": "OFF",
|
||||
"PRINT_MATH": "ON",
|
||||
"PRINT_INDICES": "ON",
|
||||
"SD_ALL_OPS": true,
|
||||
"CMAKE_BUILD_TYPE" : "Debug",
|
||||
"OPENBLAS_PATH": "$env{HOME}/.javacpp/cache/openblas-0.3.19-1.5.7-linux-x86_64.jar/org/bytedeco/openblas/linux-x86_64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "base_cpu_tests",
|
||||
"displayName": "Configure preset for the base with tests",
|
||||
"description": "Sets generator, build and install directory",
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/blasbuild/cpu",
|
||||
"cacheVariables": {
|
||||
"CMAKE_TOOLCHAIN_FILE": "",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
|
||||
"SD_LIBRARY_NAME": "nd4jcpu",
|
||||
"SD_CPU": true,
|
||||
"SD_ARCH": "x86-64",
|
||||
"PRINT_INDICES": "ON",
|
||||
"SD_BUILD_TESTS": "OFF",
|
||||
"PRINT_MATH": "ON",
|
||||
"GENERATE_FLATC": "ON",
|
||||
"SD_ALL_OPS": true,
|
||||
"CMAKE_BUILD_TYPE" : "Debug",
|
||||
"OPENBLAS_PATH": "$env{HOME}/.javacpp/cache/openblas-0.3.19-1.5.7-linux-x86_64.jar/org/bytedeco/openblas/linux-x86_64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "base_cuda",
|
||||
"displayName": "Configure preset for the base Cuda",
|
||||
"description": "Sets generator, build and install directory",
|
||||
"hidden": true,
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/blasbuild/cuda",
|
||||
"cacheVariables": {
|
||||
"CMAKE_TOOLCHAIN_FILE": "",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
|
||||
"SD_LIBRARY_NAME": "nd4jcuda",
|
||||
"SD_ALL_OPS": true,
|
||||
"SD_CUDA": true,
|
||||
"BLAS":true,
|
||||
"CMAKE_BUILD_TYPE" : "Debug",
|
||||
"COMPUTE": "8.0",
|
||||
"__CUDACC__" : "ON",
|
||||
"SD_GCC_FUNCTRACE": "OFF",
|
||||
"CMAKE_CUDA_ARCHITECTURES": "86",
|
||||
"SD_BUILD_TESTS": "OFF",
|
||||
"GENERATE_FLATC": "ON",
|
||||
"CUDA_TOOLKIT_ROOT_DIR": "/usr/local/cuda",
|
||||
"CMAKE_CUDA_COMPILER": "/usr/local/cuda/bin/nvcc"
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"name": "base_cuda_tests",
|
||||
"displayName": "Configure preset for the base Cuda",
|
||||
"description": "Sets generator, build and install directory",
|
||||
"hidden": true,
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/blasbuild/cuda",
|
||||
"cacheVariables": {
|
||||
"CMAKE_TOOLCHAIN_FILE": "",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
|
||||
"SD_LIBRARY_NAME": "nd4jcuda",
|
||||
"SD_ALL_OPS": true,
|
||||
"SD_CUDA": true,
|
||||
"GENERATE_FLATC": "ON",
|
||||
"BLAS":true,
|
||||
"SD_GCC_FUNCTRACE": "OFF",
|
||||
"__CUDACC__" : "ON",
|
||||
"CMAKE_BUILD_TYPE" : "Debug",
|
||||
"COMPUTE": "86",
|
||||
"CUDA_TOOLKIT_ROOT_DIR": "/usr/local/cuda-12.1",
|
||||
"CMAKE_CUDA_COMPILER": "/usr/local/cuda-12.2/bin/nvcc"
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
"name": "cuda_cudnn",
|
||||
"displayName": "Configure preset for the CUDA and CUDNN",
|
||||
"description": "Sets Unix Makefile generator, build and install directory",
|
||||
"hidden": false,
|
||||
"inherits": [
|
||||
"base_cuda"
|
||||
],
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/blasbuild/cuda/${presetName}",
|
||||
"cacheVariables": {
|
||||
"SD_ARCH": "x86-64",
|
||||
"HELPERS_cudnn": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cuda_cudnn_debug",
|
||||
"displayName": "Configure Debug preset for the CUDA and CUDNN",
|
||||
"description": "Sets Unix Makefile generator, build and install directory",
|
||||
"hidden": false,
|
||||
"inherits": [
|
||||
"cuda_cudnn"
|
||||
],
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/blasbuild/cuda/${presetName}",
|
||||
"cacheVariables": {
|
||||
"SD_BUILD_TESTS": "OFF",
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "cpu_build",
|
||||
"description": "",
|
||||
"displayName": "",
|
||||
"configurePreset": "base_cpu",
|
||||
"jobs": 64
|
||||
},
|
||||
{
|
||||
"name": "cuda_cudnn_debug_build",
|
||||
"description": "",
|
||||
"displayName": "",
|
||||
"configurePreset": "cuda_cudnn_debug",
|
||||
"jobs": 64
|
||||
},
|
||||
{
|
||||
"name": "cpu_debug_test",
|
||||
"description": "",
|
||||
"displayName": "",
|
||||
"configurePreset": "cuda_cudnn_debug",
|
||||
"jobs": 64
|
||||
}
|
||||
],
|
||||
"testPresets": [
|
||||
{
|
||||
"name": "cuda_cudnn_debug_test",
|
||||
"description": "",
|
||||
"displayName": "",
|
||||
"configurePreset": "cuda_cudnn_debug"
|
||||
},
|
||||
{
|
||||
"name": "cpu_debug_test",
|
||||
"description": "",
|
||||
"displayName": "",
|
||||
"configurePreset": "base_cpu_tests"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x64_x64"
|
||||
],
|
||||
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"cmakeCommandArgs": " -DSD_CUDA=true -DSD_LIBRARY_NAME=nd4jcuda -DMSVC_DEV=true -DCOMPUTE=86 -DBUILD_TESTS=true",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x64-Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Release",
|
||||
"inheritEnvironments": [
|
||||
"msvc_x64_x64"
|
||||
],
|
||||
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"cmakeCommandArgs": " -DSD_CUDA=true -DSD_LIBRARY_NAME=nd4jcuda -DMSVC_DEV=true -DCOMPUTE=86 -DBUILD_TESTS=true",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "WSL-GCC-Debug",
|
||||
"generator": "Unix Makefiles",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeExecutable": "/usr/bin/cmake",
|
||||
"cmakeCommandArgs": "-DSD_ALL_OPS=true -DCMAKE_BUILD_TYPE=Debug -DSD_CPU=true -DLIBND4J_NAME=nd4jcpu -DBUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DOPENBLAS_PATH=/usr/lib/openblas-base/ -DEXTENSION=avx2 ",
|
||||
"buildCommandArgs": "-j 4",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "linux_x64" ],
|
||||
"wslPath": "${defaultWSLPath}",
|
||||
"addressSanitizerRuntimeFlags": "detect_leaks=0",
|
||||
"variables": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
# LibND4J
|
||||
|
||||
Native operations for nd4j. Build using cmake
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* GCC 4.9+
|
||||
* CUDA Toolkit Versions 10 or 11
|
||||
* CMake 3.8 (as of Nov 2017, in near future will require 3.9)
|
||||
|
||||
### Additional build arguments
|
||||
|
||||
There's few additional arguments for `buildnativeoperations.sh` script you could use:
|
||||
|
||||
```bash
|
||||
-a XXXXXXXX// shortcut for -march/-mtune, i.e. -a native
|
||||
-b release OR -b debug // enables/desables debug builds. release is considered by default
|
||||
-j XX // this argument defines how many threads will be used to binaries on your box. i.e. -j 8
|
||||
-cc XX// CUDA-only argument, builds only binaries for target GPU architecture. use this for fast builds
|
||||
--check-vectorization auto-vectorization report for developers. (Currently, only GCC is supported)
|
||||
```
|
||||
|
||||
[More about AutoVectorization report](auto_vectorization/AutoVectorization.md)
|
||||
|
||||
You can provide the compute capability for your card [on the NVIDIA website here](https://developer.nvidia.com/cuda-gpus) or use auto.
|
||||
Please also check your Cuda Toolkit Release notes for supported and dropped features.
|
||||
Here is [the latest CUDA Toolkit Release note](https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#deprecated-features).
|
||||
You can find the same information for the older Toolkit versions [in the CUDA archives](https://docs.nvidia.com/cuda/archive/).
|
||||
|
||||
|
||||
| -cc and --compute option examples | description |
|
||||
| -------- | -------- |
|
||||
|-cc all | builds for common GPUs|
|
||||
|-cc auto |tries to detect automatically |
|
||||
|-cc Maxwell | GPU microarchitecture codename |
|
||||
|-cc 75|compute capability 7.5 without a dot|
|
||||
|-cc 7.5|compute capability 7.5 with a dot|
|
||||
|-cc "Maxwell 6.0 7.5"| space-separated multiple arguments within quotes (note: numbers only with a dot)|
|
||||
|
||||
|
||||
## OS Specific Requirements
|
||||
|
||||
### Android
|
||||
|
||||
[Download the NDK](https://developer.android.com/ndk/downloads/), extract it somewhere, and execute the following commands, replacing `android-xxx` with either `android-arm` or `android-x86`:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/eclipse/deeplearning4j
|
||||
export ANDROID_NDK=/path/to/android-ndk/
|
||||
cd deeplearning4j/libnd4j
|
||||
bash buildnativeoperations.sh -platform android-xxx
|
||||
cd ../nd4j
|
||||
mvn clean install -Djavacpp.platform=android-xxx -DskipTests -pl '!:nd4j-cuda-9.0,!:nd4j-cuda-9.0-platform,!:nd4j-tests'
|
||||
```
|
||||
|
||||
### OSX
|
||||
|
||||
Run ./setuposx.sh (Please ensure you have brew installed)
|
||||
|
||||
See [macOSx10 CPU only.md](macOSx10%20%28CPU%20only%29.md)
|
||||
|
||||
|
||||
#### Ubuntu Linux 15.10
|
||||
|
||||
```bash
|
||||
wget http://developer.download.nvidia.com/compute/cuda/7.5/Prod/local_installers/cuda-repo-ubuntu1504-7-5-local_7.5-18_amd64.deb
|
||||
sudo dpkg -i cuda-repo-ubuntu1504-7-5-local_7.5-18_amd64.deb
|
||||
sudo apt-get update
|
||||
sudo apt-get install cuda
|
||||
sudo apt-get install cmake
|
||||
sudo apt-get install gcc-4.9
|
||||
sudo apt-get install g++-4.9
|
||||
sudo apt-get install git
|
||||
git clone https://github.com/deeplearning4j/libnd4j
|
||||
cd libnd4j/
|
||||
export LIBND4J_HOME=~/libnd4j/
|
||||
sudo rm /usr/bin/gcc
|
||||
sudo rm /usr/bin/g++
|
||||
sudo ln -s /usr/bin/gcc-4.9 /usr/bin/gcc
|
||||
sudo ln -s /usr/bin/g++-4.9 /usr/bin/g++
|
||||
./buildnativeoperations.sh
|
||||
./buildnativeoperations.sh -c cuda -сс YOUR_DEVICE_ARCH
|
||||
```
|
||||
#### Ubuntu Linux 16.04
|
||||
|
||||
```bash
|
||||
sudo apt install cmake
|
||||
sudo apt install nvidia-cuda-dev nvidia-cuda-toolkit nvidia-361
|
||||
export TRICK_NVCC=YES
|
||||
./buildnativeoperations.sh
|
||||
./buildnativeoperations.sh -c cuda -сс YOUR_DEVICE_ARCH
|
||||
|
||||
```
|
||||
|
||||
The standard development headers are needed.
|
||||
|
||||
#### CentOS 6
|
||||
|
||||
```bash
|
||||
yum install centos-release-scl-rh epel-release
|
||||
yum install devtoolset-3-toolchain maven30 cmake3 git
|
||||
scl enable devtoolset-3 maven30 bash
|
||||
./buildnativeoperations.sh
|
||||
./buildnativeoperations.sh -c cuda -сс YOUR_DEVICE_ARCH
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
See [Windows.md](windows.md)
|
||||
|
||||
## Setup for All OS
|
||||
|
||||
1. Set a LIBND4J_HOME as an environment variable to the libnd4j folder you've obtained from GIT
|
||||
* Note: this is required for building nd4j as well.
|
||||
|
||||
2. Setup cpu followed by gpu, run the following on the command line:
|
||||
* For standard builds:
|
||||
|
||||
```bash
|
||||
./buildnativeoperations.sh
|
||||
./buildnativeoperations.sh -c cuda -сс YOUR_DEVICE_ARCH
|
||||
```
|
||||
|
||||
* For Debug builds:
|
||||
|
||||
```bash
|
||||
./buildnativeoperations.sh blas -b debug
|
||||
./buildnativeoperations.sh blas -c cuda -сс YOUR_DEVICE_ARCH -b debug
|
||||
```
|
||||
|
||||
* For release builds (default):
|
||||
|
||||
```bash
|
||||
./buildnativeoperations.sh
|
||||
./buildnativeoperations.sh -c cuda -сс YOUR_DEVICE_ARCH
|
||||
```
|
||||
|
||||
## OpenMP support
|
||||
|
||||
OpenMP 4.0+ should be used to compile libnd4j. However, this shouldn't be any trouble, since OpenMP 4 was released in 2015 and should be available on all major platforms.
|
||||
|
||||
## Linking with MKL
|
||||
|
||||
We can link with MKL either at build time, or at runtime with binaries initially linked with another BLAS implementation such as OpenBLAS. In either case, simply add the path containing `libmkl_rt.so` (or `mkl_rt.dll` on Windows), say `/path/to/intel64/lib/`, to the `LD_LIBRARY_PATH` environment variable on Linux (or `PATH` on Windows), and build or run your Java application as usual. If you get an error message like `undefined symbol: omp_get_num_procs`, it probably means that `libiomp5.so`, `libiomp5.dylib`, or `libiomp5md.dll` is not present on your system. In that case though, it is still possible to use the GNU version of OpenMP by setting these environment variables on Linux, for example:
|
||||
|
||||
```bash
|
||||
export MKL_THREADING_LAYER=GNU
|
||||
export LD_PRELOAD=/usr/lib64/libgomp.so.1
|
||||
```
|
||||
|
||||
##Troubleshooting MKL
|
||||
|
||||
Sometimes the above steps might not be all you need to do. Another additional step might be the need to
|
||||
add:
|
||||
|
||||
```bash
|
||||
export LD_LIBRARY_PATH=/opt/intel/lib/intel64/:/opt/intel/mkl/lib/intel64
|
||||
```
|
||||
This ensures that mkl will be found first and liked to.
|
||||
|
||||
|
||||
## Packaging
|
||||
|
||||
If on Ubuntu (14.04 or above) or CentOS (6 or above), this repository is also
|
||||
set to create packages for your distribution. Let's assume you have built:
|
||||
|
||||
- for the cpu, your command-line was `./buildnativeoperations.sh ...`:
|
||||
|
||||
```bash
|
||||
cd blasbuild/cpu
|
||||
make package
|
||||
```
|
||||
|
||||
- for the gpu, your command-line was `./buildnativeoperations.sh -c cuda ...`:
|
||||
|
||||
```bash
|
||||
cd blasbuild/cuda
|
||||
make package
|
||||
```
|
||||
|
||||
|
||||
## Running tests
|
||||
|
||||
Tests are written with [gtest](https://github.com/google/googletest),
|
||||
run using cmake.
|
||||
Tests are currently under tests_cpu/
|
||||
|
||||
There are 2 directories for running tests:
|
||||
|
||||
1. libnd4j_tests: These are older legacy ops tests.
|
||||
2. layers_tests: This covers the newer graph operations and ops associated with samediff.
|
||||
|
||||
|
||||
For running the tests, we currently use cmake or CLion to run the tests.
|
||||
|
||||
To run tests using CUDA backend it's pretty much similar process:
|
||||
|
||||
1. ./buildnativeoperations.h -c cuda -cc <YOUR_ARCH> -b debug -t -j <NUMBER_OF_CORES>
|
||||
2. ./blasbuild/cuda/tests_cpu/layers_tests/runtests (.exe on Windows)
|
||||
|
||||
|
||||
## Development
|
||||
|
||||
In order to extend and update libnd4j, understanding libnd4j's various
|
||||
cmake flags is the key. Many of them are in buildnativeoperations.sh.
|
||||
The pom.xml is used to integrate and auto configure the project
|
||||
for building with deeplearning4j.
|
||||
|
||||
At a minimum, you will want to enable tests. An example default set of flags
|
||||
for running tests and getting cpu builds working is as follows:
|
||||
```bash
|
||||
-DSD_CPU=true -DBLAS=TRUE -DSD_ARCH=x86-64 -DSD_EXTENSION= -DSD_LIBRARY_NAME=nd4jcpu -DSD_CHECK_VECTORIZATION=OFF -DSD_SHARED_LIB=ON -DSD_STATIC_LIB=OFF -DSD_BUILD_MINIFIER=false -DSD_ALL_OPS=true -DCMAKE_BUILD_TYPE=Release -DPACKAGING=none -DSD_BUILD_TESTS=OFF -DCOMPUTE=all -DOPENBLAS_PATH=C:/Users/agibs/.javacpp/cache/openblas-0.3.10-1.5.4-windows-x86_64.jar/org/bytedeco/openblas/windows-x86_64 -DDEV=FALSE -DCMAKE_NEED_RESPONSE=YES -DMKL_MULTI_THREADED=TRUE -DSD_BUILD_TESTS=YES
|
||||
```
|
||||
|
||||
The way the main build script works, it dynamically generates a set of flags
|
||||
suitable for use for building the projects. Understanding the build script
|
||||
will go a long way in to configuring cmake for your particular IDE.
|
||||
|
||||
|
||||
## CMakeSettings.Presets.json overview
|
||||
|
||||
This document presents an overview of two key configuration files: `CMakeSettings.json` and `CMakePresets.json`, used in building the libnd4j C++ library.
|
||||
|
||||
### `CMakeSettings.json`
|
||||
|
||||
`CMakeSettings.json` provides project configurations for building the libnd4j C++ library with CMake in an IDE.
|
||||
|
||||
#### Configurations
|
||||
|
||||
- **x64-Debug and x64-Release**
|
||||
- Purpose: Building the project on a 64-bit system using the Ninja generator and specifically for Microsoft Visual Studio's 64-bit compiler (`msvc_x64_x64`).
|
||||
- CUDA: Enabled
|
||||
- Library name: `nd4jcuda`
|
||||
|
||||
- **WSL-GCC-Debug**
|
||||
- Purpose: Building the project using the GCC compiler on the Windows Subsystem for Linux (WSL).
|
||||
- All operations enabled: Yes (`-DSD_ALL_OPS=true`)
|
||||
- Library name: `nd4jcpu`
|
||||
- Additional: Utilizes OpenBLAS
|
||||
|
||||
### `CMakePresets.json`
|
||||
|
||||
`CMakePresets.json` defines presets for the configure, build, and test steps. Each preset can be selected based on the specific needs of the user.
|
||||
|
||||
#### Configure Presets
|
||||
|
||||
- **base_cpu and base_cpu_tests**: Presets for CPU builds, with optional tests.
|
||||
- **base_cuda and base_cuda_tests**: Presets for CUDA-enabled GPU builds.
|
||||
- **veda_vednn_base and veda_vednn_debug**: Presets for Veda architecture with optional debugging.
|
||||
- **cuda_cudnn and cuda_cudnn_debug**: Presets for CUDA-enabled builds with cuDNN, a GPU-accelerated library from NVIDIA for deep neural networks.
|
||||
|
||||
#### Build Presets
|
||||
|
||||
Presets for building the project after configuration, specifying the number of parallel jobs to run during the build process.
|
||||
|
||||
#### Test Presets
|
||||
|
||||
Presets for testing the project after building. They inherit the configuration from the configure presets, ensuring that the testing environment matches the build environment.
|
||||
@@ -0,0 +1,43 @@
|
||||
<!--
|
||||
~ /* ******************************************************************************
|
||||
~ *
|
||||
~ *
|
||||
~ * This program and the accompanying materials are made available under the
|
||||
~ * terms of the Apache License, Version 2.0 which is available at
|
||||
~ * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
~ *
|
||||
~ * See the NOTICE file distributed with this work for additional
|
||||
~ * information regarding copyright ownership.
|
||||
~ * Unless required by applicable law or agreed to in writing, software
|
||||
~ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
~ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
~ * License for the specific language governing permissions and limitations
|
||||
~ * under the License.
|
||||
~ *
|
||||
~ * SPDX-License-Identifier: Apache-2.0
|
||||
~ ******************************************************************************/
|
||||
-->
|
||||
|
||||
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
|
||||
<id>${libnd4j.platform}-cuda-${cuda.version}</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<baseDirectory>libnd4j</baseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/</directory>
|
||||
<outputDirectory/> <!-- DO NOT remove this tag, alternative way to specify cross platform root path is to provide ${file.separator} -->
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<excludes>
|
||||
<exclude>**/target/**</exclude>
|
||||
<exclude>**/CMakeFiles/**</exclude>
|
||||
<exclude>**/CMakeCache.txt</exclude>
|
||||
<exclude>%regex[(?!.*cuda/).*blasbuild.*]</exclude>
|
||||
<exclude>%regex[.*/lib/googletest.*]</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<!--
|
||||
~ /* ******************************************************************************
|
||||
~ *
|
||||
~ *
|
||||
~ * This program and the accompanying materials are made available under the
|
||||
~ * terms of the Apache License, Version 2.0 which is available at
|
||||
~ * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
~ *
|
||||
~ * See the NOTICE file distributed with this work for additional
|
||||
~ * information regarding copyright ownership.
|
||||
~ * Unless required by applicable law or agreed to in writing, software
|
||||
~ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
~ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
~ * License for the specific language governing permissions and limitations
|
||||
~ * under the License.
|
||||
~ *
|
||||
~ * SPDX-License-Identifier: Apache-2.0
|
||||
~ ******************************************************************************/
|
||||
-->
|
||||
|
||||
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
|
||||
<id>${libnd4j.classifier}</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<baseDirectory>libnd4j</baseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/</directory>
|
||||
<outputDirectory/> <!-- DO NOT remove this tag, alternative way to specify cross platform root path is to provide ${file.separator} -->
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<excludes>
|
||||
<exclude>**/target/**</exclude>
|
||||
<exclude>**/CMakeFiles/**</exclude>
|
||||
<exclude>**/CMakeCache.txt</exclude>
|
||||
<exclude>%regex[(?!.*${libnd4j.chip}/).*blasbuild.*]</exclude>
|
||||
<exclude>%regex[.*/lib/googletest.*]</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
|
||||
Executable
+1921
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
||||
# cmake/BuildCPU.cmake
|
||||
# Contains all logic for building the CPU library.
|
||||
|
||||
add_definitions(-D__CPUBLAS__=true)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
|
||||
|
||||
# --- Source File Collection ---
|
||||
file(GLOB_RECURSE BLAS_SOURCES ./include/blas/*.h )
|
||||
file(GLOB_RECURSE PERF_SOURCES ./include/performance/*.cpp ./include/performance/*.h)
|
||||
file(GLOB_RECURSE EXCEPTIONS_SOURCES ./include/exceptions/*.cpp ./include/exceptions/*.h)
|
||||
file(GLOB_RECURSE EXEC_SOURCES ./include/execution/*.cpp ./include/execution/*.h)
|
||||
file(GLOB_RECURSE TYPES_SOURCES ./include/types/*.cpp ./include/types/*.h)
|
||||
file(GLOB_RECURSE ARRAY_SOURCES ./include/array/*.cpp ./include/array/*.h)
|
||||
file(GLOB_RECURSE MEMORY_SOURCES ./include/memory/*.cpp ./include/memory/*.h)
|
||||
file(GLOB_RECURSE GRAPH_SOURCES ./include/graph/*.cpp ./include/graph/*.h)
|
||||
file(GLOB_RECURSE CUSTOMOPS_SOURCES ./include/ops/declarable/generic/*.cpp)
|
||||
file(GLOB_RECURSE CUSTOMOPS_HELPERS_IMPL_SOURCES ./include/ops/declarable/helpers/impl/*.cpp)
|
||||
file(GLOB_RECURSE CUSTOMOPS_HELPERS_CPU_SOURCES ./include/ops/declarable/helpers/cpu/*.cpp)
|
||||
file(GLOB_RECURSE OPS_SOURCES ./include/ops/impl/*.cpp ./include/ops/declarable/impl/*.cpp ./include/ops/*.h)
|
||||
file(GLOB_RECURSE INDEXING_SOURCES ./include/indexing/*.cpp ./include/indexing/*.h)
|
||||
file(GLOB_RECURSE HELPERS_SOURCES ./include/build_info.cpp ./include/ConstMessages.cpp ./include/helpers/*.cpp ./include/helpers/cpu/*.cpp ./include/helpers/*.h)
|
||||
file(GLOB_RECURSE LEGACY_SOURCES ./include/legacy/impl/*.cpp ./include/legacy/cpu/*.cpp ./include/legacy/*.h)
|
||||
file(GLOB_RECURSE LOOPS_SOURCES ./include/loops/*.cpp ./include/loops/*.h)
|
||||
|
||||
set(ALL_SOURCES "")
|
||||
set(STATIC_SOURCES_TO_CHECK ${BLAS_SOURCES} ${PERF_SOURCES} ${EXCEPTIONS_SOURCES} ${EXEC_SOURCES} ${TYPES_SOURCES} ${ARRAY_SOURCES} ${MEMORY_SOURCES} ${GRAPH_SOURCES} ${CUSTOMOPS_SOURCES} ${CUSTOMOPS_HELPERS_IMPL_SOURCES} ${CUSTOMOPS_HELPERS_CPU_SOURCES} ${OPS_SOURCES} ${INDEXING_SOURCES} ${HELPERS_SOURCES} ${LEGACY_SOURCES} ${LOOPS_SOURCES})
|
||||
|
||||
# Add PLT wrapper functions for functrace builds (GCC and Clang)
|
||||
# Required for --wrap=atexit and --wrap=at_quick_exit linker flags
|
||||
# These wrappers avoid PLT relocations in >2GB binaries
|
||||
if(SD_GCC_FUNCTRACE)
|
||||
list(APPEND STATIC_SOURCES_TO_CHECK ./include/platform/noplt_libc_stubs.c)
|
||||
message(STATUS "✅ Added noplt_libc_stubs.c for functrace build (provides __wrap_atexit and __wrap_at_quick_exit)")
|
||||
endif()
|
||||
|
||||
if(HAVE_ONEDNN)
|
||||
file(GLOB_RECURSE CUSTOMOPS_ONEDNN_SOURCES ./include/ops/declarable/platform/mkldnn/*.cpp ./include/ops/declarable/platform/mkldnn/mkldnnUtils.h)
|
||||
list(APPEND STATIC_SOURCES_TO_CHECK ${CUSTOMOPS_ONEDNN_SOURCES})
|
||||
endif()
|
||||
if(HAVE_ARMCOMPUTE)
|
||||
file(GLOB_RECURSE CUSTOMOPS_ARMCOMPUTE_SOURCES ./include/ops/declarable/platform/armcompute/*.cpp ./include/ops/declarable/platform/armcompute/*.h)
|
||||
list(APPEND STATIC_SOURCES_TO_CHECK ${CUSTOMOPS_ARMCOMPUTE_SOURCES})
|
||||
endif()
|
||||
|
||||
list(APPEND ALL_SOURCES ${STATIC_SOURCES_TO_CHECK})
|
||||
list(REMOVE_DUPLICATES ALL_SOURCES)
|
||||
|
||||
# --- Generate CPU Template Instantiations ---
|
||||
file(GLOB_RECURSE COMPILATION_UNITS
|
||||
./include/ops/impl/compilation_units/*.cpp.in
|
||||
./include/ops/declarable/helpers/cpu/compilation_units/*.cpp.in
|
||||
./include/loops/cpu/compilation_units/*.cpp.in
|
||||
./include/helpers/cpu/loops/*.cpp.in)
|
||||
|
||||
foreach(FL_ITEM ${COMPILATION_UNITS})
|
||||
genCompilation(${FL_ITEM})
|
||||
endforeach()
|
||||
|
||||
# --- Build Library ---
|
||||
set(OBJECT_LIB_NAME "${SD_LIBRARY_NAME}_object")
|
||||
add_library(${OBJECT_LIB_NAME} OBJECT ${ALL_SOURCES})
|
||||
add_dependencies(${OBJECT_LIB_NAME} flatbuffers_interface)
|
||||
target_include_directories(${OBJECT_LIB_NAME} PUBLIC ${EXTERNAL_INCLUDE_DIRS})
|
||||
set_property(TARGET ${OBJECT_LIB_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "${MSVC_RT_LIB}$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
add_library(${SD_LIBRARY_NAME} SHARED $<TARGET_OBJECTS:${OBJECT_LIB_NAME}>)
|
||||
set_target_properties(${SD_LIBRARY_NAME} PROPERTIES OUTPUT_NAME ${SD_LIBRARY_NAME})
|
||||
set_property(TARGET ${SD_LIBRARY_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "${MSVC_RT_LIB}$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
# --- Link Dependencies ---
|
||||
target_link_libraries(${SD_LIBRARY_NAME} PUBLIC
|
||||
${ONEDNN}
|
||||
${ARMCOMPUTE_LIBRARIES}
|
||||
${OPENBLAS_LIBRARIES}
|
||||
${BLAS_LIBRARIES}
|
||||
${JVM_LIBRARY}
|
||||
flatbuffers_interface
|
||||
)
|
||||
|
||||
# --- OpenMP Configuration ---
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
message(STATUS "OpenMP found, linking OpenMP::OpenMP_CXX")
|
||||
target_link_libraries(${SD_LIBRARY_NAME} PUBLIC OpenMP::OpenMP_CXX)
|
||||
else()
|
||||
message(WARNING "OpenMP not found, falling back to manual configuration")
|
||||
target_compile_options(${SD_LIBRARY_NAME} INTERFACE "-fopenmp")
|
||||
target_link_libraries(${SD_LIBRARY_NAME} PUBLIC "-fopenmp")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
# CombinationCaching.cmake
|
||||
# Smart type combination reuse and caching system
|
||||
|
||||
# Main function to handle combination reuse
|
||||
function(use_cached_type_combinations)
|
||||
# Check if combinations already exist in memory
|
||||
if(DEFINED COMBINATIONS_2 AND DEFINED COMBINATIONS_3)
|
||||
list(LENGTH COMBINATIONS_2 combo2_count)
|
||||
list(LENGTH COMBINATIONS_3 combo3_count)
|
||||
if(combo2_count GREATER 0 AND combo3_count GREATER 0)
|
||||
message(STATUS "♻️ Reusing existing combinations: 2-type=${combo2_count}, 3-type=${combo3_count}")
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Check for cached combinations file
|
||||
set(COMBO_CACHE_FILE "${CMAKE_BINARY_DIR}/type_combinations.cache")
|
||||
if(EXISTS "${COMBO_CACHE_FILE}")
|
||||
message(STATUS "📁 Loading combinations from cache file...")
|
||||
include("${COMBO_CACHE_FILE}")
|
||||
|
||||
# Verify cache loaded successfully
|
||||
if(DEFINED COMBINATIONS_2 AND DEFINED COMBINATIONS_3)
|
||||
list(LENGTH COMBINATIONS_2 combo2_count)
|
||||
list(LENGTH COMBINATIONS_3 combo3_count)
|
||||
message(STATUS "✅ Loaded from cache: 2-type=${combo2_count}, 3-type=${combo3_count}")
|
||||
return()
|
||||
else()
|
||||
message(STATUS "⚠️ Cache file corrupted, regenerating...")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Only generate if we absolutely have to
|
||||
message(STATUS "🔄 Generating type combinations (first time only)...")
|
||||
|
||||
# Ensure type system is initialized
|
||||
if(NOT DEFINED SD_COMMON_TYPES_COUNT OR SD_COMMON_TYPES_COUNT EQUAL 0)
|
||||
validate_and_process_types_failfast()
|
||||
build_indexed_type_lists()
|
||||
endif()
|
||||
|
||||
initialize_dynamic_combinations()
|
||||
|
||||
# Verify combinations were created
|
||||
if(DEFINED COMBINATIONS_2 AND DEFINED COMBINATIONS_3)
|
||||
list(LENGTH COMBINATIONS_2 combo2_count)
|
||||
list(LENGTH COMBINATIONS_3 combo3_count)
|
||||
message(STATUS "✅ Generated combinations: 2-type=${combo2_count}, 3-type=${combo3_count}")
|
||||
|
||||
# Cache for future use
|
||||
save_combinations_to_cache("${COMBO_CACHE_FILE}")
|
||||
else()
|
||||
message(FATAL_ERROR "❌ Failed to generate type combinations!")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Save combinations to cache file
|
||||
function(save_combinations_to_cache cache_file)
|
||||
message(STATUS "💾 Saving combinations to cache...")
|
||||
|
||||
set(cache_content "# Generated type combinations cache\n")
|
||||
string(APPEND cache_content "# Generated on: ${CMAKE_CURRENT_TIMESTAMP}\n\n")
|
||||
|
||||
# Save 2-type combinations
|
||||
string(APPEND cache_content "set(COMBINATIONS_2 \"")
|
||||
foreach(combo ${COMBINATIONS_2})
|
||||
string(APPEND cache_content "${combo};")
|
||||
endforeach()
|
||||
string(APPEND cache_content "\" CACHE INTERNAL \"2-type combinations\")\n\n")
|
||||
|
||||
# Save 3-type combinations
|
||||
string(APPEND cache_content "set(COMBINATIONS_3 \"")
|
||||
foreach(combo ${COMBINATIONS_3})
|
||||
string(APPEND cache_content "${combo};")
|
||||
endforeach()
|
||||
string(APPEND cache_content "\" CACHE INTERNAL \"3-type combinations\")\n\n")
|
||||
|
||||
# Save metadata
|
||||
string(APPEND cache_content "set(COMBINATIONS_CACHE_TIMESTAMP \"${CMAKE_CURRENT_TIMESTAMP}\" CACHE INTERNAL \"Cache timestamp\")\n")
|
||||
string(APPEND cache_content "set(COMBINATIONS_CACHE_VALID TRUE CACHE INTERNAL \"Cache validity flag\")\n")
|
||||
|
||||
file(WRITE "${cache_file}" "${cache_content}")
|
||||
message(STATUS "💾 Combinations cached to: ${cache_file}")
|
||||
endfunction()
|
||||
|
||||
# Generate reusable combination strings once
|
||||
function(generate_combination_strings_once)
|
||||
if(DEFINED GLOBAL_COMB2_STRING AND DEFINED GLOBAL_COMB3_STRING)
|
||||
message(STATUS "♻️ Reusing existing combination strings")
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "🔧 Generating combination strings...")
|
||||
|
||||
# Generate 2-type combination string
|
||||
set(COMB2_STRING "")
|
||||
foreach(combination ${COMBINATIONS_2})
|
||||
string(REPLACE "," ";" combo_parts "${combination}")
|
||||
list(GET combo_parts 0 t1)
|
||||
list(GET combo_parts 1 t2)
|
||||
string(APPEND COMB2_STRING "INSTANTIATE_2(${t1}, ${t2})")
|
||||
endforeach()
|
||||
|
||||
# Generate 3-type combination string
|
||||
set(COMB3_STRING "")
|
||||
foreach(combination ${COMBINATIONS_3})
|
||||
string(REPLACE "," ";" combo_parts "${combination}")
|
||||
list(GET combo_parts 0 t1)
|
||||
list(GET combo_parts 1 t2)
|
||||
list(GET combo_parts 2 t3)
|
||||
string(APPEND COMB3_STRING "INSTANTIATE_3(${t1}, ${t2}, ${t3}); ")
|
||||
endforeach()
|
||||
|
||||
# Cache globally for reuse
|
||||
set(GLOBAL_COMB2_STRING "${COMB2_STRING}" CACHE INTERNAL "Global 2-type combination string")
|
||||
set(GLOBAL_COMB3_STRING "${COMB3_STRING}" CACHE INTERNAL "Global 3-type combination string")
|
||||
|
||||
list(LENGTH COMBINATIONS_2 combo2_count)
|
||||
list(LENGTH COMBINATIONS_3 combo3_count)
|
||||
message(STATUS "✅ Generated strings: 2-type=${combo2_count} instantiations, 3-type=${combo3_count} instantiations")
|
||||
endfunction()
|
||||
|
||||
# Clear cache if needed (for development)
|
||||
function(clear_combination_cache)
|
||||
set(COMBO_CACHE_FILE "${CMAKE_BINARY_DIR}/type_combinations.cache")
|
||||
if(EXISTS "${COMBO_CACHE_FILE}")
|
||||
file(REMOVE "${COMBO_CACHE_FILE}")
|
||||
message(STATUS "🗑️ Cleared combination cache")
|
||||
endif()
|
||||
|
||||
# Clear memory cache
|
||||
unset(COMBINATIONS_2 CACHE)
|
||||
unset(COMBINATIONS_3 CACHE)
|
||||
unset(GLOBAL_COMB2_STRING CACHE)
|
||||
unset(GLOBAL_COMB3_STRING CACHE)
|
||||
unset(COMBINATIONS_CACHE_VALID CACHE)
|
||||
endfunction()
|
||||
|
||||
# Validate cache integrity
|
||||
function(validate_combination_cache)
|
||||
if(NOT DEFINED COMBINATIONS_CACHE_VALID OR NOT COMBINATIONS_CACHE_VALID)
|
||||
message(STATUS "⚠️ Combination cache is invalid, will regenerate")
|
||||
clear_combination_cache()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Check if combinations are reasonable
|
||||
if(DEFINED COMBINATIONS_2 AND DEFINED COMBINATIONS_3)
|
||||
list(LENGTH COMBINATIONS_2 combo2_count)
|
||||
list(LENGTH COMBINATIONS_3 combo3_count)
|
||||
|
||||
if(combo2_count LESS 10 OR combo3_count LESS 10)
|
||||
message(STATUS "⚠️ Combination counts seem too low, will regenerate")
|
||||
clear_combination_cache()
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "✅ Cache validation passed")
|
||||
else()
|
||||
message(STATUS "⚠️ Combinations not found in cache, will regenerate")
|
||||
clear_combination_cache()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Main setup function
|
||||
function(setup_smart_combination_reuse)
|
||||
message(STATUS "=== SETTING UP SMART COMBINATION REUSE ===")
|
||||
|
||||
# Validate existing cache
|
||||
validate_combination_cache()
|
||||
|
||||
# Use cached combinations without regeneration
|
||||
use_cached_type_combinations()
|
||||
|
||||
# Create combination strings once, reuse everywhere
|
||||
generate_combination_strings_once()
|
||||
|
||||
message(STATUS "✅ Smart combination reuse setup complete")
|
||||
endfunction()
|
||||
@@ -0,0 +1,689 @@
|
||||
# cmake/CompilerFlags.cmake
|
||||
# Configures compiler and linker flags for optimization and correctness.
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# When sanitizers or lifecycle tracking are enabled, we use large code model which can cause PLT overflow
|
||||
# Skip -fno-plt for these builds to avoid "PC-relative offset overflow" linker errors
|
||||
if(NOT ((DEFINED SD_SANITIZERS AND NOT SD_SANITIZERS STREQUAL "") OR SD_GCC_FUNCTRACE))
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-plt")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-plt")
|
||||
else()
|
||||
if(DEFINED SD_SANITIZERS AND NOT SD_SANITIZERS STREQUAL "")
|
||||
message(STATUS "Skipping -fno-plt for sanitizer build (incompatible with large code model)")
|
||||
elseif(SD_GCC_FUNCTRACE)
|
||||
message(STATUS "Skipping -fno-plt for lifecycle tracking build (incompatible with large code model)")
|
||||
endif()
|
||||
endif()
|
||||
#This is to avoid jemalloc crashes where c++ uses sized deallocations
|
||||
add_compile_options(-fno-sized-deallocation)
|
||||
|
||||
# JavaCPP loads our library via dlopen() at runtime, not at program startup
|
||||
# Libraries loaded via dlopen() with static TLS (initial-exec model) can exhaust the static TLS block
|
||||
# Solution: Force global-dynamic TLS model for ALL thread-local storage
|
||||
# - global-dynamic: Uses __tls_get_addr() for dynamic TLS allocation at runtime
|
||||
# - Works with dlopen() because TLS is allocated dynamically, not from static block
|
||||
# - Slightly slower than initial-exec, but required for dlopen() compatibility
|
||||
# Also disable thread-safe static initialization guards which use TLS internally
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftls-model=global-dynamic -fno-threadsafe-statics")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftls-model=global-dynamic")
|
||||
|
||||
# ADDITIONAL FIX: Use GNU2 TLS dialect (TLSDESC) for better dlopen() support
|
||||
# Traditional TLS implementation (gnu dialect) has limitations with libraries loaded via dlopen()
|
||||
# GNU2 dialect uses TLS descriptors which are specifically designed for dynamic loading
|
||||
# - Reduces TLS block fragmentation
|
||||
# - More efficient for libraries loaded at runtime
|
||||
# - Better handles libraries with many TLS variables
|
||||
# This is a DIFFERENT approach from session #310's global-dynamic alone
|
||||
# Supported on x86-64 by both GCC and Clang (requires glibc 2.10+, widely available)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtls-dialect=gnu2")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mtls-dialect=gnu2")
|
||||
message(STATUS "Applied GNU2 TLS dialect (TLSDESC) for improved dlopen() compatibility")
|
||||
endif()
|
||||
|
||||
message(STATUS "Applied global-dynamic TLS model for dlopen() compatibility (JavaCPP requirement)")
|
||||
endif()
|
||||
|
||||
|
||||
# Template depth limits - standardized based on build type
|
||||
# Release builds: 512 (sufficient for production, faster compilation)
|
||||
# Debug builds: 1024 (deeper nesting for development)
|
||||
|
||||
# GCC-specific error limiting
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
add_compile_options(-fmax-errors=3) # Stop on first few errors
|
||||
endif()
|
||||
|
||||
# Clang-specific workarounds for source location limits
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# Work around Clang's source location limit with heavily templated code
|
||||
add_compile_options(-Wno-error)
|
||||
add_compile_options(-ferror-limit=0)
|
||||
# Reduce macro expansion tracking overhead
|
||||
add_compile_options(-fmacro-backtrace-limit=0)
|
||||
# Reduce template error backtrace noise
|
||||
add_compile_options(-ftemplate-backtrace-limit=10)
|
||||
|
||||
# Aggressive Clang 20 memory optimizations for functrace ONLY
|
||||
if(SD_GCC_FUNCTRACE)
|
||||
message(STATUS "⚡ Applying Clang 20 memory optimizations for functrace build ONLY")
|
||||
|
||||
# Disable PCH validation (saves memory)
|
||||
add_compile_options(-Xclang -fno-validate-pch)
|
||||
|
||||
# Reduce template instantiation depth
|
||||
add_compile_options(-ftemplate-depth=512)
|
||||
|
||||
# Clang 20 specific: Reduce memory during code generation
|
||||
add_compile_options(-Xclang -mllvm -Xclang -inline-threshold=50)
|
||||
|
||||
# Reduce DWARF debug info overhead (keep line tables only)
|
||||
add_compile_options(-fdebug-info-for-profiling)
|
||||
|
||||
# These flags don't exist: -hot-cold-split, -reduce-array-computations, -enable-loop-distribute
|
||||
|
||||
# Disable expensive optimizations during compilation to save memory
|
||||
add_compile_options(-fno-slp-vectorize)
|
||||
add_compile_options(-fno-vectorize)
|
||||
|
||||
message(STATUS " - Disabled PCH validation")
|
||||
message(STATUS " - Template depth: 512")
|
||||
message(STATUS " - Reduced inline threshold for memory")
|
||||
message(STATUS " - Debug info optimized for profiling")
|
||||
message(STATUS " - Vectorization disabled (saves memory)")
|
||||
endif()
|
||||
|
||||
# Use newer source manager if available (Clang 15+)
|
||||
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "15.0")
|
||||
message(STATUS "Clang 15+ detected, using optimizations for large translation units")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
# --- Link Time Optimization (LTO) ---
|
||||
if(SD_USE_LTO)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||
message(STATUS "Using Link Time Optimization")
|
||||
add_compile_options(-flto)
|
||||
add_link_options(-flto)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- Memory Model for large binaries ---
|
||||
# CRITICAL: -mcmodel=large is INCOMPATIBLE with system CRT libraries (crtbeginS.o, crti.o)
|
||||
# System libraries are compiled with -mcmodel=small and cannot be linked into -mcmodel=large binaries
|
||||
# This causes "relocation truncated to fit: R_X86_64_PC32" errors (see session #959, #1008)
|
||||
# SOLUTION: Use -mcmodel=medium for both sanitizers AND functrace builds
|
||||
# Medium model: Code can be anywhere, data/GOT in lowest 2GB (compatible with system libraries)
|
||||
if(SD_X86_BUILD AND NOT WIN32)
|
||||
if(SD_SANITIZE OR SD_GCC_FUNCTRACE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcmodel=medium -fPIC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcmodel=medium")
|
||||
if(SD_SANITIZE)
|
||||
message(STATUS "Applied medium memory model for x86-64 architecture (sanitizers enabled)")
|
||||
elseif(SD_GCC_FUNCTRACE)
|
||||
message(STATUS "Applied medium memory model for x86-64 architecture (lifecycle tracking enabled)")
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcmodel=medium -fPIC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcmodel=medium")
|
||||
message(STATUS "Applied medium memory model for x86-64 architecture")
|
||||
endif()
|
||||
else()
|
||||
if(SD_ARM_BUILD OR SD_ANDROID_BUILD)
|
||||
message(STATUS "Skipping large memory model for ARM/Android architecture (not supported)")
|
||||
elseif(WIN32)
|
||||
message(STATUS "Skipping large memory model for Windows (using alternative approach)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- Section splitting for better linker handling ---
|
||||
# Note: Memory optimization params (ggc-min-*) are set below in GCC-specific section to avoid duplicates
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
|
||||
|
||||
# MEMORY OPTIMIZATION: Additional flags for functrace ONLY to reduce memory
|
||||
if(SD_GCC_FUNCTRACE)
|
||||
# Merge identical constants to reduce object file size
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmerge-all-constants")
|
||||
|
||||
# Use non-unique section names (reduces ELF section overhead) - Clang only
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unique-section-names")
|
||||
# Don't keep full AST in memory during code generation
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Xclang -discard-value-names")
|
||||
endif()
|
||||
|
||||
message(STATUS "⚡ Applied memory-reduction compiler flags for functrace ONLY:")
|
||||
message(STATUS " - fmerge-all-constants (reduce duplication)")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
message(STATUS " - fno-unique-section-names (reduce ELF overhead, Clang only)")
|
||||
message(STATUS " - discard-value-names (reduce AST retention)")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- Allow duplicate instantiations for template folding ---
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
# GCC: Use -fpermissive to allow duplicate instantiations
|
||||
add_compile_options(-fpermissive)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# Clang: Suppress all warnings and errors for template instantiation issues
|
||||
add_compile_options(-w)
|
||||
add_compile_options(-Wno-error)
|
||||
add_compile_options(-Wno-everything)
|
||||
message(STATUS "✅ Clang: Enabled template folding with all warnings suppressed and dead strip")
|
||||
endif()
|
||||
|
||||
# --- MSVC-specific optimizations ---
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
add_compile_options(/Gy) # Function-level linking
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /OPT:REF /OPT:ICF")
|
||||
add_compile_options(/bigobj /EHsc /Zc:preprocessor)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
endif()
|
||||
|
||||
# --- Windows Specific Configurations ---
|
||||
if(WIN32 AND NOT ANDROID)
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj")
|
||||
endif()
|
||||
set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS ON)
|
||||
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS ON)
|
||||
set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@")
|
||||
set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@")
|
||||
set(CMAKE_NINJA_FORCE_RESPONSE_FILE ON CACHE INTERNAL "")
|
||||
endif()
|
||||
|
||||
# --- GCC/Clang Specific Flags ---
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT SD_CUDA)
|
||||
message(STATUS "Adding GCC memory optimization flags: --param ggc-min-expand=100 --param ggc-min-heapsize=131072")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --param ggc-min-expand=100 --param ggc-min-heapsize=131072 ${INFORMATIVE_FLAGS} -std=c++17 -fPIC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --param ggc-min-expand=100 --param ggc-min-heapsize=131072 -fPIC")
|
||||
if(UNIX)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath,$ORIGIN/,--no-undefined,--verbose")
|
||||
else()
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath,$ORIGIN/,--no-undefined,--verbose")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- Build Type Specific Flags ---
|
||||
if(SD_ANDROID_BUILD)
|
||||
# ... flags for android ...
|
||||
elseif(APPLE)
|
||||
# ... flags for apple ...
|
||||
elseif(WIN32)
|
||||
# ... flags for windows ...
|
||||
else() # Generic Linux/Unix
|
||||
if("${SD_GCC_FUNCTRACE}" STREQUAL "ON")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O${SD_OPTIMIZATION_LEVEL} -fPIC -g")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O${SD_OPTIMIZATION_LEVEL} -fPIC -D_RELEASE=true")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS_DEBUG " -g -O${SD_OPTIMIZATION_LEVEL} -fPIC")
|
||||
endif()
|
||||
|
||||
# --- Sanitizer Configuration ---
|
||||
# In CompilerFlags.cmake, change the sanitizer section:
|
||||
# --- Sanitizer Configuration ---
|
||||
if(SD_SANITIZE)
|
||||
# For large binaries with MSan: must use large code model
|
||||
# Use LLD linker for better memory handling (gold OOMs on 23GB+ builds)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# MEMORY OPTIMIZATION: Use -gline-tables-only instead of full debug info (Clang-specific)
|
||||
# This reduces memory by 40-60% for template-heavy code while maintaining stack traces
|
||||
set(SANITIZE_FLAGS " -fPIC -fsanitize=${SD_SANITIZERS} -fno-sanitize-recover=all -fuse-ld=gold -gline-tables-only")
|
||||
|
||||
# MemorySanitizer-specific: Use ignorelist to skip instrumentation of external libraries
|
||||
if(SD_SANITIZERS MATCHES "memory")
|
||||
set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fsanitize-ignorelist=${CMAKE_CURRENT_SOURCE_DIR}/msan_ignorelist.txt")
|
||||
|
||||
# Disable origin tracking to reduce MSan's static TLS usage
|
||||
# - Origin tracking uses significant TLS to track uninitialized memory sources
|
||||
# - With dlopen() (JavaCPP's loading method), static TLS space is limited
|
||||
# - Disabling origin tracking keeps MSan functional but reduces TLS footprint
|
||||
# - MSan will still detect uninitialized memory, just without origin traces
|
||||
set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fsanitize-memory-track-origins=0")
|
||||
|
||||
# - Dynamic linking: libnd4jcpu.so depends on libclang_rt.msan.so (separate .so with static TLS)
|
||||
# - Static linking: MSan runtime code embedded in libnd4jcpu.so (TLS becomes part of our library)
|
||||
# - Combined with global-dynamic TLS model, this eliminates static TLS block exhaustion
|
||||
# - Static linking is safe here because we only have ONE library using MSan (no multi-library conflicts)
|
||||
set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -static-libsan")
|
||||
|
||||
message(STATUS "Applied MemorySanitizer ignorelist for external libraries")
|
||||
message(STATUS "Disabled MSan origin tracking to reduce TLS usage for dlopen() compatibility")
|
||||
message(STATUS "Enabled static MSan runtime linking to eliminate separate TLS allocation")
|
||||
endif()
|
||||
|
||||
# Explicitly force global-dynamic TLS model for dlopen() compatibility
|
||||
# - global-dynamic: Uses __tls_get_addr() for dynamic TLS allocation
|
||||
# - Works with libraries loaded via dlopen() (JavaCPP's method)
|
||||
# - Avoids static TLS block exhaustion
|
||||
# ALSO disable thread-safe statics to prevent __tls_guard from using initial-exec TLS
|
||||
# Thread-safe static initialization uses internal TLS that doesn't respect -ftls-model flag
|
||||
set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -ftls-model=global-dynamic -fno-threadsafe-statics")
|
||||
|
||||
# Additional memory optimizations for template-heavy instantiation files
|
||||
set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fmerge-all-constants")
|
||||
set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fno-unique-section-names") # Clang-specific
|
||||
|
||||
message(STATUS "Applied memory-optimized sanitizer flags (-gline-tables-only, Clang-specific)")
|
||||
else()
|
||||
set(SANITIZE_FLAGS " -Wall -Wextra -fPIC -fsanitize=${SD_SANITIZERS} -fno-sanitize-recover=all")
|
||||
endif()
|
||||
# Gold linker + sanitizers: Must explicitly pass -fsanitize to linker
|
||||
# The -fsanitize flag tells clang driver to link the sanitizer runtime
|
||||
# Gold linker handles MSan's TLS correctly for shared libraries (LLD has issues)
|
||||
set(SANITIZE_LINK_FLAGS "-fsanitize=${SD_SANITIZERS} -fuse-ld=gold")
|
||||
|
||||
# Without this, linker uses wrong relocation types → "relocation truncated to fit" errors
|
||||
if(SD_X86_BUILD AND NOT WIN32)
|
||||
if(DEFINED SD_SANITIZERS AND NOT SD_SANITIZERS STREQUAL "")
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -mcmodel=large")
|
||||
message(STATUS "Applied large code model to linker flags (matches compiler -mcmodel=large)")
|
||||
else()
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -mcmodel=medium")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Linker memory optimizations for large template-heavy builds
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# Detect which linker is being used
|
||||
set(DETECTED_LINKER "unknown")
|
||||
if(SANITIZE_LINK_FLAGS MATCHES "-fuse-ld=gold")
|
||||
set(DETECTED_LINKER "gold")
|
||||
elseif(SANITIZE_LINK_FLAGS MATCHES "-fuse-ld=lld")
|
||||
set(DETECTED_LINKER "lld")
|
||||
elseif(SANITIZE_LINK_FLAGS MATCHES "-fuse-ld=bfd")
|
||||
set(DETECTED_LINKER "bfd")
|
||||
else()
|
||||
# Try to detect from compiler default
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -Wl,--version
|
||||
OUTPUT_VARIABLE LINKER_VERSION_OUTPUT
|
||||
ERROR_VARIABLE LINKER_VERSION_OUTPUT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(LINKER_VERSION_OUTPUT MATCHES "GNU gold")
|
||||
set(DETECTED_LINKER "gold")
|
||||
elseif(LINKER_VERSION_OUTPUT MATCHES "LLD")
|
||||
set(DETECTED_LINKER "lld")
|
||||
elseif(LINKER_VERSION_OUTPUT MATCHES "GNU ld")
|
||||
set(DETECTED_LINKER "bfd")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Detected linker: ${DETECTED_LINKER}")
|
||||
|
||||
# Apply linker-specific memory optimizations
|
||||
if(DETECTED_LINKER STREQUAL "gold")
|
||||
# GNU gold linker flags
|
||||
# Memory sanitizer needs reduced caching to avoid OOM, but leak sanitizer benefits from caching
|
||||
if(SD_SANITIZERS MATCHES "memory")
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -Wl,--no-keep-memory")
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -Wl,--no-map-whole-files")
|
||||
endif()
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -Wl,--icf=safe")
|
||||
|
||||
# Gold uses its own internal hash table optimization that cannot be configured
|
||||
|
||||
# Gold by default is single-threaded. Multi-threading speeds up linking 2-4x
|
||||
# and can reduce peak memory by spreading work across time
|
||||
cmake_host_system_information(RESULT NUM_CORES QUERY NUMBER_OF_PHYSICAL_CORES)
|
||||
math(EXPR LINKER_THREADS "${NUM_CORES} / 2") # Use half of cores for linking
|
||||
if(LINKER_THREADS LESS 2)
|
||||
set(LINKER_THREADS 2)
|
||||
endif()
|
||||
if(LINKER_THREADS GREATER 8)
|
||||
set(LINKER_THREADS 8) # Cap at 8 threads (gold's sweet spot)
|
||||
endif()
|
||||
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -Wl,--threads")
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -Wl,--thread-count,${LINKER_THREADS}")
|
||||
|
||||
message(STATUS "Applied GNU gold linker optimizations:")
|
||||
if(SD_SANITIZERS MATCHES "memory")
|
||||
message(STATUS " - --no-keep-memory: Don't cache file contents (MemorySanitizer only)")
|
||||
message(STATUS " - --no-map-whole-files: Map only needed file parts (MemorySanitizer only)")
|
||||
else()
|
||||
message(STATUS " - Using default caching (better for leak/address sanitizers)")
|
||||
endif()
|
||||
message(STATUS " - --icf=safe: Fold identical code sections")
|
||||
message(STATUS " - --threads: Enable parallel linking with ${LINKER_THREADS} threads")
|
||||
message(STATUS " Note: Gold linker manages hash table size internally (not configurable)")
|
||||
|
||||
elseif(DETECTED_LINKER STREQUAL "lld")
|
||||
# LLVM lld linker flags (different syntax than gold)
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -Wl,--icf=all")
|
||||
|
||||
# For very large builds (23GB+ object files), reduce memory usage
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -Wl,--gc-sections")
|
||||
|
||||
# LLD has built-in threading, configure job count
|
||||
cmake_host_system_information(RESULT NUM_CORES QUERY NUMBER_OF_PHYSICAL_CORES)
|
||||
math(EXPR LINKER_THREADS "${NUM_CORES} / 2")
|
||||
if(LINKER_THREADS LESS 2)
|
||||
set(LINKER_THREADS 2)
|
||||
endif()
|
||||
if(LINKER_THREADS GREATER 16)
|
||||
set(LINKER_THREADS 16) # LLD scales better than gold
|
||||
endif()
|
||||
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -Wl,--threads=${LINKER_THREADS}")
|
||||
|
||||
message(STATUS "Applied LLVM lld linker memory optimizations:")
|
||||
message(STATUS " - --icf=all: Aggressive identical code folding")
|
||||
message(STATUS " - --gc-sections: Remove unused code sections")
|
||||
message(STATUS " - --threads=${LINKER_THREADS}: Enable parallel linking")
|
||||
message(STATUS " Note: LLD handles large builds (23GB+) better than gold")
|
||||
|
||||
elseif(DETECTED_LINKER STREQUAL "bfd")
|
||||
# GNU ld (bfd) - older linker with limited optimization support
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -Wl,--no-keep-memory")
|
||||
# BFD doesn't support threading or advanced ICF
|
||||
|
||||
message(STATUS "Applied GNU ld (bfd) linker memory optimizations:")
|
||||
message(STATUS " - --no-keep-memory: Don't cache file contents in memory")
|
||||
message(WARNING "GNU ld (bfd) is single-threaded and slower than gold/lld. Consider using gold or lld for faster builds.")
|
||||
|
||||
else()
|
||||
message(WARNING "Unknown linker detected. Skipping linker-specific optimizations.")
|
||||
message(STATUS "To specify linker explicitly, use: -DCMAKE_CXX_FLAGS=\"-fuse-ld=gold\" (or lld/bfd)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# For Homebrew clang or custom LLVM, also add explicit runtime library path
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -print-resource-dir
|
||||
OUTPUT_VARIABLE CLANG_RESOURCE_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# Determine OS-specific lib subdirectory
|
||||
if(APPLE)
|
||||
set(SANITIZER_LIB_SUBDIR "darwin")
|
||||
elseif(WIN32)
|
||||
set(SANITIZER_LIB_SUBDIR "windows")
|
||||
else()
|
||||
set(SANITIZER_LIB_SUBDIR "linux")
|
||||
endif()
|
||||
|
||||
# Determine architecture for sanitizer library names
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64")
|
||||
set(SANITIZER_ARCH "x86_64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64")
|
||||
set(SANITIZER_ARCH "aarch64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le")
|
||||
set(SANITIZER_ARCH "powerpc64le")
|
||||
else()
|
||||
set(SANITIZER_ARCH ${CMAKE_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
|
||||
set(SANITIZER_LIB_PATH "${CLANG_RESOURCE_DIR}/lib/${SANITIZER_LIB_SUBDIR}")
|
||||
|
||||
if(EXISTS "${SANITIZER_LIB_PATH}")
|
||||
# Add library search path and RPATH for sanitizer runtime
|
||||
if(APPLE)
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -L${SANITIZER_LIB_PATH} -Wl,-rpath,${SANITIZER_LIB_PATH}")
|
||||
elseif(WIN32)
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -L${SANITIZER_LIB_PATH}")
|
||||
else()
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -L${SANITIZER_LIB_PATH} -Wl,-rpath,${SANITIZER_LIB_PATH}")
|
||||
endif()
|
||||
|
||||
# When using gold linker with -static-libsan, we don't need explicit runtime linking
|
||||
# The -static-libsan flag tells Clang to link the static runtime archives automatically
|
||||
# REMOVED: Explicit -lclang_rt.msan-* (for shared runtime) - now using static linking
|
||||
if(SD_SANITIZERS MATCHES "memory")
|
||||
# Note: With -static-libsan flag above, Clang handles static runtime linking
|
||||
message(STATUS "Using static MSan runtime (via -static-libsan) for gold linker (${SANITIZER_ARCH})")
|
||||
endif()
|
||||
|
||||
# -fsanitize=leak uses the ASAN runtime (there's no separate LSAN .so)
|
||||
# For shared libraries loaded by JVM/JNI, the sanitizer runtime MUST be
|
||||
# dynamically linked, not statically linked. Without this, the sanitizer
|
||||
# runtime is not initialized and leaks are not detected.
|
||||
#
|
||||
# With gold linker, Clang defaults to static linking of sanitizer runtime.
|
||||
# We must explicitly link the shared .so file to make it a NEEDED dependency.
|
||||
if(SD_SANITIZERS MATCHES "leak" OR SD_SANITIZERS MATCHES "address")
|
||||
set(SANITIZE_LINK_FLAGS "${SANITIZE_LINK_FLAGS} -lclang_rt.asan-${SANITIZER_ARCH}")
|
||||
message(STATUS "Added explicit ASAN shared runtime library for leak/address sanitizer (${SANITIZER_ARCH}, JNI compatibility)")
|
||||
endif()
|
||||
|
||||
message(STATUS "Added clang sanitizer runtime library path and RPATH: ${SANITIZER_LIB_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message("Using sanitizers: ${SD_SANITIZERS}...")
|
||||
if(SD_CPU)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZE_FLAGS}" CACHE STRING "C++ flags" FORCE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZE_FLAGS}" CACHE STRING "C flags" FORCE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZE_LINK_FLAGS}" CACHE STRING "Exe linker flags" FORCE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${SANITIZE_LINK_FLAGS}" CACHE STRING "Shared linker flags" FORCE)
|
||||
endif()
|
||||
if(SD_CUDA)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZE_FLAGS} --relocatable-device-code=true" CACHE STRING "C++ flags" FORCE)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} ${SANITIZE_FLAGS}" CACHE STRING "CUDA flags" FORCE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZE_LINK_FLAGS}" CACHE STRING "Exe linker flags" FORCE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${SANITIZE_LINK_FLAGS}" CACHE STRING "Shared linker flags" FORCE)
|
||||
endif()
|
||||
|
||||
# MEMORY OPTIMIZATION: Limit parallel compilation jobs for sanitizer builds
|
||||
# Template instantiation files with sanitizers can use 8-12GB per compiler process
|
||||
# Limiting parallel jobs prevents memory exhaustion
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# Use CMake 3.0+ job pools to limit parallelism
|
||||
# Each instantiation file with MSan can peak at ~10GB
|
||||
# Safe limit: max(6, available_RAM_GB / 12)
|
||||
set(SANITIZER_MAX_JOBS 8)
|
||||
set_property(GLOBAL PROPERTY JOB_POOLS compile_pool=${SANITIZER_MAX_JOBS})
|
||||
set(CMAKE_JOB_POOL_COMPILE compile_pool)
|
||||
message(STATUS "⚠️ Limited parallel compilation to ${SANITIZER_MAX_JOBS} jobs for memory-intensive sanitizer build")
|
||||
message(STATUS " Estimated peak memory: ~${SANITIZER_MAX_JOBS}0 GB")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- Strict Linker Flags to Catch Undefined Symbols Early ---
|
||||
# This helps catch missing template specializations at link time instead of runtime
|
||||
# EXCEPTION: Do NOT use --no-undefined with sanitizers, as they require runtime symbol resolution
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT SD_SANITIZE AND NOT SD_GCC_FUNCTRACE)
|
||||
message(STATUS "⚠️ ENFORCING strict linker flags - build will FAIL on ANY undefined symbols")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-undefined")
|
||||
|
||||
# Without this, linker uses wrong relocation types → "relocation truncated to fit" errors
|
||||
if(SD_X86_BUILD AND NOT WIN32)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -mcmodel=medium")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -mcmodel=medium")
|
||||
message(STATUS "Applied medium code model to linker flags (matches compiler -mcmodel=medium)")
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND SD_GCC_FUNCTRACE AND NOT SD_SANITIZE)
|
||||
#
|
||||
#
|
||||
# THIS IS A PLATFORM LIMITATION, NOT A CODE BUG
|
||||
#
|
||||
|
||||
message(STATUS "⚠️ SD_GCC_FUNCTRACE enabled - binary will be ~3GB")
|
||||
message(STATUS "⚠️ WARNING: High risk of relocation errors with precompiled system libraries")
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-undefined")
|
||||
|
||||
# Aggressive size reduction for functrace builds
|
||||
add_compile_options(-ffunction-sections -fdata-sections)
|
||||
add_compile_options(-fvisibility=hidden -fvisibility-inlines-hidden)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections,--as-needed")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections,--as-needed")
|
||||
|
||||
# Memory optimizations for linking large binaries
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-keep-memory")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--reduce-memory-overheads")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--hash-size=31")
|
||||
|
||||
# NOTE: We use compiler-rt for runtime builtins but NOT libunwind for exception handling
|
||||
# (Session #1045 fix: libunwind conflicts with JVM's libgcc_s, causing _Unwind_SetGR crashes)
|
||||
# The system's libgcc_s handles exception unwinding, which is compatible with JVM
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# CRITICAL FIX: Do NOT use --unwindlib=libunwind for JNI libraries!
|
||||
#
|
||||
# Problem (discovered in session #1045):
|
||||
# - When --unwindlib=libunwind is used, Clang generates code assuming LLVM's libunwind ABI
|
||||
# - We also statically link libunwind.a
|
||||
# - BUT: At runtime, the JVM has libgcc_s.so loaded (for its own exception handling)
|
||||
# - Due to dynamic symbol interposition, _Unwind* symbols from libgcc_s.so override
|
||||
# our statically linked libunwind symbols
|
||||
# - Result: ABI mismatch between exception context format → CRASH in _Unwind_SetGR
|
||||
#
|
||||
# The crash manifests as: SIGSEGV in _Unwind_SetGR+0x3e trying to write to read-only
|
||||
# memory in libnd4jcpu.so during exception handling
|
||||
#
|
||||
# Solution: Use the system's default exception handling (libgcc_s), which is
|
||||
# compatible with the JVM environment. Keep compiler-rt only for builtins.
|
||||
#
|
||||
# Use compiler-rt for runtime builtins (math, etc.) but NOT for exception handling
|
||||
add_compile_options(--rtlib=compiler-rt)
|
||||
# REMOVED: add_compile_options(--unwindlib=libunwind)
|
||||
# Let the system use libgcc_s for exception unwinding - compatible with JVM
|
||||
|
||||
message(STATUS "✅ Using Clang compiler-rt for runtime builtins")
|
||||
message(STATUS "✅ Using system libgcc_s for exception handling (JNI/JVM compatible)")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
# With GCC, -finstrument-functions may pull in gprof startup code (__gmon_start__)
|
||||
# but this symbol is weakly defined and doesn't cause actual linker errors.
|
||||
# No special linker flags needed - GCC runtime handles this correctly.
|
||||
message(STATUS "✅ Using GCC with functrace (no special profiling symbols needed)")
|
||||
endif()
|
||||
|
||||
# Apply medium code model to match compiler (CRITICAL: large model incompatible with system CRT)
|
||||
if(SD_X86_BUILD AND NOT WIN32)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -mcmodel=medium")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -mcmodel=medium")
|
||||
# Allow text relocations as escape hatch if binary is still too large
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,notext")
|
||||
# Disable linker relaxation to prevent GOTPCREL relocation failures (required for medium code model)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-relax")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-relax")
|
||||
message(STATUS "Applied medium code model for functrace ONLY (binary size: ~3GB)")
|
||||
message(STATUS "Applied linker memory optimizations for functrace ONLY (--no-keep-memory, --reduce-memory-overheads)")
|
||||
message(STATUS "Added -Wl,-z,notext to allow text relocations if needed")
|
||||
message(STATUS "Added -Wl,--no-relax to prevent GOT relocation issues with medium code model")
|
||||
endif()
|
||||
elseif(SD_SANITIZE)
|
||||
message(STATUS "ℹ️ Skipping --no-undefined for sanitizer build (sanitizer runtime symbols resolved at runtime)")
|
||||
endif()
|
||||
|
||||
# Make build more verbose to see template instantiation issues
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
|
||||
if(SD_GCC_FUNCTRACE)
|
||||
message(STATUS "✅ Applying SD_GCC_FUNCTRACE debug flags for line number information")
|
||||
|
||||
# MEMORY OPTIMIZATION: Use minimal debug info instead of full debug info
|
||||
# This reduces compilation memory usage by 40-60% while maintaining stack traces
|
||||
# Clang: -gline-tables-only provides file names, line numbers, function names
|
||||
# GCC: -g1 provides minimal debug info (line numbers and functions only)
|
||||
# Full debug info (-ggdb3) causes memory explosion with templates
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O0 -gline-tables-only -fPIC -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -gline-tables-only -fPIC")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-O0 -gline-tables-only -fPIC -DNDEBUG")
|
||||
set(CMAKE_C_FLAGS_DEBUG "-O0 -gline-tables-only -fPIC")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O0 -g1 -fPIC -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g1 -fPIC")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-O0 -g1 -fPIC -DNDEBUG")
|
||||
set(CMAKE_C_FLAGS_DEBUG "-O0 -g1 -fPIC")
|
||||
endif()
|
||||
|
||||
# Add comprehensive debug flags
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
# Debug flags with function instrumentation
|
||||
# MEMORY OPTIMIZATION: Use -g1 (minimal debug info) instead of -ggdb3
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g1 -finstrument-functions -fno-omit-frame-pointer -fno-optimize-sibling-calls -rdynamic -fno-threadsafe-statics -ftls-model=global-dynamic")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g1 -fno-omit-frame-pointer -ftls-model=global-dynamic")
|
||||
message(STATUS "Applied memory-optimized debug flags for GCC (instrumentation enabled):")
|
||||
message(STATUS " - g1 (minimal debug info) for 40-60% memory reduction vs ggdb3")
|
||||
message(STATUS " - disabled thread-safe static guards")
|
||||
message(STATUS " - enabled function instrumentation")
|
||||
|
||||
# Override any conflicting optimization
|
||||
string(REGEX REPLACE "-O[0-9s]" "-O0" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REGEX REPLACE "-O[0-9s]" "-O0" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# Debug flags with function instrumentation
|
||||
# MEMORY OPTIMIZATION: Use -gline-tables-only instead of -ggdb3 (Clang-specific flag)
|
||||
# AGGRESSIVE MEMORY: Disable inline tracking and macro debug info
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -gline-tables-only -finstrument-functions -fno-omit-frame-pointer -fno-optimize-sibling-calls -rdynamic -fno-threadsafe-statics -ftls-model=global-dynamic -fno-standalone-debug")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -gline-tables-only -fno-omit-frame-pointer -ftls-model=global-dynamic -fno-standalone-debug")
|
||||
message(STATUS "Applied memory-optimized debug flags for Clang (instrumentation enabled):")
|
||||
message(STATUS " - gline-tables-only (Clang-specific) for 40-60% memory reduction vs ggdb3")
|
||||
message(STATUS " - disabled thread-safe static guards")
|
||||
message(STATUS " - enabled function instrumentation")
|
||||
|
||||
# Override any conflicting optimization
|
||||
string(REGEX REPLACE "-O[0-9s]" "-O0" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REGEX REPLACE "-O[0-9s]" "-O0" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
endif()
|
||||
|
||||
# Ensure debug info is preserved in linker
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rdynamic")
|
||||
|
||||
# Prevent stripping
|
||||
set(CMAKE_STRIP "/bin/true")
|
||||
|
||||
# Add the compiler definition
|
||||
add_compile_definitions(SD_GCC_FUNCTRACE=ON)
|
||||
|
||||
# Enable function instrumentation
|
||||
message(STATUS "ℹ️ Function instrumentation enabled. This will significantly increase binary size.")
|
||||
endif()
|
||||
|
||||
# --- Flag Deduplication ---
|
||||
# Remove duplicate flags that may have accumulated through multiple conditional blocks
|
||||
# This ensures cleaner build logs and prevents potential flag conflicts
|
||||
|
||||
# Helper function to deduplicate flags in a space-separated string
|
||||
function(deduplicate_flags FLAG_VAR)
|
||||
# Get the original flags
|
||||
set(original_flags "${${FLAG_VAR}}")
|
||||
|
||||
# Special handling: protect --param flags by temporarily replacing spaces
|
||||
string(REGEX REPLACE "--param ([^ ]+)" "--param=\\1" temp_flags "${original_flags}")
|
||||
|
||||
# Convert space-separated string to list
|
||||
string(REPLACE " " ";" FLAG_LIST "${temp_flags}")
|
||||
|
||||
# Remove duplicates while preserving order
|
||||
list(REMOVE_DUPLICATES FLAG_LIST)
|
||||
|
||||
# Convert back to space-separated string
|
||||
string(REPLACE ";" " " FLAG_STRING "${FLAG_LIST}")
|
||||
|
||||
# Restore --param format (space instead of =)
|
||||
string(REGEX REPLACE "--param=([^ ]+)" "--param \\1" FLAG_STRING "${FLAG_STRING}")
|
||||
|
||||
# Set the parent scope variable
|
||||
set(${FLAG_VAR} "${FLAG_STRING}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Deduplicate compiler flags
|
||||
deduplicate_flags(CMAKE_CXX_FLAGS)
|
||||
deduplicate_flags(CMAKE_C_FLAGS)
|
||||
deduplicate_flags(CMAKE_CXX_FLAGS_RELEASE)
|
||||
deduplicate_flags(CMAKE_CXX_FLAGS_DEBUG)
|
||||
deduplicate_flags(CMAKE_C_FLAGS_RELEASE)
|
||||
deduplicate_flags(CMAKE_C_FLAGS_DEBUG)
|
||||
|
||||
# Deduplicate linker flags
|
||||
deduplicate_flags(CMAKE_SHARED_LINKER_FLAGS)
|
||||
deduplicate_flags(CMAKE_EXE_LINKER_FLAGS)
|
||||
deduplicate_flags(CMAKE_MODULE_LINKER_FLAGS)
|
||||
|
||||
message(STATUS "✅ Compiler and linker flags deduplicated")
|
||||
@@ -0,0 +1,107 @@
|
||||
# CompilerOptimizations.cmake - Compiler flags and optimization settings
|
||||
|
||||
|
||||
|
||||
# Link Time Optimization
|
||||
if(SD_USE_LTO)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||
message(STATUS "Using Link Time Optimization")
|
||||
add_compile_options(-flto)
|
||||
add_link_options(-flto)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Architecture Tuning
|
||||
if(SD_ARCH MATCHES "armv8")
|
||||
set(ARCH_TUNE "-march=${SD_ARCH}")
|
||||
elseif(SD_ARCH MATCHES "armv7")
|
||||
set(ARCH_TUNE "-march=${SD_ARCH} -mfpu=neon")
|
||||
elseif(SD_EXTENSION MATCHES "avx2")
|
||||
message("Building AVX2 binary...")
|
||||
set(ARCH_TUNE "-mmmx -msse -msse2 -msse3 -msse4.1 -msse4.2 -mavx -mavx2 -mfma -mf16c -mprefetchwt1 -DSD_F16C=true -DF_AVX2=true")
|
||||
if(NO_AVX256_SPLIT)
|
||||
set(ARCH_TUNE "${ARCH_TUNE} -mno-avx256-split-unaligned-load -mno-avx256-split-unaligned-store")
|
||||
endif()
|
||||
else()
|
||||
if("${SD_ARCH}" STREQUAL "x86-64")
|
||||
message("Building x86_64 binary...")
|
||||
set(ARCH_TYPE "generic")
|
||||
add_compile_definitions(F_X64=true)
|
||||
else()
|
||||
set(ARCH_TYPE "${SD_ARCH}")
|
||||
endif()
|
||||
|
||||
if(SD_EXTENSION MATCHES "avx512")
|
||||
message("Building AVX512 binary...")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmmx -msse -msse2 -msse3 -msse4.1 -msse4.2 -mavx -mavx2 -mfma -mf16c -mavx512f -mavx512vl -mavx512bw -mavx512dq -mavx512cd -mbmi -mbmi2 -mprefetchwt1 -mclflushopt -mxsavec -mxsaves -DSD_F16C=true -DF_AVX512=true")
|
||||
endif()
|
||||
|
||||
# FIXED: Only set architecture flags if we have valid values
|
||||
if(NOT WIN32 AND NOT SD_CUDA)
|
||||
if(DEFINED SD_ARCH AND NOT SD_ARCH STREQUAL "" AND DEFINED ARCH_TYPE AND NOT ARCH_TYPE STREQUAL "")
|
||||
set(ARCH_TUNE "-march=${SD_ARCH} -mtune=${ARCH_TYPE}")
|
||||
elseif(DEFINED SD_ARCH AND NOT SD_ARCH STREQUAL "")
|
||||
# Fallback if ARCH_TYPE is not set
|
||||
set(ARCH_TUNE "-march=${SD_ARCH}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Comprehensive linker fix for PLT overflow
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND SD_X86_BUILD)
|
||||
message(STATUS "Configuring linker for large template library with PLT overflow prevention")
|
||||
|
||||
# Clear any existing conflicting linker flags
|
||||
string(REGEX REPLACE "-fuse-ld=[a-zA-Z]+" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
string(REGEX REPLACE "-fuse-ld=[a-zA-Z]+" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
|
||||
# Test if linker supports --plt-align before using it
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_LINKER} --help
|
||||
OUTPUT_VARIABLE LD_HELP_OUTPUT
|
||||
ERROR_QUIET
|
||||
)
|
||||
endif()
|
||||
|
||||
# Use large memory model (required for your template scale) - FIXED: Only for x86-64, not ARM
|
||||
if(SD_X86_BUILD AND NOT WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcmodel=medium -fPIC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcmodel=medium")
|
||||
message(STATUS "Applied large memory model for x86-64 architecture")
|
||||
else()
|
||||
if(SD_ARM_BUILD OR SD_ANDROID_BUILD)
|
||||
message(STATUS "Skipping large memory model for ARM/Android architecture (not supported)")
|
||||
elseif(WIN32)
|
||||
message(STATUS "Skipping large memory model for Windows (using alternative approach)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Memory optimization during compilation - FIXED: Only apply to GCC
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --param ggc-min-expand=100 --param ggc-min-heapsize=131072")
|
||||
endif()
|
||||
|
||||
# Section splitting for better linker handling - FIXED: Only apply to GCC/Clang
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
|
||||
endif()
|
||||
|
||||
# MSVC-specific optimizations
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
# MSVC equivalent optimizations
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Gy") # Function-level linking
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gy") # Function-level linking
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /OPT:REF /OPT:ICF") # Remove unreferenced code
|
||||
endif()
|
||||
|
||||
message(STATUS "Applied PLT overflow prevention for large template library")
|
||||
|
||||
if(SD_NATIVE)
|
||||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "ppc64*" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm64*")
|
||||
set(SD_X86_BUILD false)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,850 @@
|
||||
################################################################################
|
||||
# CUDA Configuration Functions
|
||||
# Functions for CUDA-specific build configuration and optimization
|
||||
################################################################################
|
||||
|
||||
# Enhanced CUDA toolkit detection with proper include path setup
|
||||
function(setup_cuda_toolkit_paths)
|
||||
message(STATUS "🔍 Setting up CUDA toolkit paths...")
|
||||
|
||||
# Find CUDA toolkit first
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
if(NOT CUDAToolkit_FOUND)
|
||||
message(FATAL_ERROR "CUDA toolkit not found. Please install CUDA toolkit or set CUDA_PATH environment variable.")
|
||||
endif()
|
||||
|
||||
# Get CUDA include directories
|
||||
get_target_property(CUDA_INCLUDE_DIRS CUDA::toolkit INTERFACE_INCLUDE_DIRECTORIES)
|
||||
|
||||
# If the above doesn't work, try alternative methods
|
||||
if(NOT CUDA_INCLUDE_DIRS)
|
||||
set(CUDA_INCLUDE_DIRS "${CUDAToolkit_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
||||
# Still not found? Try environment variables and common paths
|
||||
if(NOT CUDA_INCLUDE_DIRS)
|
||||
set(CUDA_SEARCH_PATHS
|
||||
$ENV{CUDA_PATH}
|
||||
$ENV{CUDA_HOME}
|
||||
$ENV{CUDA_ROOT}
|
||||
${CUDAToolkit_ROOT}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND CUDA_SEARCH_PATHS
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.6"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.5"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.4"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.3"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.2"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.1"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.0"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.8"
|
||||
"C:/tools/cuda"
|
||||
)
|
||||
else()
|
||||
list(APPEND CUDA_SEARCH_PATHS
|
||||
/usr/local/cuda
|
||||
/opt/cuda
|
||||
/usr/cuda
|
||||
)
|
||||
endif()
|
||||
|
||||
foreach(search_path ${CUDA_SEARCH_PATHS})
|
||||
if(EXISTS "${search_path}/include/cuda.h")
|
||||
set(CUDA_INCLUDE_DIRS "${search_path}/include")
|
||||
message(STATUS "✅ Found CUDA include directory: ${CUDA_INCLUDE_DIRS}")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Verify we found CUDA headers
|
||||
if(NOT CUDA_INCLUDE_DIRS)
|
||||
message(FATAL_ERROR "❌ CUDA include directories not found. Please ensure CUDA toolkit is properly installed.")
|
||||
endif()
|
||||
|
||||
# Verify cuda.h exists
|
||||
set(CUDA_H_FOUND FALSE)
|
||||
foreach(include_dir ${CUDA_INCLUDE_DIRS})
|
||||
if(EXISTS "${include_dir}/cuda.h")
|
||||
set(CUDA_H_FOUND TRUE)
|
||||
message(STATUS "✅ Found cuda.h in: ${include_dir}")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT CUDA_H_FOUND)
|
||||
message(FATAL_ERROR "❌ cuda.h not found in CUDA include directories: ${CUDA_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
||||
# Set variables for parent scope
|
||||
set(CUDA_INCLUDE_DIRS "${CUDA_INCLUDE_DIRS}" PARENT_SCOPE)
|
||||
set(CUDA_TOOLKIT_ROOT_DIR "${CUDAToolkit_ROOT}" PARENT_SCOPE)
|
||||
|
||||
message(STATUS "✅ CUDA toolkit paths configured:")
|
||||
message(STATUS " Root: ${CUDAToolkit_ROOT}")
|
||||
message(STATUS " Include: ${CUDA_INCLUDE_DIRS}")
|
||||
message(STATUS " Version: ${CUDAToolkit_VERSION}")
|
||||
endfunction()
|
||||
|
||||
# Modern cuDNN detection using updated FindCUDNN.cmake practices
|
||||
function(setup_modern_cudnn)
|
||||
set(HAVE_CUDNN FALSE PARENT_SCOPE)
|
||||
|
||||
if(NOT (HELPERS_cudnn AND SD_CUDA))
|
||||
message(STATUS "🔍 cuDNN: Skipped (HELPERS_cudnn=${HELPERS_cudnn}, SD_CUDA=${SD_CUDA})")
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "🔍 Searching for cuDNN...")
|
||||
|
||||
# Find the CUDA toolkit first to get the proper paths
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
# Enhanced search paths for CI environments and common installations
|
||||
set(CUDNN_SEARCH_PATHS
|
||||
# Environment variables
|
||||
$ENV{CUDNN_ROOT_DIR}
|
||||
$ENV{CUDNN_ROOT}
|
||||
$ENV{CUDA_PATH}
|
||||
$ENV{CUDA_HOME}
|
||||
|
||||
# CMake variables
|
||||
${CUDNN_ROOT_DIR}
|
||||
${CUDAToolkit_ROOT}
|
||||
)
|
||||
|
||||
# Add platform-specific paths
|
||||
if(WIN32)
|
||||
# Windows-specific paths
|
||||
list(APPEND CUDNN_SEARCH_PATHS
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.6"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.5"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.4"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.3"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.2"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.1"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v12.0"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.8"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.7"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.6"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.5"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.4"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.3"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.2"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.1"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA/v11.0"
|
||||
"$ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit/CUDA"
|
||||
"C:/tools/cuda" # Common CI path on Windows
|
||||
)
|
||||
else()
|
||||
# Linux/Unix-specific paths
|
||||
list(APPEND CUDNN_SEARCH_PATHS
|
||||
# CI-specific paths (GitHub Actions, etc.)
|
||||
/usr/local/cuda-12.6
|
||||
/usr/local/cuda-12.5
|
||||
/usr/local/cuda-12.4
|
||||
/usr/local/cuda-12.3
|
||||
/usr/local/cuda-12.2
|
||||
/usr/local/cuda-12.1
|
||||
/usr/local/cuda-12.0
|
||||
/usr/local/cuda-11.8
|
||||
/usr/local/cuda-11.7
|
||||
/usr/local/cuda-11.6
|
||||
/usr/local/cuda-11.5
|
||||
/usr/local/cuda-11.4
|
||||
/usr/local/cuda-11.3
|
||||
/usr/local/cuda-11.2
|
||||
/usr/local/cuda-11.1
|
||||
/usr/local/cuda-11.0
|
||||
/usr/local/cuda
|
||||
|
||||
# Package manager paths
|
||||
/usr/include/cudnn
|
||||
/usr/local/include/cudnn
|
||||
/opt/cuda
|
||||
/opt/cudnn
|
||||
|
||||
# System paths
|
||||
/usr
|
||||
/usr/local
|
||||
)
|
||||
endif()
|
||||
|
||||
message(STATUS "🔍 Searching for cuDNN headers...")
|
||||
|
||||
# Search for cuDNN headers with comprehensive path coverage
|
||||
find_path(CUDNN_INCLUDE_DIR
|
||||
NAMES cudnn.h
|
||||
HINTS ${CUDNN_SEARCH_PATHS}
|
||||
PATHS ${CUDNN_SEARCH_PATHS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
targets/x86_64-linux/include
|
||||
targets/aarch64-linux/include
|
||||
include/cudnn
|
||||
cudnn/include
|
||||
x86_64-linux/include
|
||||
aarch64-linux/include
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
# If not found, try system paths
|
||||
if(NOT CUDNN_INCLUDE_DIR)
|
||||
find_path(CUDNN_INCLUDE_DIR
|
||||
NAMES cudnn.h
|
||||
PATHS /usr/include /usr/local/include /opt/include
|
||||
PATH_SUFFIXES cudnn
|
||||
)
|
||||
endif()
|
||||
|
||||
message(STATUS "🔍 Searching for cuDNN libraries...")
|
||||
|
||||
# Search for cuDNN libraries
|
||||
find_library(CUDNN_LIBRARY
|
||||
NAMES cudnn libcudnn cudnn8 libcudnn8
|
||||
HINTS ${CUDNN_SEARCH_PATHS}
|
||||
PATHS ${CUDNN_SEARCH_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib64
|
||||
lib
|
||||
lib/x64
|
||||
targets/x86_64-linux/lib
|
||||
targets/aarch64-linux/lib
|
||||
lib64/cudnn
|
||||
lib/cudnn
|
||||
cudnn/lib64
|
||||
cudnn/lib
|
||||
x86_64-linux/lib
|
||||
aarch64-linux/lib
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
# If not found, try system paths
|
||||
if(NOT CUDNN_LIBRARY)
|
||||
find_library(CUDNN_LIBRARY
|
||||
NAMES cudnn libcudnn cudnn8 libcudnn8
|
||||
PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib /opt/lib64 /opt/lib
|
||||
PATH_SUFFIXES cudnn
|
||||
)
|
||||
endif()
|
||||
|
||||
message(STATUS "🔍 cuDNN search results:")
|
||||
message(STATUS " CUDNN_INCLUDE_DIR: ${CUDNN_INCLUDE_DIR}")
|
||||
message(STATUS " CUDNN_LIBRARY: ${CUDNN_LIBRARY}")
|
||||
|
||||
# Check if we found both header and library
|
||||
if(CUDNN_INCLUDE_DIR AND CUDNN_LIBRARY)
|
||||
message(STATUS "✅ cuDNN found!")
|
||||
|
||||
# Extract version information from cudnn.h
|
||||
if(EXISTS "${CUDNN_INCLUDE_DIR}/cudnn.h")
|
||||
file(READ "${CUDNN_INCLUDE_DIR}/cudnn.h" CUDNN_HEADER_CONTENTS)
|
||||
|
||||
# Try different version detection methods
|
||||
string(REGEX MATCH "define CUDNN_MAJOR[ \t]+([0-9]+)" CUDNN_VERSION_MAJOR_MATCH "${CUDNN_HEADER_CONTENTS}")
|
||||
string(REGEX MATCH "define CUDNN_MINOR[ \t]+([0-9]+)" CUDNN_VERSION_MINOR_MATCH "${CUDNN_HEADER_CONTENTS}")
|
||||
string(REGEX MATCH "define CUDNN_PATCHLEVEL[ \t]+([0-9]+)" CUDNN_VERSION_PATCH_MATCH "${CUDNN_HEADER_CONTENTS}")
|
||||
|
||||
if(CUDNN_VERSION_MAJOR_MATCH)
|
||||
string(REGEX REPLACE "define CUDNN_MAJOR[ \t]+([0-9]+)" "\\1" CUDNN_VERSION_MAJOR "${CUDNN_VERSION_MAJOR_MATCH}")
|
||||
string(REGEX REPLACE "define CUDNN_MINOR[ \t]+([0-9]+)" "\\1" CUDNN_VERSION_MINOR "${CUDNN_VERSION_MINOR_MATCH}")
|
||||
string(REGEX REPLACE "define CUDNN_PATCHLEVEL[ \t]+([0-9]+)" "\\1" CUDNN_VERSION_PATCH "${CUDNN_VERSION_PATCH_MATCH}")
|
||||
|
||||
set(CUDNN_VERSION_STRING "${CUDNN_VERSION_MAJOR}.${CUDNN_VERSION_MINOR}.${CUDNN_VERSION_PATCH}")
|
||||
else()
|
||||
# Try alternative version detection
|
||||
string(REGEX MATCH "#define CUDNN_MAJOR ([0-9]+)" CUDNN_VERSION_MAJOR_MATCH2 "${CUDNN_HEADER_CONTENTS}")
|
||||
if(CUDNN_VERSION_MAJOR_MATCH2)
|
||||
string(REGEX REPLACE "#define CUDNN_MAJOR ([0-9]+)" "\\1" CUDNN_VERSION_MAJOR "${CUDNN_VERSION_MAJOR_MATCH2}")
|
||||
string(REGEX MATCH "#define CUDNN_MINOR ([0-9]+)" CUDNN_VERSION_MINOR_MATCH2 "${CUDNN_HEADER_CONTENTS}")
|
||||
string(REGEX MATCH "#define CUDNN_PATCHLEVEL ([0-9]+)" CUDNN_VERSION_PATCH_MATCH2 "${CUDNN_HEADER_CONTENTS}")
|
||||
string(REGEX REPLACE "#define CUDNN_MINOR ([0-9]+)" "\\1" CUDNN_VERSION_MINOR "${CUDNN_VERSION_MINOR_MATCH2}")
|
||||
string(REGEX REPLACE "#define CUDNN_PATCHLEVEL ([0-9]+)" "\\1" CUDNN_VERSION_PATCH "${CUDNN_VERSION_PATCH_MATCH2}")
|
||||
set(CUDNN_VERSION_STRING "${CUDNN_VERSION_MAJOR}.${CUDNN_VERSION_MINOR}.${CUDNN_VERSION_PATCH}")
|
||||
else()
|
||||
set(CUDNN_VERSION_STRING "Unknown")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "⚠️ cuDNN header found but cannot read version")
|
||||
set(CUDNN_VERSION_STRING "Unknown")
|
||||
endif()
|
||||
|
||||
# Create imported target if it doesn't exist
|
||||
if(NOT TARGET CUDNN::cudnn)
|
||||
add_library(CUDNN::cudnn UNKNOWN IMPORTED)
|
||||
set_target_properties(CUDNN::cudnn PROPERTIES
|
||||
IMPORTED_LOCATION "${CUDNN_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CUDNN_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
message(STATUS "✅ cuDNN configuration:")
|
||||
message(STATUS " Include: ${CUDNN_INCLUDE_DIR}")
|
||||
message(STATUS " Library: ${CUDNN_LIBRARY}")
|
||||
message(STATUS " Version: ${CUDNN_VERSION_STRING}")
|
||||
|
||||
# Set all the variables that might be needed
|
||||
set(HAVE_CUDNN TRUE PARENT_SCOPE)
|
||||
set(CUDNN_FOUND TRUE PARENT_SCOPE)
|
||||
set(CUDNN_INCLUDE_DIR "${CUDNN_INCLUDE_DIR}" PARENT_SCOPE)
|
||||
set(CUDNN_LIBRARIES "${CUDNN_LIBRARY}" PARENT_SCOPE)
|
||||
set(CUDNN_LIBRARY "${CUDNN_LIBRARY}" PARENT_SCOPE)
|
||||
set(CUDNN_VERSION_STRING "${CUDNN_VERSION_STRING}" PARENT_SCOPE)
|
||||
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Try package manager detection as fallback
|
||||
find_package(PkgConfig QUIET)
|
||||
if(PkgConfig_FOUND)
|
||||
pkg_check_modules(PC_CUDNN QUIET cudnn)
|
||||
if(PC_CUDNN_FOUND)
|
||||
message(STATUS "✅ Found cuDNN via pkg-config")
|
||||
set(HAVE_CUDNN TRUE PARENT_SCOPE)
|
||||
set(CUDNN_INCLUDE_DIR "${PC_CUDNN_INCLUDE_DIRS}" PARENT_SCOPE)
|
||||
set(CUDNN_LIBRARIES "${PC_CUDNN_LIBRARIES}" PARENT_SCOPE)
|
||||
set(CUDNN_VERSION_STRING "${PC_CUDNN_VERSION}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Final attempt: check if cuDNN is embedded in CUDA installation
|
||||
if(CUDAToolkit_FOUND AND CUDAToolkit_INCLUDE_DIRS)
|
||||
foreach(cuda_include_dir ${CUDAToolkit_INCLUDE_DIRS})
|
||||
if(EXISTS "${cuda_include_dir}/cudnn.h")
|
||||
message(STATUS "✅ Found cuDNN embedded in CUDA installation")
|
||||
set(HAVE_CUDNN TRUE PARENT_SCOPE)
|
||||
set(CUDNN_INCLUDE_DIR "${cuda_include_dir}" PARENT_SCOPE)
|
||||
set(CUDNN_LIBRARIES "" PARENT_SCOPE) # May be linked with CUDA
|
||||
set(CUDNN_VERSION_STRING "Embedded" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
message(STATUS "❌ cuDNN not found. Searched extensively in:")
|
||||
message(STATUS " Environment variables: CUDNN_ROOT_DIR, CUDNN_ROOT, CUDA_PATH, CUDA_HOME")
|
||||
message(STATUS " CUDA installation: ${CUDAToolkit_ROOT}")
|
||||
if(WIN32)
|
||||
message(STATUS " System paths: $ENV{ProgramFiles}/NVIDIA GPU Computing Toolkit")
|
||||
else()
|
||||
message(STATUS " System paths: /usr, /usr/local, /opt")
|
||||
endif()
|
||||
message(STATUS " Package manager: pkg-config")
|
||||
message(STATUS "")
|
||||
message(STATUS "💡 To fix this issue:")
|
||||
message(STATUS " 1. Install cuDNN development libraries")
|
||||
message(STATUS " 2. Set CUDNN_ROOT_DIR to your cuDNN installation")
|
||||
message(STATUS " 3. Ensure cuDNN headers are in CUDA_PATH/include")
|
||||
message(STATUS " 4. Or disable cuDNN with -DHELPERS_cudnn=OFF")
|
||||
|
||||
# Debug information
|
||||
message(STATUS "")
|
||||
message(STATUS "🔍 Debug information:")
|
||||
message(STATUS " CUDAToolkit_ROOT: ${CUDAToolkit_ROOT}")
|
||||
message(STATUS " CUDAToolkit_INCLUDE_DIRS: ${CUDAToolkit_INCLUDE_DIRS}")
|
||||
message(STATUS " ENV CUDNN_ROOT_DIR: $ENV{CUDNN_ROOT_DIR}")
|
||||
message(STATUS " ENV CUDA_PATH: $ENV{CUDA_PATH}")
|
||||
message(STATUS " ENV CUDA_HOME: $ENV{CUDA_HOME}")
|
||||
endfunction()
|
||||
|
||||
function(configure_cuda_linking main_target_name)
|
||||
# Setup CUDA toolkit paths first
|
||||
setup_cuda_toolkit_paths()
|
||||
|
||||
# Find the CUDAToolkit to define the CUDA::toolkit target
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
# Setup modern cuDNN detection
|
||||
setup_modern_cudnn()
|
||||
|
||||
# This ensures cuda.h and other CUDA headers are found
|
||||
if(CUDA_INCLUDE_DIRS)
|
||||
target_include_directories(${main_target_name} PUBLIC ${CUDA_INCLUDE_DIRS})
|
||||
message(STATUS "✅ Added CUDA include directories to ${main_target_name}: ${CUDA_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
||||
# Apply GNU-specific CUDA compiler flags for duplicate instantiation handling
|
||||
# ONLY for non-Windows builds
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT WIN32)
|
||||
message(STATUS "🔧 Applying GNU-specific CUDA flags for duplicate instantiation handling")
|
||||
target_compile_options(${main_target_name} PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=-fno-implicit-templates>
|
||||
)
|
||||
endif()
|
||||
|
||||
# Modern CMake uses imported targets which handle all necessary dependencies.
|
||||
# Linking against CUDA::toolkit automatically adds include directories,
|
||||
# runtime libraries, and all other required flags.
|
||||
target_link_libraries(${main_target_name} PUBLIC CUDA::toolkit)
|
||||
|
||||
# If cuDNN was found, link against its imported target
|
||||
if(HAVE_CUDNN AND TARGET CUDNN::cudnn)
|
||||
message(STATUS "✅ Linking with modern CUDNN::cudnn target")
|
||||
target_link_libraries(${main_target_name} PUBLIC CUDNN::cudnn)
|
||||
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=1)
|
||||
elseif(HAVE_CUDNN AND CUDNN_LIBRARIES)
|
||||
message(STATUS "✅ Linking with cuDNN libraries: ${CUDNN_LIBRARIES}")
|
||||
target_link_libraries(${main_target_name} PUBLIC ${CUDNN_LIBRARIES})
|
||||
target_include_directories(${main_target_name} PUBLIC ${CUDNN_INCLUDE_DIR})
|
||||
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=1)
|
||||
elseif(HAVE_CUDNN AND CUDNN_INCLUDE_DIR)
|
||||
message(STATUS "✅ Linking with cuDNN include-only (embedded in CUDA)")
|
||||
target_include_directories(${main_target_name} PUBLIC ${CUDNN_INCLUDE_DIR})
|
||||
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=1)
|
||||
else()
|
||||
message(STATUS "ℹ️ Building without cuDNN support")
|
||||
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=0)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${main_target_name} PUBLIC flatbuffers_interface)
|
||||
install(TARGETS ${main_target_name} DESTINATION .)
|
||||
endfunction()
|
||||
|
||||
function(setup_cuda_architectures_early)
|
||||
if(NOT SD_CUDA)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Fix missing _CMAKE_CUDA_WHOLE_FLAG (note the underscore prefix)
|
||||
if(NOT DEFINED _CMAKE_CUDA_WHOLE_FLAG)
|
||||
message(STATUS "Setting _CMAKE_CUDA_WHOLE_FLAG (was missing)")
|
||||
if(WIN32)
|
||||
set(_CMAKE_CUDA_WHOLE_FLAG "/WHOLEARCHIVE:" CACHE INTERNAL "CUDA whole archive flag")
|
||||
else()
|
||||
set(_CMAKE_CUDA_WHOLE_FLAG "-Wl,--whole-archive" CACHE INTERNAL "CUDA whole archive flag")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_CUDA_WHOLE_FLAG)
|
||||
if(WIN32)
|
||||
set(CMAKE_CUDA_WHOLE_FLAG "/WHOLEARCHIVE:" CACHE STRING "CUDA whole archive flag")
|
||||
else()
|
||||
set(CMAKE_CUDA_WHOLE_FLAG "-Wl,--whole-archive" CACHE STRING "CUDA whole archive flag")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "🔧 Early CUDA: Configuring architectures before project() call")
|
||||
|
||||
if(DEFINED COMPUTE)
|
||||
string(TOLOWER "${COMPUTE}" COMPUTE_CMP)
|
||||
if(COMPUTE_CMP STREQUAL "all")
|
||||
set(CUDA_ARCHITECTURES "75;80;86;89" PARENT_SCOPE)
|
||||
message(STATUS " CUDA architectures (all): 75;80;86;89")
|
||||
elseif(COMPUTE_CMP STREQUAL "auto")
|
||||
set(CMAKE_CUDA_ARCHITECTURES "86" PARENT_SCOPE)
|
||||
message(STATUS " CUDA architectures (auto): 86")
|
||||
else()
|
||||
string(REPLACE "," ";" ARCH_LIST "${COMPUTE}")
|
||||
set(PARSED_ARCHS "")
|
||||
foreach(ARCH ${ARCH_LIST})
|
||||
string(REPLACE "." "" ARCH_CLEAN "${ARCH}")
|
||||
if(ARCH_CLEAN MATCHES "^[0-9][0-9]$")
|
||||
list(APPEND PARSED_ARCHS "${ARCH_CLEAN}")
|
||||
endif()
|
||||
endforeach()
|
||||
if(PARSED_ARCHS)
|
||||
set(CUDA_ARCHITECTURES "${PARSED_ARCHS}" PARENT_SCOPE)
|
||||
message(STATUS " CUDA architectures (custom): ${PARSED_ARCHS}")
|
||||
else()
|
||||
set(CUDA_ARCHITECTURES "86" PARENT_SCOPE)
|
||||
message(STATUS " CUDA architectures (default): 86")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
set(CUDA_ARCHITECTURES "86" PARENT_SCOPE)
|
||||
message(STATUS " CUDA architectures (no COMPUTE): 86")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(setup_cuda_language)
|
||||
if(NOT DEFINED _CMAKE_CUDA_WHOLE_FLAG)
|
||||
message(STATUS "Setting _CMAKE_CUDA_WHOLE_FLAG (was missing)")
|
||||
if(WIN32)
|
||||
set(_CMAKE_CUDA_WHOLE_FLAG "/WHOLEARCHIVE:" CACHE INTERNAL "CUDA whole archive flag")
|
||||
else()
|
||||
set(_CMAKE_CUDA_WHOLE_FLAG "-Wl,--whole-archive" CACHE INTERNAL "CUDA whole archive flag")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(CheckLanguage)
|
||||
check_language(CUDA)
|
||||
|
||||
if(NOT CMAKE_CUDA_COMPILER)
|
||||
find_program(NVCC_EXECUTABLE nvcc)
|
||||
if(NVCC_EXECUTABLE)
|
||||
set(CMAKE_CUDA_COMPILER ${NVCC_EXECUTABLE} PARENT_SCOPE)
|
||||
message(STATUS "CUDA compiler found: ${CMAKE_CUDA_COMPILER}")
|
||||
else()
|
||||
message(FATAL_ERROR "CUDA compiler not found. Please ensure CUDA toolkit is installed and nvcc is in PATH.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "CUDA language enabled successfully with compiler: ${CMAKE_CUDA_COMPILER}")
|
||||
endfunction()
|
||||
|
||||
function(configure_windows_cuda_build)
|
||||
if(NOT WIN32)
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "Configuring Windows CUDA build with verbose mode...")
|
||||
|
||||
# Enable verbose output for the build system
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON PARENT_SCOPE)
|
||||
set(CMAKE_CUDA_VERBOSE_FLAG ON PARENT_SCOPE)
|
||||
|
||||
# Completely disable response files to prevent command line issues
|
||||
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS OFF PARENT_SCOPE)
|
||||
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES OFF PARENT_SCOPE)
|
||||
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES OFF PARENT_SCOPE)
|
||||
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LINK_OBJECTS OFF PARENT_SCOPE)
|
||||
|
||||
# Remove problematic dependency generation that causes NVCC failures
|
||||
set(CMAKE_CUDA_DEPFILE_FORMAT "" PARENT_SCOPE)
|
||||
set(CMAKE_CUDA_DEPENDS_USE_COMPILER OFF PARENT_SCOPE)
|
||||
|
||||
# Clean MSVC runtime library settings
|
||||
set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded "" PARENT_SCOPE)
|
||||
set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL "" PARENT_SCOPE)
|
||||
set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug "" PARENT_SCOPE)
|
||||
set(CMAKE_CUDA_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "" PARENT_SCOPE)
|
||||
|
||||
# Force clean CXX flags to prevent contamination
|
||||
set(CMAKE_CXX_FLAGS "" PARENT_SCOPE)
|
||||
|
||||
# Enable verbose rule and target messages
|
||||
set_property(GLOBAL PROPERTY RULE_MESSAGES ON)
|
||||
set_property(GLOBAL PROPERTY TARGET_MESSAGES ON)
|
||||
|
||||
message(STATUS "Windows CUDA: Verbose mode enabled with clean flags")
|
||||
endfunction()
|
||||
function(configure_cuda_architecture_flags COMPUTE)
|
||||
string(TOLOWER "${COMPUTE}" COMPUTE_CMP)
|
||||
if(COMPUTE_CMP STREQUAL "all")
|
||||
set(CUDA_ARCH_FLAGS "-gencode arch=compute_75,code=sm_75 -gencode arch=compute_80,code=sm_80 -gencode arch=compute_86,code=sm_86 -gencode arch=compute_89,code=sm_89" PARENT_SCOPE)
|
||||
message(STATUS "Building for all CUDA architectures (gencode flags)")
|
||||
elseif(COMPUTE_CMP STREQUAL "auto")
|
||||
set(CUDA_ARCH_FLAGS "-gencode arch=compute_86,code=sm_86" PARENT_SCOPE)
|
||||
message(STATUS "Auto-detecting CUDA architectures (gencode flags)")
|
||||
else()
|
||||
string(REPLACE "," ";" ARCH_LIST "${COMPUTE}")
|
||||
set(ARCH_FLAGS "")
|
||||
foreach(ARCH ${ARCH_LIST})
|
||||
string(REPLACE "." "" ARCH_CLEAN "${ARCH}")
|
||||
if(ARCH_CLEAN MATCHES "^[0-9][0-9]$")
|
||||
set(ARCH_FLAGS "${ARCH_FLAGS} -gencode arch=compute_${ARCH_CLEAN},code=sm_${ARCH_CLEAN}")
|
||||
endif()
|
||||
endforeach()
|
||||
string(STRIP "${ARCH_FLAGS}" ARCH_FLAGS)
|
||||
if(ARCH_FLAGS)
|
||||
set(CUDA_ARCH_FLAGS "${ARCH_FLAGS}" PARENT_SCOPE)
|
||||
message(STATUS "Using custom CUDA architectures (gencode flags): ${ARCH_FLAGS}")
|
||||
else()
|
||||
set(CUDA_ARCH_FLAGS "-gencode arch=compute_86,code=sm_86" PARENT_SCOPE)
|
||||
message(STATUS "Using default CUDA architecture (gencode flags)")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(build_cuda_compiler_flags CUDA_ARCH_FLAGS)
|
||||
set(LOCAL_CUDA_FLAGS "")
|
||||
|
||||
if(WIN32 AND MSVC)
|
||||
message(STATUS "Configuring CUDA for Windows MSVC with verbose mode...")
|
||||
set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER} PARENT_SCOPE)
|
||||
set(LOCAL_CUDA_FLAGS "-maxrregcount=128")
|
||||
|
||||
# Enable verbose mode for Windows CUDA compilation
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --verbose")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --ptxas-options=-v")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --resource-usage")
|
||||
|
||||
# Host compiler verbose flags
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=/showIncludes")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=/verbose")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=/diagnostics:caret")
|
||||
|
||||
# Linker verbose flags
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xlinker=/VERBOSE")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xlinker=/TIME")
|
||||
|
||||
# Explicitly enable C++17 for the host compiler
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=/std:c++17")
|
||||
|
||||
if(WIN32 AND NOT CMAKE_CUDA_HOST_COMPILER)
|
||||
find_program(CL_IN_PATH cl.exe)
|
||||
if(CL_IN_PATH)
|
||||
# Check if this cl.exe is 64-bit by examining its path
|
||||
get_filename_component(CL_DIR ${CL_IN_PATH} DIRECTORY)
|
||||
if(CL_DIR MATCHES "x64")
|
||||
set(CMAKE_CUDA_HOST_COMPILER ${CL_IN_PATH})
|
||||
message(STATUS "Found x64 cl.exe in PATH: ${CMAKE_CUDA_HOST_COMPILER}")
|
||||
else()
|
||||
# Try to find x64 version relative to this cl.exe
|
||||
get_filename_component(CL_PARENT ${CL_DIR} DIRECTORY)
|
||||
if(EXISTS "${CL_PARENT}/x64/cl.exe")
|
||||
set(CMAKE_CUDA_HOST_COMPILER "${CL_PARENT}/x64/cl.exe")
|
||||
message(STATUS "Found x64 cl.exe relative to PATH cl.exe: ${CMAKE_CUDA_HOST_COMPILER}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT CMAKE_CUDA_HOST_COMPILER)
|
||||
# Only check the most common paths that exist in barebones installs
|
||||
set(COMMON_PATHS
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC"
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/VC/Tools/MSVC"
|
||||
"C:/Program Files/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC"
|
||||
)
|
||||
|
||||
foreach(BASE_PATH ${COMMON_PATHS})
|
||||
if(EXISTS ${BASE_PATH})
|
||||
file(GLOB MSVC_VERSIONS "${BASE_PATH}/*")
|
||||
if(MSVC_VERSIONS)
|
||||
# Get the lexicographically last version (should be newest)
|
||||
list(SORT MSVC_VERSIONS)
|
||||
list(REVERSE MSVC_VERSIONS)
|
||||
list(GET MSVC_VERSIONS 0 LATEST_MSVC)
|
||||
|
||||
set(CANDIDATE_COMPILER "${LATEST_MSVC}/bin/Hostx64/x64/cl.exe")
|
||||
if(EXISTS ${CANDIDATE_COMPILER})
|
||||
set(CMAKE_CUDA_HOST_COMPILER ${CANDIDATE_COMPILER})
|
||||
message(STATUS "Found CUDA host compiler in standard path: ${CMAKE_CUDA_HOST_COMPILER}")
|
||||
break()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Validation and warning
|
||||
if(WIN32)
|
||||
if(CMAKE_CUDA_HOST_COMPILER)
|
||||
if(NOT EXISTS ${CMAKE_CUDA_HOST_COMPILER})
|
||||
message(WARNING "CUDA host compiler path does not exist: ${CMAKE_CUDA_HOST_COMPILER}")
|
||||
unset(CMAKE_CUDA_HOST_COMPILER)
|
||||
else()
|
||||
message(STATUS "Final CUDA host compiler: ${CMAKE_CUDA_HOST_COMPILER}")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "Could not auto-detect x64 CUDA host compiler.")
|
||||
message(STATUS "Manual options:")
|
||||
message(STATUS " 1. Use x64 Native Tools Command Prompt")
|
||||
message(STATUS " 2. Set manually: -DCMAKE_CUDA_HOST_COMPILER=\"path/to/x64/cl.exe\"")
|
||||
message(STATUS " 3. Ensure x64 cl.exe is in your PATH")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Windows/MSVC flags: bigobj, EHsc, *and* disable the new preprocessor
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}
|
||||
-Xcompiler=/std:c++17
|
||||
-Xcompiler=/bigobj
|
||||
-Xcompiler=/EHsc
|
||||
-Xcompiler=/Zc:preprocessor-")
|
||||
|
||||
# Force clean host compiler flags
|
||||
set(CMAKE_CXX_FLAGS "" PARENT_SCOPE)
|
||||
|
||||
message(STATUS "CUDA Windows verbose flags configured")
|
||||
else()
|
||||
message(STATUS "Configuring CUDA for Unix/Linux with verbose mode...")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -maxrregcount=128")
|
||||
|
||||
# Enable verbose mode for Unix/Linux CUDA compilation
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --verbose")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --ptxas-options=-v")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --resource-usage")
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
# Host compiler verbose flags for GCC
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=-v")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=-H")
|
||||
|
||||
# Linker verbose flags
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xlinker=-v")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xlinker=--verbose")
|
||||
|
||||
if(SD_GCC_FUNCTRACE)
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=-fPIC --device-debug -lineinfo -G")
|
||||
else()
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=-fPIC -Xcompiler=-fpermissive")
|
||||
# Add flags to handle duplicate instantiations for GNU compiler
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -Xcompiler=-fno-implicit-templates")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "CUDA Unix/Linux verbose flags configured")
|
||||
endif()
|
||||
|
||||
if("${SD_PTXAS}" STREQUAL "ON")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --ptxas-options=-v")
|
||||
endif()
|
||||
|
||||
if(SD_KEEP_NVCC_OUTPUT)
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} --keep")
|
||||
endif()
|
||||
|
||||
if(DEFINED CUDA_ARCH_FLAGS)
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} ${CUDA_ARCH_FLAGS}")
|
||||
endif()
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -w --cudart=shared --expt-extended-lambda -Xfatbin -compress-all")
|
||||
|
||||
if(CMAKE_CUDA_COMPILER_VERSION)
|
||||
string(REGEX MATCH "^([0-9]+)" CUDA_VERSION_MAJOR "${CMAKE_CUDA_COMPILER_VERSION}")
|
||||
set(LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS} -DCUDA_VERSION_MAJOR=${CUDA_VERSION_MAJOR}")
|
||||
endif()
|
||||
|
||||
# Clean up any problematic flags for Windows
|
||||
if(WIN32)
|
||||
# Remove any GCC-style flags that might have been added
|
||||
string(REGEX REPLACE "-MD[^a-zA-Z]" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
|
||||
string(REGEX REPLACE "-MT[^a-zA-Z]" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
|
||||
string(REGEX REPLACE "-MF[^a-zA-Z]" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
|
||||
string(REGEX REPLACE "-x cu" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
|
||||
string(REGEX REPLACE "-fpermissive" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
|
||||
string(REGEX REPLACE "-Wno-error" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
|
||||
string(REGEX REPLACE "/FS[ ]*" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
|
||||
string(REGEX REPLACE "-Xcompiler=-Fd[^,]*,?" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
|
||||
string(REGEX REPLACE "-Xcompiler=," "-Xcompiler=" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
|
||||
string(REGEX REPLACE "-Xcompiler=$" "" LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
|
||||
endif()
|
||||
|
||||
string(REGEX REPLACE " +" " " LOCAL_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}")
|
||||
string(STRIP "${LOCAL_CUDA_FLAGS}" LOCAL_CUDA_FLAGS)
|
||||
|
||||
set(CMAKE_CUDA_SEPARABLE_COMPILATION ON PARENT_SCOPE)
|
||||
set(CMAKE_CUDA_FLAGS "${LOCAL_CUDA_FLAGS}" PARENT_SCOPE)
|
||||
|
||||
message(STATUS "Final CMAKE_CUDA_FLAGS (with verbose): ${LOCAL_CUDA_FLAGS}")
|
||||
endfunction()
|
||||
|
||||
# Debug configuration function
|
||||
function(debug_cuda_configuration)
|
||||
message(STATUS "=== CUDA Configuration Debug Info ===")
|
||||
message(STATUS "CMAKE_CUDA_COMPILER: ${CMAKE_CUDA_COMPILER}")
|
||||
message(STATUS "CMAKE_CUDA_COMPILER_VERSION: ${CMAKE_CUDA_COMPILER_VERSION}")
|
||||
message(STATUS "CMAKE_CUDA_ARCHITECTURES: ${CMAKE_CUDA_ARCHITECTURES}")
|
||||
message(STATUS "CMAKE_CUDA_FLAGS: ${CMAKE_CUDA_FLAGS}")
|
||||
message(STATUS "CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES: ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}")
|
||||
message(STATUS "CMAKE_CUDA_COMPILE_OBJECT: ${CMAKE_CUDA_COMPILE_OBJECT}")
|
||||
message(STATUS "CUDA_INCLUDE_DIRS: ${CUDA_INCLUDE_DIRS}")
|
||||
message(STATUS "CUDAToolkit_ROOT: ${CUDAToolkit_ROOT}")
|
||||
message(STATUS "CUDAToolkit_INCLUDE_DIRS: ${CUDAToolkit_INCLUDE_DIRS}")
|
||||
if(HAVE_CUDNN)
|
||||
message(STATUS "CUDNN_INCLUDE_DIR: ${CUDNN_INCLUDE_DIR}")
|
||||
message(STATUS "CUDNN_LIBRARIES: ${CUDNN_LIBRARIES}")
|
||||
message(STATUS "CUDNN_VERSION: ${CUDNN_VERSION_STRING}")
|
||||
endif()
|
||||
message(STATUS "=== End CUDA Debug Info ===")
|
||||
endfunction()
|
||||
|
||||
# Enhanced CUDA include directory setup for global configuration
|
||||
function(setup_cuda_include_directories)
|
||||
setup_cuda_toolkit_paths()
|
||||
|
||||
# Set global include directories that will be inherited by all targets
|
||||
if(CUDA_INCLUDE_DIRS)
|
||||
include_directories(${CUDA_INCLUDE_DIRS})
|
||||
message(STATUS "✅ Added global CUDA include directories: ${CUDA_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
||||
# Also set the CMAKE variable for compatibility
|
||||
if(CUDAToolkit_INCLUDE_DIRS)
|
||||
set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES ${CUDAToolkit_INCLUDE_DIRS} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(setup_cuda_build)
|
||||
message(STATUS "=== CUDA BUILD CONFIGURATION (VERBOSE MODE) ===")
|
||||
|
||||
# Enable verbose output for the build system
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON PARENT_SCOPE)
|
||||
set(CMAKE_CUDA_VERBOSE_FLAG ON PARENT_SCOPE)
|
||||
|
||||
if(NOT DEFINED _CMAKE_CUDA_WHOLE_FLAG)
|
||||
message(STATUS "Setting _CMAKE_CUDA_WHOLE_FLAG (was missing)")
|
||||
if(WIN32)
|
||||
set(_CMAKE_CUDA_WHOLE_FLAG "/WHOLEARCHIVE:" CACHE INTERNAL "CUDA whole archive flag")
|
||||
else()
|
||||
set(_CMAKE_CUDA_WHOLE_FLAG "-Wl,--whole-archive" CACHE INTERNAL "CUDA whole archive flag")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Setup CUDA toolkit paths and include directories early
|
||||
setup_cuda_include_directories()
|
||||
|
||||
if(NOT DEFINED COMPUTE)
|
||||
set(COMPUTE "auto")
|
||||
endif()
|
||||
configure_cuda_architecture_flags("${COMPUTE}")
|
||||
set_property(GLOBAL PROPERTY CUDA_ARCHITECTURES "${CMAKE_CUDA_ARCHITECTURES}")
|
||||
|
||||
setup_cuda_language()
|
||||
|
||||
if(NOT CMAKE_CUDA_COMPILER)
|
||||
message(FATAL_ERROR "CUDA compiler not found after enabling CUDA language")
|
||||
endif()
|
||||
|
||||
message(STATUS "CUDA Compiler: ${CMAKE_CUDA_COMPILER}")
|
||||
message(STATUS "CUDA Include Dirs: ${CUDA_INCLUDE_DIRS}")
|
||||
message(STATUS "CUDAToolkit Include Dirs: ${CUDAToolkit_INCLUDE_DIRS}")
|
||||
message(STATUS "Host CXX Compiler: ${CMAKE_CXX_COMPILER_ID}")
|
||||
|
||||
configure_windows_cuda_build()
|
||||
build_cuda_compiler_flags("${CUDA_ARCH_FLAGS}")
|
||||
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS}" PARENT_SCOPE)
|
||||
|
||||
# Also set the toolkit include directories for global access
|
||||
set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${CUDA_INCLUDE_DIRS}" PARENT_SCOPE)
|
||||
|
||||
# Enable verbose rule and target messages
|
||||
set_property(GLOBAL PROPERTY RULE_MESSAGES ON)
|
||||
set_property(GLOBAL PROPERTY TARGET_MESSAGES ON)
|
||||
|
||||
debug_cuda_configuration()
|
||||
|
||||
add_compile_definitions(SD_CUDA=true)
|
||||
set(DEFAULT_ENGINE "samediff::ENGINE_CUDA" PARENT_SCOPE)
|
||||
|
||||
message(STATUS "=== CUDA BUILD CONFIGURATION (VERBOSE MODE) COMPLETE ===")
|
||||
endfunction()
|
||||
|
||||
# Enhanced function to ensure CUDA paths are available at configure time
|
||||
function(ensure_cuda_paths_available)
|
||||
if(NOT SD_CUDA)
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "🔍 Ensuring CUDA paths are available...")
|
||||
|
||||
# Find CUDA early
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
# Set up paths immediately
|
||||
setup_cuda_toolkit_paths()
|
||||
|
||||
# Export to parent scope for immediate use
|
||||
set(CUDA_INCLUDE_DIRS "${CUDA_INCLUDE_DIRS}" PARENT_SCOPE)
|
||||
set(CUDA_TOOLKIT_ROOT_DIR "${CUDAToolkit_ROOT}" PARENT_SCOPE)
|
||||
|
||||
message(STATUS "✅ CUDA paths configured and available")
|
||||
endfunction()
|
||||
|
||||
# Legacy function for backward compatibility - now calls modern version
|
||||
function(setup_cudnn)
|
||||
setup_modern_cudnn()
|
||||
|
||||
# Set legacy variables for backward compatibility
|
||||
set(HAVE_CUDNN ${HAVE_CUDNN} PARENT_SCOPE)
|
||||
if(HAVE_CUDNN)
|
||||
set(CUDNN_INCLUDE_DIR ${CUDNN_INCLUDE_DIR} PARENT_SCOPE)
|
||||
set(CUDNN ${CUDNN_LIBRARIES} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -0,0 +1,510 @@
|
||||
# cmake/Dependencies.cmake
|
||||
# Manages all third-party dependencies. Logic is encapsulated in functions.
|
||||
|
||||
include(ExternalProject)
|
||||
function(setup_android_arm_openblas)
|
||||
set(is_android_or_arm FALSE)
|
||||
|
||||
if(ANDROID OR SD_ANDROID_BUILD OR SD_ARM_BUILD OR CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64|arm64|ARM64")
|
||||
set(is_android_or_arm TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT is_android_or_arm)
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "🔧 Setting up OpenBLAS for Android/ARM platform")
|
||||
|
||||
# Handle path normalization for Android/ARM
|
||||
if(OPENBLAS_PATH MATCHES "lib/[^/]+$")
|
||||
get_filename_component(OPENBLAS_PATH "${OPENBLAS_PATH}/../.." ABSOLUTE)
|
||||
message(STATUS "🔧 Normalized OPENBLAS_PATH: ${OPENBLAS_PATH}")
|
||||
endif()
|
||||
|
||||
# Platform-specific OpenBLAS library name handling
|
||||
if(EXISTS "${OPENBLAS_PATH}/lib")
|
||||
# Define search patterns based on platform
|
||||
set(LIB_SEARCH_PATTERNS
|
||||
"${OPENBLAS_PATH}/lib/libopenblas.so"
|
||||
"${OPENBLAS_PATH}/lib/libopenblas.a"
|
||||
)
|
||||
|
||||
# Add platform-specific patterns
|
||||
if(ANDROID OR SD_ANDROID_BUILD)
|
||||
if(CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64")
|
||||
list(APPEND LIB_SEARCH_PATTERNS
|
||||
"${OPENBLAS_PATH}/lib/android-x86_64/libopenblas.so"
|
||||
"${OPENBLAS_PATH}/lib/android-x86_64/libopenblas.a"
|
||||
)
|
||||
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a")
|
||||
list(APPEND LIB_SEARCH_PATTERNS
|
||||
"${OPENBLAS_PATH}/lib/android-arm64/libopenblas.so"
|
||||
"${OPENBLAS_PATH}/lib/android-arm64/libopenblas.a"
|
||||
"${OPENBLAS_PATH}/lib/android-aarch64/libopenblas.so"
|
||||
"${OPENBLAS_PATH}/lib/android-aarch64/libopenblas.a"
|
||||
)
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64|arm64|ARM64")
|
||||
list(APPEND LIB_SEARCH_PATTERNS
|
||||
"${OPENBLAS_PATH}/lib/linux-arm64/libopenblas.so"
|
||||
"${OPENBLAS_PATH}/lib/linux-arm64/libopenblas.a"
|
||||
"${OPENBLAS_PATH}/lib/linux-aarch64/libopenblas.so"
|
||||
"${OPENBLAS_PATH}/lib/linux-aarch64/libopenblas.a"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Search for libraries
|
||||
set(FOUND_OPENBLAS_LIBS "")
|
||||
foreach(pattern ${LIB_SEARCH_PATTERNS})
|
||||
file(GLOB matched_libs ${pattern})
|
||||
if(matched_libs)
|
||||
list(APPEND FOUND_OPENBLAS_LIBS ${matched_libs})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(FOUND_OPENBLAS_LIBS)
|
||||
message(STATUS "✅ Found OpenBLAS libraries: ${FOUND_OPENBLAS_LIBS}")
|
||||
else()
|
||||
message(WARNING "⚠️ No OpenBLAS libraries found in ${OPENBLAS_PATH}/lib")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Set platform-specific compiler flags for OpenBLAS
|
||||
if(ANDROID OR SD_ANDROID_BUILD)
|
||||
if(CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=x86-64" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64" PARENT_SCOPE)
|
||||
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8-a" PARENT_SCOPE)
|
||||
endif()
|
||||
elseif(SD_ARM_BUILD OR CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64|arm64|ARM64")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a -mtune=cortex-a72" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8-a -mtune=cortex-a72" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
# Set additional ARM-specific optimizations
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64|arm64|ARM64" OR CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfix-cortex-a53-835769 -mfix-cortex-a53-843419" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfix-cortex-a53-835769 -mfix-cortex-a53-843419" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(setup_blas)
|
||||
if(SD_CUDA)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT OPENBLAS_PATH)
|
||||
message(STATUS "❌ OPENBLAS_PATH not set")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Handle Android path normalization at CMake level (in case shell script normalization didn't work)
|
||||
setup_android_arm_openblas()
|
||||
|
||||
|
||||
# Verify the path exists and has the required headers
|
||||
if(NOT EXISTS "${OPENBLAS_PATH}/include")
|
||||
message(STATUS "❌ OpenBLAS include directory not found: ${OPENBLAS_PATH}/include")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${OPENBLAS_PATH}/include/cblas.h")
|
||||
message(STATUS "❌ OpenBLAS cblas.h not found: ${OPENBLAS_PATH}/include/cblas.h")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Set up OpenBLAS
|
||||
message(STATUS "✅ Setting up OpenBLAS:")
|
||||
message(STATUS " Path: ${OPENBLAS_PATH}")
|
||||
message(STATUS " Include: ${OPENBLAS_PATH}/include")
|
||||
message(STATUS " Library: ${OPENBLAS_PATH}/")
|
||||
|
||||
# Use global include_directories for compatibility
|
||||
include_directories(${OPENBLAS_PATH}/include/)
|
||||
|
||||
# Set up library directories
|
||||
if(EXISTS "${OPENBLAS_PATH}/lib")
|
||||
link_directories(${OPENBLAS_PATH}/)
|
||||
endif()
|
||||
|
||||
add_compile_definitions(HAVE_OPENBLAS=1)
|
||||
|
||||
# Set parent scope variables
|
||||
set(HAVE_OPENBLAS 1 PARENT_SCOPE)
|
||||
set(OPENBLAS_LIBRARIES openblas PARENT_SCOPE)
|
||||
|
||||
set(OPENBLAS_PATH "${OPENBLAS_PATH}" PARENT_SCOPE)
|
||||
|
||||
message(STATUS "✅ OpenBLAS setup complete")
|
||||
endfunction()
|
||||
|
||||
|
||||
|
||||
|
||||
function(setup_cudnn)
|
||||
set(HAVE_CUDNN false PARENT_SCOPE)
|
||||
set(CUDNN "" PARENT_SCOPE)
|
||||
|
||||
if(NOT (HELPERS_cudnn STREQUAL "ON" AND SD_CUDA))
|
||||
message(STATUS "cuDNN helper is disabled (HELPERS_cudnn=${HELPERS_cudnn}, SD_CUDA=${SD_CUDA})")
|
||||
return()
|
||||
endif()
|
||||
endfunction()
|
||||
# =============================================================================
|
||||
# FLATBUFFERS (Required) - Cross-compilation compatible version
|
||||
# =============================================================================
|
||||
function(setup_flatbuffers)
|
||||
set(FLATBUFFERS_VERSION "25.2.10")
|
||||
set(FLATBUFFERS_URL "https://github.com/google/flatbuffers/archive/v${FLATBUFFERS_VERSION}.tar.gz")
|
||||
|
||||
# Determine if we should build flatc
|
||||
set(SHOULD_BUILD_FLATC FALSE)
|
||||
if(DEFINED ENV{GENERATE_FLATC} OR DEFINED GENERATE_FLATC)
|
||||
set(SHOULD_BUILD_FLATC TRUE)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CROSSCOMPILING AND SHOULD_BUILD_FLATC)
|
||||
# Cross-compilation scenario: build flatc for host, library for target
|
||||
message(STATUS "Cross-compiling FlatBuffers: building flatc for host, library for target")
|
||||
|
||||
# Stage 1: Build flatc for host system
|
||||
set(FLATC_HOST_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-host")
|
||||
set(FLATC_HOST_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-host-build")
|
||||
set(FLATC_EXECUTABLE "${FLATC_HOST_BUILD_DIR}/flatc")
|
||||
|
||||
# Determine host system compilers
|
||||
find_program(HOST_C_COMPILER NAMES gcc clang cc)
|
||||
find_program(HOST_CXX_COMPILER NAMES g++ clang++ c++)
|
||||
|
||||
if(NOT HOST_C_COMPILER OR NOT HOST_CXX_COMPILER)
|
||||
message(FATAL_ERROR "Could not find host system compilers for flatc build")
|
||||
endif()
|
||||
|
||||
# Build CMAKE_ARGS without toolchain file for host build
|
||||
set(HOST_CMAKE_ARGS
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DFLATBUFFERS_BUILD_FLATC=ON
|
||||
-DFLATBUFFERS_BUILD_FLATLIB=OFF
|
||||
-DFLATBUFFERS_BUILD_TESTS=OFF
|
||||
-DFLATBUFFERS_BUILD_SAMPLES=OFF
|
||||
-DCMAKE_C_COMPILER=${HOST_C_COMPILER}
|
||||
-DCMAKE_CXX_COMPILER=${HOST_CXX_COMPILER}
|
||||
)
|
||||
|
||||
ExternalProject_Add(flatbuffers_host
|
||||
URL ${FLATBUFFERS_URL}
|
||||
SOURCE_DIR "${FLATC_HOST_DIR}"
|
||||
BINARY_DIR "${FLATC_HOST_BUILD_DIR}"
|
||||
CMAKE_ARGS ${HOST_CMAKE_ARGS}
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} --build . --target flatc --config Release
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_BYPRODUCTS "${FLATC_EXECUTABLE}"
|
||||
)
|
||||
|
||||
# Stage 2: Build FlatBuffers library for target
|
||||
# Build CMAKE_ARGS for target build, only include variables that are set
|
||||
set(TARGET_CMAKE_ARGS
|
||||
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DFLATBUFFERS_BUILD_FLATC=OFF
|
||||
-DFLATBUFFERS_BUILD_FLATLIB=ON
|
||||
-DFLATBUFFERS_BUILD_TESTS=OFF
|
||||
-DFLATBUFFERS_BUILD_SAMPLES=OFF
|
||||
)
|
||||
|
||||
# Only add cross-compilation arguments if they are defined
|
||||
if(CMAKE_TOOLCHAIN_FILE)
|
||||
list(APPEND TARGET_CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME)
|
||||
list(APPEND TARGET_CMAKE_ARGS -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_VERSION)
|
||||
list(APPEND TARGET_CMAKE_ARGS -DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION})
|
||||
endif()
|
||||
if(CMAKE_ANDROID_ARCH_ABI)
|
||||
list(APPEND TARGET_CMAKE_ARGS -DCMAKE_ANDROID_ARCH_ABI=${CMAKE_ANDROID_ARCH_ABI})
|
||||
endif()
|
||||
if(CMAKE_ANDROID_NDK)
|
||||
list(APPEND TARGET_CMAKE_ARGS -DCMAKE_ANDROID_NDK=${CMAKE_ANDROID_NDK})
|
||||
endif()
|
||||
if(CMAKE_ANDROID_STL_TYPE)
|
||||
list(APPEND TARGET_CMAKE_ARGS -DCMAKE_ANDROID_STL_TYPE=${CMAKE_ANDROID_STL_TYPE})
|
||||
endif()
|
||||
if(ANDROID_ABI)
|
||||
list(APPEND TARGET_CMAKE_ARGS -DANDROID_ABI=${ANDROID_ABI})
|
||||
endif()
|
||||
if(ANDROID_PLATFORM)
|
||||
list(APPEND TARGET_CMAKE_ARGS -DANDROID_PLATFORM=${ANDROID_PLATFORM})
|
||||
endif()
|
||||
if(ANDROID_STL)
|
||||
list(APPEND TARGET_CMAKE_ARGS -DANDROID_STL=${ANDROID_STL})
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(flatbuffers_target
|
||||
URL ${FLATBUFFERS_URL}
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-target-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-target-build"
|
||||
CMAKE_ARGS ${TARGET_CMAKE_ARGS}
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-target-build/libflatbuffers.a"
|
||||
DEPENDS flatbuffers_host
|
||||
)
|
||||
|
||||
# DO NOT use include_directories() - use target_include_directories on flatbuffers_interface instead
|
||||
# Set up include directories and library
|
||||
# include_directories("${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-target-src/include")
|
||||
set(FLATBUFFERS_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-target-build/libflatbuffers.a")
|
||||
set(FLATBUFFERS_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-target-src")
|
||||
|
||||
# Create interface library for target
|
||||
add_library(flatbuffers_interface INTERFACE)
|
||||
target_link_libraries(flatbuffers_interface INTERFACE ${FLATBUFFERS_LIBRARY})
|
||||
target_include_directories(flatbuffers_interface INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-target-src/include")
|
||||
add_dependencies(flatbuffers_interface flatbuffers_target)
|
||||
|
||||
# Check if flatbuffers.h already exists
|
||||
set(FLATBUFFERS_HEADER_DEST "${CMAKE_SOURCE_DIR}/libnd4j/include/flatbuffers/flatbuffers.h")
|
||||
if(EXISTS ${FLATBUFFERS_HEADER_DEST})
|
||||
message(STATUS "Found existing flatbuffers.h at ${FLATBUFFERS_HEADER_DEST}")
|
||||
endif()
|
||||
|
||||
# Generate headers and copy Java files inline after ExternalProject builds
|
||||
ExternalProject_Add_Step(flatbuffers_host generate_headers_and_copy_java
|
||||
COMMAND ${CMAKE_COMMAND} -E env "FLATC_PATH=${FLATC_EXECUTABLE}"
|
||||
bash ${CMAKE_CURRENT_SOURCE_DIR}/flatc-generate.sh
|
||||
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/copy-flatc-java.sh
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
"${CMAKE_SOURCE_DIR}/libnd4j/include/flatbuffers"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-host/include/flatbuffers/flatbuffers.h"
|
||||
"${CMAKE_SOURCE_DIR}/libnd4j/include/flatbuffers/flatbuffers.h"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Generating FlatBuffers headers, copying Java files, and copying flatbuffers.h using host flatc"
|
||||
DEPENDEES build
|
||||
BYPRODUCTS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/graph/generated.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/.java_files_copied
|
||||
${CMAKE_SOURCE_DIR}/libnd4j/include/flatbuffers/flatbuffers.h
|
||||
)
|
||||
|
||||
else()
|
||||
# Native build or cross-compilation without flatc generation
|
||||
message(STATUS "Native FlatBuffers build")
|
||||
|
||||
if(SHOULD_BUILD_FLATC)
|
||||
set(FLATBUFFERS_BUILD_FLATC "ON")
|
||||
else()
|
||||
set(FLATBUFFERS_BUILD_FLATC "OFF")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(flatbuffers_external
|
||||
URL ${FLATBUFFERS_URL}
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build"
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DFLATBUFFERS_BUILD_FLATC=${FLATBUFFERS_BUILD_FLATC}
|
||||
-DFLATBUFFERS_BUILD_FLATLIB=ON
|
||||
-DFLATBUFFERS_BUILD_TESTS=OFF
|
||||
-DFLATBUFFERS_BUILD_SAMPLES=OFF
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_BYPRODUCTS
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build/flatc"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build/libflatbuffers.a"
|
||||
)
|
||||
|
||||
# DO NOT use include_directories() - use target_include_directories on flatbuffers_interface instead
|
||||
# include_directories("${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-src/include")
|
||||
set(FLATBUFFERS_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build/libflatbuffers.a")
|
||||
set(FLATBUFFERS_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-src")
|
||||
|
||||
# Check if flatbuffers.h already exists
|
||||
set(FLATBUFFERS_HEADER_DEST "${CMAKE_SOURCE_DIR}/libnd4j/include/flatbuffers/flatbuffers.h")
|
||||
if(EXISTS ${FLATBUFFERS_HEADER_DEST})
|
||||
message(STATUS "Found existing flatbuffers.h at ${FLATBUFFERS_HEADER_DEST}")
|
||||
endif()
|
||||
|
||||
if(SHOULD_BUILD_FLATC)
|
||||
set(FLATC_EXECUTABLE "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build/flatc")
|
||||
|
||||
# Generate headers and copy Java files inline after ExternalProject builds
|
||||
ExternalProject_Add_Step(flatbuffers_external generate_headers_and_copy_java
|
||||
COMMAND ${CMAKE_COMMAND} -E env "FLATC_PATH=${FLATC_EXECUTABLE}"
|
||||
bash ${CMAKE_CURRENT_SOURCE_DIR}/flatc-generate.sh
|
||||
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/copy-flatc-java.sh
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
"${CMAKE_SOURCE_DIR}/include/flatbuffers"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-src/include/flatbuffers/flatbuffers.h"
|
||||
"${CMAKE_SOURCE_DIR}/include/flatbuffers/flatbuffers.h"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Generating FlatBuffers headers, copying Java files, and copying flatbuffers.h"
|
||||
DEPENDEES build
|
||||
BYPRODUCTS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/graph/generated.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/.java_files_copied
|
||||
${CMAKE_SOURCE_DIR}/libnd4j/include/flatbuffers/flatbuffers.h
|
||||
)
|
||||
else()
|
||||
# Even without flatc generation, copy the flatbuffers.h header
|
||||
ExternalProject_Add_Step(flatbuffers_external copy_flatbuffers_header
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
"${CMAKE_SOURCE_DIR}/libnd4j/include/flatbuffers"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-src/include/flatbuffers/flatbuffers.h"
|
||||
"${CMAKE_SOURCE_DIR}/libnd4j/include/flatbuffers/flatbuffers.h"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Copying flatbuffers.h header"
|
||||
DEPENDEES build
|
||||
BYPRODUCTS
|
||||
${CMAKE_SOURCE_DIR}/libnd4j/include/flatbuffers/flatbuffers.h
|
||||
)
|
||||
endif()
|
||||
|
||||
# Create interface library
|
||||
add_library(flatbuffers_interface INTERFACE)
|
||||
target_link_libraries(flatbuffers_interface INTERFACE ${FLATBUFFERS_LIBRARY})
|
||||
target_include_directories(flatbuffers_interface INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-src/include")
|
||||
add_dependencies(flatbuffers_interface flatbuffers_external)
|
||||
endif()
|
||||
|
||||
# Set global variables for parent scope
|
||||
set(FLATBUFFERS_LIBRARY ${FLATBUFFERS_LIBRARY} PARENT_SCOPE)
|
||||
set(FLATBUFFERS_SOURCE_DIR ${FLATBUFFERS_SOURCE_DIR} PARENT_SCOPE)
|
||||
if(SHOULD_BUILD_FLATC)
|
||||
set(FLATC_EXECUTABLE ${FLATC_EXECUTABLE} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
message(STATUS "✅ FlatBuffers setup complete")
|
||||
if(CMAKE_CROSSCOMPILING AND SHOULD_BUILD_FLATC)
|
||||
message(STATUS " Host flatc: ${FLATC_EXECUTABLE}")
|
||||
message(STATUS " Target library: ${FLATBUFFERS_LIBRARY}")
|
||||
else()
|
||||
message(STATUS " Library: ${FLATBUFFERS_LIBRARY}")
|
||||
if(SHOULD_BUILD_FLATC)
|
||||
message(STATUS " flatc: ${FLATC_EXECUTABLE}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
# =============================================================================
|
||||
# ONEDNN (Optional)
|
||||
# =============================================================================
|
||||
function(setup_onednn)
|
||||
if(NOT HELPERS_onednn STREQUAL "ON")
|
||||
message(STATUS "OneDNN helper is disabled (HELPERS_onednn=${HELPERS_onednn})")
|
||||
set(HAVE_ONEDNN FALSE PARENT_SCOPE)
|
||||
set(ONEDNN "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(TARGET onednn_external)
|
||||
message(STATUS "OneDNN helper is enabled (target already exists)")
|
||||
set(HAVE_ONEDNN TRUE PARENT_SCOPE)
|
||||
set(ONEDNN onednn_interface PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "OneDNN helper is enabled")
|
||||
set(HAVE_ONEDNN TRUE PARENT_SCOPE)
|
||||
set(ONEDNN_INSTALL_DIR "${CMAKE_BINARY_DIR}/onednn_install")
|
||||
|
||||
ExternalProject_Add(onednn_external
|
||||
PREFIX "${CMAKE_BINARY_DIR}/onednn_external"
|
||||
GIT_REPOSITORY "https://github.com/uxlfoundation/oneDNN.git"
|
||||
GIT_TAG "v3.8.1"
|
||||
SOURCE_DIR "${CMAKE_BINARY_DIR}/onednn_external/src"
|
||||
BINARY_DIR "${CMAKE_BINARY_DIR}/onednn_external/build"
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${ONEDNN_INSTALL_DIR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DDNNL_LIBRARY_TYPE=STATIC -DDNNL_BUILD_TESTS=OFF -DDNNL_BUILD_EXAMPLES=OFF -DDNNL_VERBOSE=OFF -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --config ${CMAKE_BUILD_TYPE} --parallel
|
||||
INSTALL_COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --target install --config ${CMAKE_BUILD_TYPE}
|
||||
BUILD_BYPRODUCTS "${ONEDNN_INSTALL_DIR}/include/dnnl.h" "${ONEDNN_INSTALL_DIR}/lib/libdnnl.a" "${ONEDNN_INSTALL_DIR}/lib/dnnl.lib"
|
||||
TIMEOUT 600
|
||||
)
|
||||
|
||||
add_library(onednn_interface INTERFACE)
|
||||
target_include_directories(onednn_interface INTERFACE "${ONEDNN_INSTALL_DIR}/include")
|
||||
if(WIN32)
|
||||
target_link_libraries(onednn_interface INTERFACE "${ONEDNN_INSTALL_DIR}/lib/dnnl.lib")
|
||||
else()
|
||||
target_link_libraries(onednn_interface INTERFACE "${ONEDNN_INSTALL_DIR}/lib/libdnnl.a")
|
||||
endif()
|
||||
add_dependencies(onednn_interface onednn_external)
|
||||
set(ONEDNN onednn_interface PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# =============================================================================
|
||||
# ARM COMPUTE LIBRARY (Optional)
|
||||
# =============================================================================
|
||||
function(setup_armcompute)
|
||||
set(HAVE_ARMCOMPUTE 0 PARENT_SCOPE)
|
||||
if(NOT HELPERS_armcompute STREQUAL "ON")
|
||||
message(STATUS "ARM Compute helper is disabled (HELPERS_armcompute=${HELPERS_armcompute})")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(TARGET armcompute_external)
|
||||
set(HAVE_ARMCOMPUTE 1 PARENT_SCOPE)
|
||||
set(ARMCOMPUTE_LIBRARIES armcompute_interface PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(LIBND4J_BUILD_WITH_ARMCOMPUTE AND (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64|arm64|ARM64"))
|
||||
set(ARMCOMPUTE_INSTALL_DIR "${CMAKE_BINARY_DIR}/armcompute_install")
|
||||
set(ARMCOMPUTE_VERSION "v25.04")
|
||||
set(ARMCOMPUTE_ARCH "aarch64")
|
||||
set(ARMCOMPUTE_PLATFORM "linux")
|
||||
set(ARMCOMPUTE_FLAVOR "cpu")
|
||||
set(ARMCOMPUTE_PKG_NAME "arm_compute-${ARMCOMPUTE_VERSION}-${ARMCOMPUTE_PLATFORM}-${ARMCOMPUTE_ARCH}-${ARMCOMPUTE_FLAVOR}-bin")
|
||||
set(ARMCOMPUTE_URL "https://github.com/ARM-software/ComputeLibrary/releases/download/${ARMCOMPUTE_VERSION}/${ARMCOMPUTE_PKG_NAME}.tar.gz")
|
||||
|
||||
ExternalProject_Add(armcompute_external
|
||||
PREFIX "${CMAKE_BINARY_DIR}/armcompute_external"
|
||||
URL "${ARMCOMPUTE_URL}"
|
||||
DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/downloads"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory <SOURCE_DIR>/${ARMCOMPUTE_PKG_NAME} ${ARMCOMPUTE_INSTALL_DIR}
|
||||
BUILD_BYPRODUCTS "${ARMCOMPUTE_INSTALL_DIR}/include/arm_compute/core/CL/CLKernelLibrary.h"
|
||||
)
|
||||
|
||||
add_library(armcompute_interface INTERFACE)
|
||||
target_include_directories(armcompute_interface INTERFACE "${ARMCOMPUTE_INSTALL_DIR}/include")
|
||||
target_link_directories(armcompute_interface INTERFACE "${ARMCOMPUTE_INSTALL_DIR}/lib")
|
||||
target_link_libraries(armcompute_interface INTERFACE arm_compute arm_compute_graph)
|
||||
add_dependencies(armcompute_interface armcompute_external)
|
||||
|
||||
set(ARMCOMPUTE_LIBRARIES armcompute_interface PARENT_SCOPE)
|
||||
set(HAVE_ARMCOMPUTE 1 PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# =============================================================================
|
||||
# CUDNN (Optional, for CUDA builds)
|
||||
# =============================================================================
|
||||
function(setup_cudnn)
|
||||
set(HAVE_CUDNN false PARENT_SCOPE)
|
||||
set(CUDNN "" PARENT_SCOPE)
|
||||
|
||||
if(NOT (HELPERS_cudnn AND SD_CUDA))
|
||||
return()
|
||||
endif()
|
||||
|
||||
find_package(CUDNN)
|
||||
if(CUDNN_FOUND)
|
||||
message(STATUS "✓ Found cuDNN: ${CUDNN_LIBRARY}")
|
||||
include_directories(${CUDNN_INCLUDE_DIR})
|
||||
set(HAVE_CUDNN true PARENT_SCOPE)
|
||||
set(CUDNN ${CUDNN_LIBRARIES} PARENT_SCOPE)
|
||||
add_definitions(-DHAVE_CUDNN=1)
|
||||
else()
|
||||
message(WARNING "✗ cuDNN not found. Continuing without cuDNN support.")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# GCC and Clang flags for C++ template duplicate instantiation issues
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
# For C++ template duplicate instantiation errors
|
||||
if(NOT SD_CUDA)
|
||||
add_compile_options(-fpermissive)
|
||||
add_compile_options(-ftemplate-depth=1024)
|
||||
add_compile_options(-fno-gnu-unique)
|
||||
message(STATUS "Added -fpermissive: Allows duplicate template instantiations")
|
||||
message(STATUS "Added template-related flags for C++ duplicate handling")
|
||||
else()
|
||||
# Also set CXX flags for host compilation
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -Wno-error")
|
||||
message(STATUS "Added CUDA-specific compiler flags for duplicate template instantiations")
|
||||
message(STATUS "Added --disable-warnings to suppress NVCC errors")
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
# For Clang template duplicate instantiation handling
|
||||
if(NOT SD_CUDA)
|
||||
# Template instantiation depth
|
||||
add_compile_options(-ftemplate-depth=1024)
|
||||
|
||||
# Check if this is an Android build
|
||||
if(ANDROID OR CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
# Android NDK specific handling - be more permissive like GCC
|
||||
add_compile_options(-Wno-error)
|
||||
add_compile_options(-Wno-duplicate-decl-specifier)
|
||||
add_compile_options(-Wno-unused-command-line-argument)
|
||||
add_compile_options(-ffunction-sections)
|
||||
add_compile_options(-fdata-sections)
|
||||
# Android linker doesn't support ICF well, use basic folding
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
message(STATUS "Added Android-specific Clang flags for duplicate template handling")
|
||||
else()
|
||||
# Desktop Clang with full template folding support
|
||||
add_compile_options(-ffunction-sections)
|
||||
add_compile_options(-fdata-sections)
|
||||
add_compile_options(-fmerge-all-constants)
|
||||
add_compile_options(-fno-unique-section-names)
|
||||
# Use LLD linker for better template folding support
|
||||
add_compile_options(-fuse-ld=lld)
|
||||
# Linker flags for identical code folding (ICF)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--icf=all -Wl,--gc-sections")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--icf=all -Wl,--gc-sections")
|
||||
message(STATUS "Added desktop Clang template folding with LLD linker")
|
||||
endif()
|
||||
else()
|
||||
# CUDA with Clang
|
||||
if(ANDROID OR CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth=1024 -Wno-error -Wno-duplicate-decl-specifier")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
message(STATUS "Added Android CUDA-specific Clang flags")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth=1024 -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler=-ffunction-sections -Xcompiler=-fdata-sections")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld -Wl,--icf=all")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=lld -Wl,--icf=all")
|
||||
message(STATUS "Added desktop CUDA-specific Clang template folding")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,590 @@
|
||||
# cmake/ExtractInstantiations.cmake
|
||||
# COMPLETE CONSOLIDATED PARALLEL TEMPLATE INSTANTIATION EXTRACTION
|
||||
# All functionality in ONE file - no separate helper files needed
|
||||
|
||||
message(STATUS "")
|
||||
message(STATUS "=====================================================")
|
||||
message(STATUS "=== TEMPLATE INSTANTIATION ANALYSIS MODE ACTIVE ===")
|
||||
message(STATUS "=====================================================")
|
||||
message(STATUS "SD_EXTRACT_INSTANTIATIONS = ${SD_EXTRACT_INSTANTIATIONS}")
|
||||
message(STATUS "CMAKE_SOURCE_DIR = ${CMAKE_SOURCE_DIR}")
|
||||
message(STATUS "CMAKE_BINARY_DIR = ${CMAKE_BINARY_DIR}")
|
||||
|
||||
# ============================================================================
|
||||
# HELPER FUNCTIONS - ALL INLINE, NO SEPARATE FILES
|
||||
# ============================================================================
|
||||
|
||||
# Function to normalize template signatures for comparison
|
||||
function(normalize_template_signature TEMPLATE OUT_VAR)
|
||||
set(normalized "${TEMPLATE}")
|
||||
|
||||
# Remove all extra whitespace
|
||||
string(REGEX REPLACE "[ \t\r\n]+" " " normalized "${normalized}")
|
||||
string(STRIP "${normalized}" normalized)
|
||||
|
||||
# Normalize spacing around template brackets
|
||||
string(REPLACE "< " "<" normalized "${normalized}")
|
||||
string(REPLACE " >" ">" normalized "${normalized}")
|
||||
string(REPLACE " <" "<" normalized "${normalized}")
|
||||
string(REPLACE "> " ">" normalized "${normalized}")
|
||||
|
||||
# Normalize pointer and reference notation
|
||||
string(REPLACE " *" "*" normalized "${normalized}")
|
||||
string(REPLACE " &" "&" normalized "${normalized}")
|
||||
string(REPLACE "* " "*" normalized "${normalized}")
|
||||
string(REPLACE "& " "&" normalized "${normalized}")
|
||||
|
||||
# Normalize const placement
|
||||
string(REGEX REPLACE "const[ ]+([^ ]+)" "\\1 const" normalized "${normalized}")
|
||||
|
||||
# Normalize namespace separators
|
||||
string(REPLACE " ::" "::" normalized "${normalized}")
|
||||
string(REPLACE ":: " "::" normalized "${normalized}")
|
||||
|
||||
# Remove trailing const
|
||||
string(REGEX REPLACE "[ ]+const$" "" normalized "${normalized}")
|
||||
|
||||
set(${OUT_VAR} "${normalized}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Function to check if a template should be filtered out
|
||||
function(should_filter_template TEMPLATE OUT_VAR)
|
||||
set(should_filter FALSE)
|
||||
|
||||
# Filter out all std:: templates
|
||||
if(TEMPLATE MATCHES "^std::")
|
||||
set(should_filter TRUE)
|
||||
endif()
|
||||
|
||||
# Filter out compiler intrinsics and internal templates
|
||||
if(TEMPLATE MATCHES "^__" OR
|
||||
TEMPLATE MATCHES "^operator" OR
|
||||
TEMPLATE MATCHES "^decltype" OR
|
||||
TEMPLATE MATCHES "^typename" OR
|
||||
TEMPLATE MATCHES "^template")
|
||||
set(should_filter TRUE)
|
||||
endif()
|
||||
|
||||
# Filter out basic types that aren't really templates
|
||||
if(TEMPLATE MATCHES "^(bool|char|short|int|long|float|double|void|unsigned|signed)")
|
||||
set(should_filter TRUE)
|
||||
endif()
|
||||
|
||||
set(${OUT_VAR} ${should_filter} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Setup compilation flags function
|
||||
function(setup_instantiation_flags)
|
||||
# Setup FlatBuffers
|
||||
set(PREPROCESS_FLATBUFFERS_VERSION "25.2.10")
|
||||
set(PREPROCESS_FLATBUFFERS_URL "https://github.com/google/flatbuffers/archive/v${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz")
|
||||
set(PREPROCESS_FB_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/preprocess-flatbuffers-src")
|
||||
|
||||
set(PREPROCESS_FB_HEADER "${PREPROCESS_FB_SOURCE_DIR}/include/flatbuffers/flatbuffers.h")
|
||||
if(NOT EXISTS ${PREPROCESS_FB_HEADER})
|
||||
message("Downloading and extracting FlatBuffers for instantiation analysis...")
|
||||
|
||||
file(DOWNLOAD ${PREPROCESS_FLATBUFFERS_URL}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz"
|
||||
SHOW_PROGRESS
|
||||
STATUS download_status)
|
||||
|
||||
list(GET download_status 0 download_result)
|
||||
if(NOT download_result EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to download FlatBuffers for instantiation analysis")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E tar xzf "flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
RESULT_VARIABLE extract_result
|
||||
)
|
||||
|
||||
if(NOT extract_result EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to extract FlatBuffers for instantiation analysis")
|
||||
endif()
|
||||
|
||||
file(RENAME "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}"
|
||||
"${PREPROCESS_FB_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
# Build include paths
|
||||
set(all_includes "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
file(GLOB_RECURSE all_dirs LIST_DIRECTORIES true "${CMAKE_CURRENT_SOURCE_DIR}/include/*")
|
||||
foreach(item ${all_dirs})
|
||||
if(IS_DIRECTORY ${item})
|
||||
list(APPEND all_includes ${item})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list(APPEND all_includes
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/include"
|
||||
"${CMAKE_SOURCE_DIR}/include/"
|
||||
"${CMAKE_SOURCE_DIR}/include/system"
|
||||
"${CMAKE_BINARY_DIR}/compilation_units"
|
||||
"${CMAKE_BINARY_DIR}/cpu_instantiations"
|
||||
"${CMAKE_BINARY_DIR}/cuda_instantiations"
|
||||
"${CMAKE_BINARY_DIR}/include"
|
||||
"${PREPROCESS_FB_SOURCE_DIR}/include"
|
||||
)
|
||||
|
||||
# Build include flags string
|
||||
set(include_flags "")
|
||||
foreach(dir IN LISTS all_includes)
|
||||
if(EXISTS ${dir})
|
||||
string(APPEND include_flags " -I${dir}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Build definition flags
|
||||
set(defs_flags "")
|
||||
string(APPEND defs_flags " -D__CPUBLAS__=true")
|
||||
if(SD_CUDA)
|
||||
string(APPEND defs_flags " -D__CUDABLAS__=true -DHAVE_CUDA=1")
|
||||
endif()
|
||||
if(HAVE_OPENBLAS)
|
||||
string(APPEND defs_flags " -DHAVE_OPENBLAS=1")
|
||||
endif()
|
||||
|
||||
if(SD_ALL_OPS OR "${SD_OPS_LIST}" STREQUAL "")
|
||||
string(APPEND defs_flags " -DSD_ALL_OPS=1")
|
||||
string(APPEND defs_flags " -DNOT_EXCLUDED(x)=1")
|
||||
else()
|
||||
foreach(OP ${SD_OPS_LIST})
|
||||
string(APPEND defs_flags " -DOP_${OP}=1")
|
||||
endforeach()
|
||||
string(APPEND defs_flags " -DNOT_EXCLUDED(x)=\\(defined\\(x\\)\\)")
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
string(APPEND defs_flags " -DDEBUG=1 -D_DEBUG=1")
|
||||
else()
|
||||
string(APPEND defs_flags " -DNDEBUG=1")
|
||||
endif()
|
||||
|
||||
if(SD_TYPES_LIST)
|
||||
string(REPLACE ";" "," types_comma_list "${SD_TYPES_LIST}")
|
||||
string(APPEND defs_flags " -DSD_TYPES_LIST=\"${types_comma_list}\"")
|
||||
endif()
|
||||
|
||||
# Export to parent scope
|
||||
set(INST_INCLUDE_FLAGS ${include_flags} PARENT_SCOPE)
|
||||
set(INST_DEFS_FLAGS ${defs_flags} PARENT_SCOPE)
|
||||
set(INST_LANG_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}" PARENT_SCOPE)
|
||||
|
||||
# Find required tools
|
||||
find_program(NM_TOOL NAMES nm gcc-nm llvm-nm)
|
||||
find_program(CPPFILT_TOOL NAMES c++filt llvm-cxxfilt)
|
||||
|
||||
set(NM_TOOL ${NM_TOOL} PARENT_SCOPE)
|
||||
set(CPPFILT_TOOL ${CPPFILT_TOOL} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Get source list function
|
||||
function(get_source_list OUT_VAR)
|
||||
if(DEFINED ALL_SOURCES AND ALL_SOURCES)
|
||||
set(${OUT_VAR} ${ALL_SOURCES} PARENT_SCOPE)
|
||||
elseif(DEFINED ALL_SOURCES_LIST AND ALL_SOURCES_LIST)
|
||||
set(${OUT_VAR} ${ALL_SOURCES_LIST} PARENT_SCOPE)
|
||||
else()
|
||||
set(${OUT_VAR} "" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# MAIN EXTRACTION FUNCTION - CONSOLIDATED WITH ACCURATE FILTERING
|
||||
function(extract_templates_consolidated SOURCE_FILE USED_OUTPUT_FILE PROVIDED_OUTPUT_FILE SAFE_NAME)
|
||||
# Initialize empty results
|
||||
set(used_templates "")
|
||||
set(provided_templates "")
|
||||
|
||||
# Check if source file exists
|
||||
if(NOT EXISTS "${SOURCE_FILE}")
|
||||
file(WRITE ${USED_OUTPUT_FILE} "")
|
||||
file(WRITE ${PROVIDED_OUTPUT_FILE} "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Determine compiler and flags
|
||||
if(SOURCE_FILE MATCHES "\\.cu$")
|
||||
set(compiler "${CMAKE_CUDA_COMPILER}")
|
||||
set(lang_flags "${CMAKE_CUDA_FLAGS} ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}}")
|
||||
else()
|
||||
set(compiler "${CMAKE_CXX_COMPILER}")
|
||||
set(lang_flags "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}")
|
||||
endif()
|
||||
|
||||
if(NOT compiler)
|
||||
file(WRITE ${USED_OUTPUT_FILE} "")
|
||||
file(WRITE ${PROVIDED_OUTPUT_FILE} "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# SINGLE PREPROCESSING PASS
|
||||
separate_arguments(lang_flags_list UNIX_COMMAND "${lang_flags}")
|
||||
separate_arguments(defs_flags_list UNIX_COMMAND "${INST_DEFS_FLAGS}")
|
||||
separate_arguments(include_flags_list UNIX_COMMAND "${INST_INCLUDE_FLAGS}")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${compiler}
|
||||
-E -P -C -dD
|
||||
${lang_flags_list}
|
||||
${defs_flags_list}
|
||||
${include_flags_list}
|
||||
"${SOURCE_FILE}"
|
||||
OUTPUT_VARIABLE preprocessed_content
|
||||
ERROR_VARIABLE preprocess_errors
|
||||
RESULT_VARIABLE preprocess_result
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
if(NOT preprocess_result EQUAL 0)
|
||||
file(WRITE ${USED_OUTPUT_FILE} "")
|
||||
file(WRITE ${PROVIDED_OUTPUT_FILE} "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
string(LENGTH "${preprocessed_content}" content_length)
|
||||
if(content_length GREATER 52428800)
|
||||
file(WRITE ${USED_OUTPUT_FILE} "")
|
||||
file(WRITE ${PROVIDED_OUTPUT_FILE} "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# EXTRACT PROVIDED TEMPLATES
|
||||
string(REGEX MATCHALL "template[ \t]+(?!extern)(class|struct)[ \t]+[a-zA-Z_][a-zA-Z0-9_:]*[ \t]*<[^;>]+>[ \t]*;"
|
||||
explicit_instantiations "${preprocessed_content}")
|
||||
|
||||
foreach(inst ${explicit_instantiations})
|
||||
string(REGEX MATCH "[a-zA-Z_][a-zA-Z0-9_:]*<[^>]+>" tmpl "${inst}")
|
||||
if(tmpl)
|
||||
should_filter_template("${tmpl}" should_filter)
|
||||
if(NOT should_filter)
|
||||
normalize_template_signature("${tmpl}" normalized)
|
||||
list(APPEND provided_templates "${normalized}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# EXTRACT USED TEMPLATES
|
||||
string(REGEX MATCHALL "extern[ \t]+template[ \t]+(class|struct)[ \t]+[a-zA-Z_][a-zA-Z0-9_:]*[ \t]*<[^;>]+>[ \t]*;"
|
||||
extern_templates "${preprocessed_content}")
|
||||
|
||||
foreach(ext ${extern_templates})
|
||||
string(REGEX MATCH "[a-zA-Z_][a-zA-Z0-9_:]*<[^>]+>" tmpl "${ext}")
|
||||
if(tmpl)
|
||||
should_filter_template("${tmpl}" should_filter)
|
||||
if(NOT should_filter)
|
||||
normalize_template_signature("${tmpl}" normalized)
|
||||
list(APPEND used_templates "${normalized}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Project-specific patterns
|
||||
set(project_template_patterns
|
||||
"NDArray<[^>]+>"
|
||||
"DataBuffer<[^>]+>"
|
||||
"ResultSet<[^>]+>"
|
||||
"ShapeList<[^>]+>"
|
||||
"LaunchContext<[^>]+>"
|
||||
"BroadcastHelper<[^>]+>"
|
||||
"BroadcastInt<[^>]+>"
|
||||
"BroadcastBool<[^>]+>"
|
||||
"Broadcast<[^>]+>"
|
||||
"PairWiseTransform<[^>]+>"
|
||||
"ScalarTransform<[^>]+>"
|
||||
"RandomFunction<[^>]+>"
|
||||
"ReduceSameFunction<[^>]+>"
|
||||
"ReduceFloatFunction<[^>]+>"
|
||||
"ReduceBoolFunction<[^>]+>"
|
||||
"ReduceLongFunction<[^>]+>"
|
||||
"Reduce3<[^>]+>"
|
||||
"IndexReduce<[^>]+>"
|
||||
"ReductionLoops<[^>]+>"
|
||||
"IndexReductionLoops<[^>]+>"
|
||||
"LoopKind::Kind<[^>]+>"
|
||||
"SpecialMethods<[^>]+>"
|
||||
"TypeCast::convertGeneric<[^>]+>"
|
||||
"DeclarableOp<[^>]+>"
|
||||
"DeclarableCustomOp<[^>]+>"
|
||||
"DeclarableReductionOp<[^>]+>"
|
||||
"GEMM<[^>]+>"
|
||||
"GEMV<[^>]+>"
|
||||
"AXPY<[^>]+>"
|
||||
)
|
||||
|
||||
foreach(pattern ${project_template_patterns})
|
||||
string(REGEX MATCHALL "${pattern}" matches "${preprocessed_content}")
|
||||
foreach(match ${matches})
|
||||
should_filter_template("${match}" should_filter)
|
||||
if(NOT should_filter)
|
||||
normalize_template_signature("${match}" normalized)
|
||||
list(APPEND used_templates "${normalized}")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# Remove duplicates and write
|
||||
if(used_templates)
|
||||
list(REMOVE_DUPLICATES used_templates)
|
||||
list(SORT used_templates)
|
||||
string(REPLACE ";" "\n" used_content "${used_templates}")
|
||||
file(WRITE ${USED_OUTPUT_FILE} "${used_content}")
|
||||
else()
|
||||
file(WRITE ${USED_OUTPUT_FILE} "")
|
||||
endif()
|
||||
|
||||
if(provided_templates)
|
||||
list(REMOVE_DUPLICATES provided_templates)
|
||||
list(SORT provided_templates)
|
||||
string(REPLACE ";" "\n" provided_content "${provided_templates}")
|
||||
file(WRITE ${PROVIDED_OUTPUT_FILE} "${provided_content}")
|
||||
else()
|
||||
file(WRITE ${PROVIDED_OUTPUT_FILE} "")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Process batch function for parallel execution
|
||||
function(process_batch BATCH_ID BATCH_FILE)
|
||||
if(NOT EXISTS ${BATCH_FILE})
|
||||
file(WRITE "${INST_BATCH_DIR}/batch_${BATCH_ID}.done" "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
file(STRINGS ${BATCH_FILE} FILES_TO_PROCESS)
|
||||
list(LENGTH FILES_TO_PROCESS batch_size)
|
||||
message("[Batch ${BATCH_ID}] Processing ${batch_size} files")
|
||||
|
||||
set(batch_results "")
|
||||
set(processed_count 0)
|
||||
|
||||
foreach(src IN LISTS FILES_TO_PROCESS)
|
||||
if(NOT EXISTS ${src})
|
||||
continue()
|
||||
endif()
|
||||
|
||||
get_filename_component(src_name ${src} NAME_WE)
|
||||
get_filename_component(src_path ${src} PATH)
|
||||
get_filename_component(src_full_name ${src} NAME)
|
||||
file(RELATIVE_PATH rel_path ${CMAKE_SOURCE_DIR} ${src_path})
|
||||
string(REPLACE "/" "_" safe_name "${rel_path}_${src_name}")
|
||||
|
||||
set(IS_GENERATED FALSE)
|
||||
if(src MATCHES "${CMAKE_BINARY_DIR}")
|
||||
set(IS_GENERATED TRUE)
|
||||
endif()
|
||||
|
||||
set(used_file "${INST_USED_DIR}/${safe_name}.used")
|
||||
set(provided_file "${INST_PROVIDED_DIR}/${safe_name}.provided")
|
||||
|
||||
extract_templates_consolidated("${src}" "${used_file}" "${provided_file}" "${safe_name}")
|
||||
|
||||
if(EXISTS ${used_file})
|
||||
file(STRINGS ${used_file} used_list)
|
||||
else()
|
||||
set(used_list "")
|
||||
endif()
|
||||
|
||||
if(EXISTS ${provided_file})
|
||||
file(STRINGS ${provided_file} provided_list)
|
||||
else()
|
||||
set(provided_list "")
|
||||
endif()
|
||||
|
||||
set(missing_templates "")
|
||||
foreach(used_tmpl ${used_list})
|
||||
set(found FALSE)
|
||||
foreach(provided_tmpl ${provided_list})
|
||||
if(used_tmpl STREQUAL provided_tmpl)
|
||||
set(found TRUE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
if(NOT found)
|
||||
list(APPEND missing_templates "${used_tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(missing_file "${INST_MISSING_DIR}/${safe_name}.missing")
|
||||
if(missing_templates)
|
||||
list(REMOVE_DUPLICATES missing_templates)
|
||||
string(REPLACE ";" "\n" missing_content "${missing_templates}")
|
||||
file(WRITE ${missing_file} "${missing_content}")
|
||||
list(LENGTH missing_templates missing_count)
|
||||
else()
|
||||
file(WRITE ${missing_file} "")
|
||||
set(missing_count 0)
|
||||
endif()
|
||||
|
||||
list(LENGTH used_list used_count)
|
||||
list(LENGTH provided_list provided_count)
|
||||
|
||||
string(APPEND batch_results "${src}|${safe_name}|${used_count}|${provided_count}|${missing_count}|${IS_GENERATED}\n")
|
||||
math(EXPR processed_count "${processed_count} + 1")
|
||||
endforeach()
|
||||
|
||||
file(WRITE "${INST_BATCH_DIR}/batch_${BATCH_ID}.done" "${batch_results}")
|
||||
message("[Batch ${BATCH_ID}] Completed: ${processed_count} files")
|
||||
endfunction()
|
||||
|
||||
# ============================================================================
|
||||
# MAIN EXECUTION
|
||||
# ============================================================================
|
||||
|
||||
# Determine parallelism
|
||||
if(NOT DEFINED INST_PARALLEL_JOBS)
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(PROCESSOR_COUNT)
|
||||
# PERFORMANCE OPTIMIZATION: Use all available cores for functrace builds
|
||||
# Old logic: Reserved 2 cores (PROCESSOR_COUNT - 2)
|
||||
# New logic: Use all cores (template processing is CPU-bound, not I/O-bound)
|
||||
if(PROCESSOR_COUNT GREATER 0)
|
||||
set(INST_PARALLEL_JOBS ${PROCESSOR_COUNT})
|
||||
else()
|
||||
set(INST_PARALLEL_JOBS 4)
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Parallel jobs: ${INST_PARALLEL_JOBS}")
|
||||
|
||||
# Setup directories
|
||||
set(INST_DIR "${CMAKE_SOURCE_DIR}/instantiation_analysis")
|
||||
set(INST_USED_DIR "${INST_DIR}/used")
|
||||
set(INST_PROVIDED_DIR "${INST_DIR}/provided")
|
||||
set(INST_MISSING_DIR "${INST_DIR}/missing")
|
||||
set(INST_REPORTS_DIR "${INST_DIR}/reports")
|
||||
set(INST_TEMP_DIR "${INST_DIR}/temp")
|
||||
set(INST_BY_FILE_DIR "${INST_DIR}/by_file")
|
||||
set(INST_BATCH_DIR "${INST_DIR}/batches")
|
||||
|
||||
foreach(dir IN ITEMS ${INST_DIR} ${INST_USED_DIR} ${INST_PROVIDED_DIR}
|
||||
${INST_MISSING_DIR} ${INST_REPORTS_DIR} ${INST_TEMP_DIR}
|
||||
${INST_BY_FILE_DIR} ${INST_BATCH_DIR})
|
||||
if(NOT EXISTS ${dir})
|
||||
file(MAKE_DIRECTORY ${dir})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Setup flags
|
||||
setup_instantiation_flags()
|
||||
|
||||
# Get sources
|
||||
message(STATUS "Collecting source files...")
|
||||
get_source_list(SOURCE_LIST)
|
||||
|
||||
if(NOT SOURCE_LIST)
|
||||
file(GLOB_RECURSE SOURCE_LIST
|
||||
"${CMAKE_SOURCE_DIR}/include/**/*.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/include/**/*.cu"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Add generated sources
|
||||
if(SD_CUDA)
|
||||
file(GLOB_RECURSE GEN_SOURCES
|
||||
"${CMAKE_BINARY_DIR}/cuda_instantiations/*.cu"
|
||||
"${CMAKE_BINARY_DIR}/compilation_units/*.cu")
|
||||
else()
|
||||
file(GLOB_RECURSE GEN_SOURCES
|
||||
"${CMAKE_BINARY_DIR}/cpu_instantiations/*.cpp"
|
||||
"${CMAKE_BINARY_DIR}/compilation_units/*.cpp")
|
||||
endif()
|
||||
list(APPEND SOURCE_LIST ${GEN_SOURCES})
|
||||
|
||||
# Filter and deduplicate
|
||||
set(FILTERED_SOURCE_LIST "")
|
||||
foreach(src IN LISTS SOURCE_LIST)
|
||||
if(src MATCHES "\\.(cpp|cxx|cc|cu)$" AND EXISTS ${src})
|
||||
list(APPEND FILTERED_SOURCE_LIST ${src})
|
||||
endif()
|
||||
endforeach()
|
||||
list(REMOVE_DUPLICATES FILTERED_SOURCE_LIST)
|
||||
set(SOURCE_LIST ${FILTERED_SOURCE_LIST})
|
||||
|
||||
list(LENGTH SOURCE_LIST source_count)
|
||||
message(STATUS "Total files to analyze: ${source_count}")
|
||||
|
||||
# Create batches
|
||||
math(EXPR FILES_PER_BATCH "${source_count} / ${INST_PARALLEL_JOBS}")
|
||||
if(FILES_PER_BATCH EQUAL 0)
|
||||
set(FILES_PER_BATCH 1)
|
||||
endif()
|
||||
|
||||
set(current_batch 0)
|
||||
set(files_in_batch 0)
|
||||
foreach(src IN LISTS SOURCE_LIST)
|
||||
file(APPEND "${INST_BATCH_DIR}/batch_${current_batch}.txt" "${src}\n")
|
||||
math(EXPR files_in_batch "${files_in_batch} + 1")
|
||||
if(files_in_batch GREATER_EQUAL FILES_PER_BATCH AND current_batch LESS ${INST_PARALLEL_JOBS})
|
||||
math(EXPR current_batch "${current_batch} + 1")
|
||||
set(files_in_batch 0)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Process batches
|
||||
message(STATUS "Processing ${INST_PARALLEL_JOBS} batches...")
|
||||
foreach(batch_id RANGE 0 ${INST_PARALLEL_JOBS})
|
||||
set(batch_file "${INST_BATCH_DIR}/batch_${batch_id}.txt")
|
||||
if(EXISTS ${batch_file})
|
||||
process_batch(${batch_id} ${batch_file})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Aggregate results
|
||||
message(STATUS "Aggregating results...")
|
||||
set(TOTAL_USED 0)
|
||||
set(TOTAL_PROVIDED 0)
|
||||
set(TOTAL_MISSING 0)
|
||||
|
||||
file(WRITE ${INST_REPORTS_DIR}/summary.csv "File,Path,Used,Provided,Missing,Type\n")
|
||||
|
||||
foreach(batch_id RANGE 0 ${INST_PARALLEL_JOBS})
|
||||
set(done_file "${INST_BATCH_DIR}/batch_${batch_id}.done")
|
||||
if(EXISTS ${done_file})
|
||||
file(STRINGS ${done_file} batch_results)
|
||||
foreach(result_line ${batch_results})
|
||||
if(result_line)
|
||||
string(REPLACE "|" ";" result_parts "${result_line}")
|
||||
list(LENGTH result_parts parts_count)
|
||||
if(parts_count EQUAL 6)
|
||||
list(GET result_parts 0 src)
|
||||
list(GET result_parts 2 used_count)
|
||||
list(GET result_parts 3 provided_count)
|
||||
list(GET result_parts 4 missing_count)
|
||||
list(GET result_parts 5 is_generated)
|
||||
|
||||
math(EXPR TOTAL_USED "${TOTAL_USED} + ${used_count}")
|
||||
math(EXPR TOTAL_PROVIDED "${TOTAL_PROVIDED} + ${provided_count}")
|
||||
math(EXPR TOTAL_MISSING "${TOTAL_MISSING} + ${missing_count}")
|
||||
|
||||
get_filename_component(src_name ${src} NAME)
|
||||
get_filename_component(src_path ${src} PATH)
|
||||
file(RELATIVE_PATH rel_path ${CMAKE_SOURCE_DIR} ${src_path})
|
||||
|
||||
set(file_type "original")
|
||||
if(is_generated)
|
||||
set(file_type "generated")
|
||||
endif()
|
||||
|
||||
file(APPEND ${INST_REPORTS_DIR}/summary.csv
|
||||
"${src_name},${rel_path},${used_count},${provided_count},${missing_count},${file_type}\n")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Final summary
|
||||
message(STATUS "")
|
||||
message(STATUS "=====================================================")
|
||||
message(STATUS "=== ANALYSIS COMPLETE ===")
|
||||
message(STATUS "=====================================================")
|
||||
message(STATUS "Templates Used: ${TOTAL_USED}")
|
||||
message(STATUS "Templates Provided: ${TOTAL_PROVIDED}")
|
||||
message(STATUS "Templates Missing: ${TOTAL_MISSING}")
|
||||
message(STATUS "")
|
||||
message(STATUS "Reports generated in: ${INST_REPORTS_DIR}")
|
||||
|
||||
# Exit without continuing build
|
||||
message(STATUS "Exiting after instantiation extraction (SD_EXTRACT_INSTANTIATIONS=ON)")
|
||||
return()
|
||||
@@ -0,0 +1,533 @@
|
||||
# FileConcatenation.cmake
|
||||
# Clean template concatenation with duplicate import elimination
|
||||
|
||||
# Global variables to track includes and content
|
||||
set(GLOBAL_INCLUDES_SET "" CACHE INTERNAL "Set of unique includes")
|
||||
set(GLOBAL_INCLUDES_LIST "" CACHE INTERNAL "Ordered list of unique includes")
|
||||
|
||||
# Function to extract and deduplicate includes from content
|
||||
function(extract_and_deduplicate_includes content includes_var content_without_includes_var)
|
||||
# Handle empty content
|
||||
if(content STREQUAL "")
|
||||
set(${includes_var} "" PARENT_SCOPE)
|
||||
set(${content_without_includes_var} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Split content into lines
|
||||
string(REPLACE "\n" ";" content_lines "${content}")
|
||||
|
||||
set(extracted_includes "")
|
||||
set(content_without_includes "")
|
||||
set(in_multiline_comment FALSE)
|
||||
|
||||
foreach(line ${content_lines})
|
||||
# Handle empty lines
|
||||
if(NOT DEFINED line OR line STREQUAL "")
|
||||
string(APPEND content_without_includes "\n")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Handle multi-line comments
|
||||
if(line MATCHES "/\\*")
|
||||
set(in_multiline_comment TRUE)
|
||||
endif()
|
||||
if(line MATCHES "\\*/")
|
||||
set(in_multiline_comment FALSE)
|
||||
string(APPEND content_without_includes "${line}\n")
|
||||
continue()
|
||||
endif()
|
||||
if(in_multiline_comment)
|
||||
string(APPEND content_without_includes "${line}\n")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Skip single-line comments unless they contain includes
|
||||
if(line MATCHES "^[ \t]*//.*#include")
|
||||
# This is a commented include, treat as regular content
|
||||
string(APPEND content_without_includes "${line}\n")
|
||||
elseif(line MATCHES "^[ \t]*//")
|
||||
# Regular comment, keep as content
|
||||
string(APPEND content_without_includes "${line}\n")
|
||||
elseif(line MATCHES "^[ \t]*#include")
|
||||
# Extract include statement - use STRIP instead of REGEX REPLACE to avoid empty match issues
|
||||
string(STRIP "${line}" cleaned_include)
|
||||
if(NOT cleaned_include STREQUAL "")
|
||||
list(APPEND extracted_includes "${cleaned_include}")
|
||||
endif()
|
||||
else()
|
||||
# Regular content line
|
||||
string(APPEND content_without_includes "${line}\n")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(${includes_var} "${extracted_includes}" PARENT_SCOPE)
|
||||
set(${content_without_includes_var} "${content_without_includes}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Function to add includes to global set maintaining order
|
||||
function(add_includes_to_global_set new_includes)
|
||||
foreach(include_stmt ${new_includes})
|
||||
# Normalize the include statement
|
||||
string(STRIP "${include_stmt}" include_stmt)
|
||||
|
||||
# Check if this include is already in our global set
|
||||
list(FIND GLOBAL_INCLUDES_SET "${include_stmt}" found_index)
|
||||
if(found_index EQUAL -1)
|
||||
# New include, add to both set and ordered list
|
||||
list(APPEND GLOBAL_INCLUDES_SET "${include_stmt}")
|
||||
list(APPEND GLOBAL_INCLUDES_LIST "${include_stmt}")
|
||||
|
||||
# Update cache
|
||||
set(GLOBAL_INCLUDES_SET "${GLOBAL_INCLUDES_SET}" CACHE INTERNAL "Set of unique includes")
|
||||
set(GLOBAL_INCLUDES_LIST "${GLOBAL_INCLUDES_LIST}" CACHE INTERNAL "Ordered list of unique includes")
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# Function to generate the final includes section
|
||||
function(generate_includes_section result_var)
|
||||
set(includes_section "")
|
||||
|
||||
if(GLOBAL_INCLUDES_LIST)
|
||||
string(APPEND includes_section "/*\n * Consolidated Include Section\n * All unique includes from processed templates\n */\n")
|
||||
|
||||
# Group includes by type for better organization
|
||||
set(system_includes "")
|
||||
set(local_includes "")
|
||||
set(other_includes "")
|
||||
|
||||
foreach(include_stmt ${GLOBAL_INCLUDES_LIST})
|
||||
if(include_stmt MATCHES "#include[ \t]*<.*>")
|
||||
list(APPEND system_includes "${include_stmt}")
|
||||
elseif(include_stmt MATCHES "#include[ \t]*\".*\"")
|
||||
list(APPEND local_includes "${include_stmt}")
|
||||
else()
|
||||
list(APPEND other_includes "${include_stmt}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Output system includes first
|
||||
if(system_includes)
|
||||
string(APPEND includes_section "\n// System includes\n")
|
||||
foreach(include_stmt ${system_includes})
|
||||
string(APPEND includes_section "${include_stmt}\n")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Then local includes
|
||||
if(local_includes)
|
||||
string(APPEND includes_section "\n// Local includes\n")
|
||||
foreach(include_stmt ${local_includes})
|
||||
string(APPEND includes_section "${include_stmt}\n")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Finally other includes
|
||||
if(other_includes)
|
||||
string(APPEND includes_section "\n// Other includes\n")
|
||||
foreach(include_stmt ${other_includes})
|
||||
string(APPEND includes_section "${include_stmt}\n")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
string(APPEND includes_section "\n")
|
||||
endif()
|
||||
|
||||
set(${result_var} "${includes_section}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Process a single template instance with specific type indices
|
||||
function(process_single_template_instance template_file comb1 comb2 comb3 result_var)
|
||||
file(READ "${template_file}" original_content)
|
||||
|
||||
# Set template variables
|
||||
set(FL_TYPE_INDEX ${comb1})
|
||||
set(TYPE_INDEX_1 ${comb1})
|
||||
set(TYPE_INDEX_2 ${comb2})
|
||||
set(TYPE_INDEX_3 ${comb3})
|
||||
|
||||
# Determine what #cmakedefine flags to enable based on template content
|
||||
set(SD_COMMON_TYPES_GEN 0)
|
||||
set(SD_FLOAT_TYPES_GEN 0)
|
||||
set(SD_INTEGER_TYPES_GEN 0)
|
||||
set(SD_PAIRWISE_TYPES_GEN 0)
|
||||
set(SD_SEMANTIC_TYPES_GEN 0)
|
||||
|
||||
if(original_content MATCHES "#cmakedefine[ \t]+SD_COMMON_TYPES_GEN")
|
||||
set(SD_COMMON_TYPES_GEN 1)
|
||||
endif()
|
||||
if(original_content MATCHES "#cmakedefine[ \t]+SD_FLOAT_TYPES_GEN")
|
||||
set(SD_FLOAT_TYPES_GEN 1)
|
||||
endif()
|
||||
if(original_content MATCHES "#cmakedefine[ \t]+SD_INTEGER_TYPES_GEN")
|
||||
set(SD_INTEGER_TYPES_GEN 1)
|
||||
endif()
|
||||
if(original_content MATCHES "#cmakedefine[ \t]+SD_PAIRWISE_TYPES_GEN")
|
||||
set(SD_PAIRWISE_TYPES_GEN 1)
|
||||
endif()
|
||||
if(original_content MATCHES "#cmakedefine[ \t]+SD_SEMANTIC_TYPES_GEN")
|
||||
set(SD_SEMANTIC_TYPES_GEN 1)
|
||||
endif()
|
||||
|
||||
# Manual string replacement instead of configure_file
|
||||
set(processed_content "${original_content}")
|
||||
|
||||
# Replace @variable@ patterns
|
||||
string(REPLACE "@FL_TYPE_INDEX@" "${FL_TYPE_INDEX}" processed_content "${processed_content}")
|
||||
string(REPLACE "@TYPE_INDEX_1@" "${TYPE_INDEX_1}" processed_content "${processed_content}")
|
||||
string(REPLACE "@TYPE_INDEX_2@" "${TYPE_INDEX_2}" processed_content "${processed_content}")
|
||||
string(REPLACE "@TYPE_INDEX_3@" "${TYPE_INDEX_3}" processed_content "${processed_content}")
|
||||
|
||||
# Process #cmakedefine directives
|
||||
if(SD_COMMON_TYPES_GEN)
|
||||
string(REPLACE "#cmakedefine SD_COMMON_TYPES_GEN" "#define SD_COMMON_TYPES_GEN" processed_content "${processed_content}")
|
||||
else()
|
||||
string(REPLACE "#cmakedefine SD_COMMON_TYPES_GEN" "/* #undef SD_COMMON_TYPES_GEN */" processed_content "${processed_content}")
|
||||
endif()
|
||||
|
||||
if(SD_FLOAT_TYPES_GEN)
|
||||
string(REPLACE "#cmakedefine SD_FLOAT_TYPES_GEN" "#define SD_FLOAT_TYPES_GEN" processed_content "${processed_content}")
|
||||
else()
|
||||
string(REPLACE "#cmakedefine SD_FLOAT_TYPES_GEN" "/* #undef SD_FLOAT_TYPES_GEN */" processed_content "${processed_content}")
|
||||
endif()
|
||||
|
||||
if(SD_INTEGER_TYPES_GEN)
|
||||
string(REPLACE "#cmakedefine SD_INTEGER_TYPES_GEN" "#define SD_INTEGER_TYPES_GEN" processed_content "${processed_content}")
|
||||
else()
|
||||
string(REPLACE "#cmakedefine SD_INTEGER_TYPES_GEN" "/* #undef SD_INTEGER_TYPES_GEN */" processed_content "${processed_content}")
|
||||
endif()
|
||||
|
||||
if(SD_PAIRWISE_TYPES_GEN)
|
||||
string(REPLACE "#cmakedefine SD_PAIRWISE_TYPES_GEN" "#define SD_PAIRWISE_TYPES_GEN" processed_content "${processed_content}")
|
||||
else()
|
||||
string(REPLACE "#cmakedefine SD_PAIRWISE_TYPES_GEN" "/* #undef SD_PAIRWISE_TYPES_GEN */" processed_content "${processed_content}")
|
||||
endif()
|
||||
|
||||
if(SD_SEMANTIC_TYPES_GEN)
|
||||
string(REPLACE "#cmakedefine SD_SEMANTIC_TYPES_GEN" "#define SD_SEMANTIC_TYPES_GEN" processed_content "${processed_content}")
|
||||
else()
|
||||
string(REPLACE "#cmakedefine SD_SEMANTIC_TYPES_GEN" "/* #undef SD_SEMANTIC_TYPES_GEN */" processed_content "${processed_content}")
|
||||
endif()
|
||||
|
||||
# Validation - check that processing worked
|
||||
if(processed_content MATCHES "@[A-Za-z_]+@")
|
||||
message(WARNING "Template processing failed for ${template_file} with indices ${comb1},${comb2},${comb3} - unresolved variables remain")
|
||||
set(${result_var} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(processed_content MATCHES "#cmakedefine[ \t]+[A-Za-z_]+")
|
||||
message(WARNING "CMakeDefine processing failed for ${template_file} with indices ${comb1},${comb2},${comb3} - unresolved directives remain")
|
||||
set(${result_var} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(${result_var} "${processed_content}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Process template with type combinations and include deduplication
|
||||
function(process_template_with_combinations template_file combination_type combinations result_var)
|
||||
if(NOT EXISTS "${template_file}")
|
||||
set(${result_var} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(all_content "")
|
||||
get_filename_component(template_name ${template_file} NAME_WE)
|
||||
|
||||
# Detect if this is a single-type template
|
||||
file(READ "${template_file}" template_content)
|
||||
set(is_single_type_template FALSE)
|
||||
|
||||
if(template_content MATCHES "@FL_TYPE_INDEX@" AND
|
||||
NOT template_content MATCHES "@TYPE_INDEX_[23]@|@COMB[23]@")
|
||||
set(is_single_type_template TRUE)
|
||||
message(STATUS "📋 Detected single-type template: ${template_name}")
|
||||
endif()
|
||||
|
||||
if(is_single_type_template)
|
||||
# Single-type processing: Extract all unique type indices and process each individually
|
||||
set(unique_indices "")
|
||||
|
||||
foreach(combination ${combinations})
|
||||
string(REPLACE "," ";" comb_list "${combination}")
|
||||
foreach(index ${comb_list})
|
||||
list(FIND unique_indices ${index} found_pos)
|
||||
if(found_pos EQUAL -1)
|
||||
list(APPEND unique_indices ${index})
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
list(SORT unique_indices COMPARE NATURAL)
|
||||
message(STATUS "🔢 Processing ${template_name} with individual indices: ${unique_indices}")
|
||||
|
||||
# Process each unique index individually
|
||||
foreach(index ${unique_indices})
|
||||
# For single-type templates, use the index for all three parameters
|
||||
process_single_template_instance("${template_file}" ${index} ${index} ${index} instance_content)
|
||||
|
||||
if(NOT instance_content STREQUAL "")
|
||||
# Extract includes and content separately
|
||||
extract_and_deduplicate_includes("${instance_content}" extracted_includes content_only)
|
||||
|
||||
# Add includes to global set
|
||||
add_includes_to_global_set("${extracted_includes}")
|
||||
|
||||
# Only append the content without includes
|
||||
string(APPEND all_content "// === ${template_name}_${index}.cpp ===\n")
|
||||
string(APPEND all_content "${content_only}")
|
||||
string(APPEND all_content "// === End ${template_name}_${index}.cpp ===\n\n")
|
||||
|
||||
# Verify float16 instantiation
|
||||
if(index EQUAL 3)
|
||||
if(instance_content MATCHES "SD_COMMON_TYPES_3")
|
||||
message(STATUS "✅ Float16 ${template_name} instantiation generated (index ${index})")
|
||||
else()
|
||||
message(WARNING "⚠️ Float16 ${template_name} instantiation incomplete")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
else()
|
||||
# Multi-type processing: Original logic for templates that actually use multiple types
|
||||
message(STATUS "📋 Processing multi-type template: ${template_name}")
|
||||
|
||||
foreach(combination ${combinations})
|
||||
string(REPLACE "," ";" comb_list "${combination}")
|
||||
list(LENGTH comb_list comb_count)
|
||||
|
||||
# Validate combination format
|
||||
if(NOT ((combination_type EQUAL 3 AND comb_count EQUAL 3) OR
|
||||
(combination_type EQUAL 2 AND comb_count EQUAL 2)))
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Extract combination indices
|
||||
if(combination_type EQUAL 3)
|
||||
list(GET comb_list 0 comb1)
|
||||
list(GET comb_list 1 comb2)
|
||||
list(GET comb_list 2 comb3)
|
||||
set(file_suffix "${comb1}_${comb2}_${comb3}")
|
||||
else()
|
||||
list(GET comb_list 0 comb1)
|
||||
list(GET comb_list 1 comb2)
|
||||
set(comb3 ${comb1})
|
||||
set(file_suffix "${comb1}_${comb2}")
|
||||
endif()
|
||||
|
||||
# Validate indices
|
||||
if(DEFINED SD_COMMON_TYPES_COUNT)
|
||||
math(EXPR max_index "${SD_COMMON_TYPES_COUNT} - 1")
|
||||
if(comb1 GREATER max_index OR comb2 GREATER max_index OR comb3 GREATER max_index)
|
||||
continue()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Process the multi-type template
|
||||
process_single_template_instance("${template_file}" ${comb1} ${comb2} ${comb3} instance_content)
|
||||
|
||||
if(NOT instance_content STREQUAL "")
|
||||
# Extract includes and content separately
|
||||
extract_and_deduplicate_includes("${instance_content}" extracted_includes content_only)
|
||||
|
||||
# Add includes to global set
|
||||
add_includes_to_global_set("${extracted_includes}")
|
||||
|
||||
# Only append the content without includes
|
||||
string(APPEND all_content "// === ${template_name}_${file_suffix}.cpp ===\n")
|
||||
string(APPEND all_content "${content_only}")
|
||||
string(APPEND all_content "// === End ${template_name}_${file_suffix}.cpp ===\n\n")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set(${result_var} "${all_content}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Detect template requirements
|
||||
function(detect_template_requirements template_file needs_2_type_var needs_3_type_var)
|
||||
file(READ "${template_file}" template_content)
|
||||
|
||||
set(needs_2_type FALSE)
|
||||
set(needs_3_type FALSE)
|
||||
|
||||
if(template_content MATCHES "TYPE_INDEX_3|COMB3|_template_3")
|
||||
set(needs_3_type TRUE)
|
||||
endif()
|
||||
|
||||
if(template_content MATCHES "TYPE_INDEX_2|COMB2|_template_2")
|
||||
set(needs_2_type TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT needs_2_type AND NOT needs_3_type)
|
||||
get_filename_component(template_name "${template_file}" NAME)
|
||||
if(template_name MATCHES "_3\\.")
|
||||
set(needs_3_type TRUE)
|
||||
elseif(template_name MATCHES "_2\\.")
|
||||
set(needs_2_type TRUE)
|
||||
else()
|
||||
set(needs_2_type TRUE)
|
||||
set(needs_3_type TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(${needs_2_type_var} ${needs_2_type} PARENT_SCOPE)
|
||||
set(${needs_3_type_var} ${needs_3_type} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Process a batch of templates into one concatenated unit
|
||||
function(process_concatenated_unit unit_index template_files)
|
||||
# Clear global includes for this unit
|
||||
set(GLOBAL_INCLUDES_SET "" CACHE INTERNAL "Set of unique includes")
|
||||
set(GLOBAL_INCLUDES_LIST "" CACHE INTERNAL "Ordered list of unique includes")
|
||||
|
||||
set(output_dir "${CMAKE_BINARY_DIR}")
|
||||
set(final_unit_file "${output_dir}/concatenated_unit_${unit_index}.cpp")
|
||||
|
||||
string(TIMESTAMP current_time "%Y-%m-%d %H:%M:%S")
|
||||
set(unit_content_body "")
|
||||
|
||||
foreach(template_file ${template_files})
|
||||
get_filename_component(template_name ${template_file} NAME_WE)
|
||||
message(STATUS " Processing template: ${template_name}")
|
||||
|
||||
# Detect template requirements
|
||||
detect_template_requirements("${template_file}" needs_2_type needs_3_type)
|
||||
|
||||
# Process with 3-type combinations if needed
|
||||
if(needs_3_type AND COMBINATIONS_3)
|
||||
process_template_with_combinations("${template_file}" 3 "${COMBINATIONS_3}" template_content)
|
||||
string(APPEND unit_content_body "${template_content}")
|
||||
endif()
|
||||
|
||||
# Process with 2-type combinations if needed
|
||||
if(needs_2_type AND COMBINATIONS_2)
|
||||
process_template_with_combinations("${template_file}" 2 "${COMBINATIONS_2}" template_content)
|
||||
string(APPEND unit_content_body "${template_content}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Generate the consolidated includes section
|
||||
generate_includes_section(includes_section)
|
||||
|
||||
# Combine everything with proper structure
|
||||
set(final_content "/*\n * Concatenated Compilation Unit ${unit_index}\n * Generated: ${current_time}\n */\n\n")
|
||||
string(APPEND final_content "${includes_section}")
|
||||
string(APPEND final_content "/*\n * Template Implementations\n */\n\n")
|
||||
string(APPEND final_content "${unit_content_body}")
|
||||
|
||||
file(WRITE "${final_unit_file}" "${final_content}")
|
||||
list(APPEND CONCATENATED_SOURCES "${final_unit_file}")
|
||||
set(CONCATENATED_SOURCES ${CONCATENATED_SOURCES} PARENT_SCOPE)
|
||||
|
||||
# Report deduplication statistics
|
||||
list(LENGTH GLOBAL_INCLUDES_LIST total_unique_includes)
|
||||
message(STATUS "✅ Created concatenated_unit_${unit_index}.cpp with ${total_unique_includes} unique includes")
|
||||
endfunction()
|
||||
|
||||
# Main function to concatenate and process compilation units
|
||||
function(concatenate_and_process_compilation_units target_count)
|
||||
message(STATUS "=== CONCATENATING AND PROCESSING COMPILATION UNITS ===")
|
||||
|
||||
# Find all template files
|
||||
file(GLOB_RECURSE ALL_TEMPLATE_FILES
|
||||
"${CMAKE_SOURCE_DIR}/include/ops/declarable/helpers/cpu/compilation_units/*.cpp.in"
|
||||
"${CMAKE_SOURCE_DIR}/include/loops/cpu/compilation_units/*.cpp.in"
|
||||
"${CMAKE_SOURCE_DIR}/include/loops/cpu/comb_compilation_units/*.cpp.in"
|
||||
"${CMAKE_SOURCE_DIR}/include/helpers/cpu/loops/*.cpp.in"
|
||||
)
|
||||
|
||||
list(LENGTH ALL_TEMPLATE_FILES total_files)
|
||||
if(total_files EQUAL 0)
|
||||
message(FATAL_ERROR "❌ No template files found to process!")
|
||||
endif()
|
||||
|
||||
math(EXPR files_per_unit "(${total_files} + ${target_count} - 1) / ${target_count}")
|
||||
message(STATUS "📊 Processing ${total_files} templates into ${target_count} units with include deduplication")
|
||||
|
||||
# Ensure we have combinations
|
||||
if(NOT DEFINED COMBINATIONS_2 OR NOT DEFINED COMBINATIONS_3)
|
||||
message(FATAL_ERROR "❌ Type combinations not initialized!")
|
||||
endif()
|
||||
|
||||
list(LENGTH COMBINATIONS_2 combo2_count)
|
||||
list(LENGTH COMBINATIONS_3 combo3_count)
|
||||
message(STATUS "Using ${combo2_count} 2-type and ${combo3_count} 3-type combinations")
|
||||
|
||||
# Create concatenated units
|
||||
set(unit_index 0)
|
||||
set(files_in_current_unit 0)
|
||||
set(current_unit_files "")
|
||||
|
||||
foreach(template_file ${ALL_TEMPLATE_FILES})
|
||||
list(APPEND current_unit_files ${template_file})
|
||||
math(EXPR files_in_current_unit "${files_in_current_unit} + 1")
|
||||
|
||||
if(files_in_current_unit GREATER_EQUAL files_per_unit)
|
||||
process_concatenated_unit(${unit_index} "${current_unit_files}")
|
||||
set(current_unit_files "")
|
||||
set(files_in_current_unit 0)
|
||||
math(EXPR unit_index "${unit_index} + 1")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Handle remaining files
|
||||
if(NOT current_unit_files STREQUAL "")
|
||||
process_concatenated_unit(${unit_index} "${current_unit_files}")
|
||||
endif()
|
||||
|
||||
message(STATUS "✅ Created concatenated compilation units with deduplicated includes")
|
||||
set(CONCATENATED_SOURCES ${CONCATENATED_SOURCES} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
|
||||
# Main entry point
|
||||
function(create_4gb_safe_concatenated_units)
|
||||
message(STATUS "🔧 Creating concatenated compilation units with include deduplication...")
|
||||
|
||||
set(TARGET_UNITS 4)
|
||||
|
||||
if(NOT DEFINED COMBINATIONS_2 OR NOT DEFINED COMBINATIONS_3)
|
||||
message(STATUS "Initializing dynamic combinations...")
|
||||
initialize_dynamic_combinations()
|
||||
endif()
|
||||
|
||||
# Debug output
|
||||
list(LENGTH COMBINATIONS_2 combo2_count)
|
||||
list(LENGTH COMBINATIONS_3 combo3_count)
|
||||
if(combo2_count GREATER 0)
|
||||
list(GET COMBINATIONS_2 0 first_combo2)
|
||||
message(STATUS "Debug: First 2-type combination: ${first_combo2}")
|
||||
endif()
|
||||
if(combo3_count GREATER 0)
|
||||
list(GET COMBINATIONS_3 0 first_combo3)
|
||||
message(STATUS "Debug: First 3-type combination: ${first_combo3}")
|
||||
endif()
|
||||
|
||||
concatenate_and_process_compilation_units(${TARGET_UNITS})
|
||||
|
||||
if(DEFINED CONCATENATED_SOURCES)
|
||||
list(LENGTH CONCATENATED_SOURCES unit_count)
|
||||
message(STATUS "📊 Created ${unit_count} concatenated units with deduplicated includes")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Clean up existing units
|
||||
function(clean_concatenated_units)
|
||||
file(GLOB existing_units "${CMAKE_BINARY_DIR}/concatenated_unit_*.cpp")
|
||||
if(existing_units)
|
||||
file(REMOVE ${existing_units})
|
||||
list(LENGTH existing_units removed_count)
|
||||
message(STATUS "🗑️ Cleaned up ${removed_count} existing concatenated units")
|
||||
endif()
|
||||
|
||||
# Clean up any temp processing files
|
||||
file(GLOB temp_files "${CMAKE_BINARY_DIR}/temp_*.cpp*")
|
||||
if(temp_files)
|
||||
file(REMOVE ${temp_files})
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -0,0 +1,69 @@
|
||||
# FindARMCOMPUTE.cmake
|
||||
# Find ARM Compute Library includes and libraries
|
||||
#
|
||||
# Sets the following variables:
|
||||
# ARMCOMPUTE_FOUND - True if ARM Compute Library was found
|
||||
# ARMCOMPUTE_INCLUDE - Path to ARM Compute Library include directory
|
||||
# ARMCOMPUTE_LIBRARIES - ARM Compute Library libraries to link against
|
||||
#
|
||||
# This module will look for ARM Compute Library in standard locations and
|
||||
# in the directory specified by the ARMCOMPUTE_ROOT variable.
|
||||
|
||||
# Find include directory
|
||||
find_path(ARMCOMPUTE_INCLUDE
|
||||
NAMES arm_compute/core/CL/CLKernelLibrary.h
|
||||
PATHS
|
||||
${ARMCOMPUTE_ROOT}
|
||||
${ARMCOMPUTE_ROOT}/include
|
||||
ENV ARMCOMPUTE_ROOT
|
||||
ENV ARMCOMPUTE_PATH
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
REQUIRED
|
||||
)
|
||||
|
||||
# Find library files
|
||||
find_library(ARMCOMPUTE_CORE_LIBRARY
|
||||
NAMES arm_compute_core-static arm_compute_core
|
||||
PATHS
|
||||
${ARMCOMPUTE_ROOT}
|
||||
${ARMCOMPUTE_ROOT}/lib
|
||||
${ARMCOMPUTE_ROOT}/build
|
||||
ENV ARMCOMPUTE_ROOT
|
||||
ENV ARMCOMPUTE_PATH
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
REQUIRED
|
||||
)
|
||||
|
||||
find_library(ARMCOMPUTE_LIBRARY
|
||||
NAMES arm_compute-static arm_compute
|
||||
PATHS
|
||||
${ARMCOMPUTE_ROOT}
|
||||
${ARMCOMPUTE_ROOT}/lib
|
||||
${ARMCOMPUTE_ROOT}/build
|
||||
ENV ARMCOMPUTE_ROOT
|
||||
ENV ARMCOMPUTE_PATH
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
REQUIRED
|
||||
)
|
||||
|
||||
# Set libraries variable
|
||||
set(ARMCOMPUTE_LIBRARIES ${ARMCOMPUTE_LIBRARY} ${ARMCOMPUTE_CORE_LIBRARY})
|
||||
|
||||
# Handle the QUIETLY and REQUIRED arguments
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ARMCOMPUTE
|
||||
DEFAULT_MSG
|
||||
ARMCOMPUTE_INCLUDE
|
||||
ARMCOMPUTE_LIBRARIES
|
||||
)
|
||||
|
||||
# Mark as advanced
|
||||
mark_as_advanced(
|
||||
ARMCOMPUTE_INCLUDE
|
||||
ARMCOMPUTE_LIBRARY
|
||||
ARMCOMPUTE_CORE_LIBRARY
|
||||
ARMCOMPUTE_LIBRARIES
|
||||
)
|
||||
@@ -0,0 +1,100 @@
|
||||
# - Find Dwarf
|
||||
# Find the dwarf.h header from elf utils
|
||||
#
|
||||
# DWARF_INCLUDE_DIR - where to find dwarf.h, etc.
|
||||
# DWARF_LIBRARIES - List of libraries when using elf utils.
|
||||
# DWARF_FOUND - True if fdo found.
|
||||
|
||||
message(STATUS "Checking availability of DWARF and ELF development libraries")
|
||||
|
||||
INCLUDE(CheckLibraryExists)
|
||||
|
||||
if (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR AND DWARF_LIBRARY AND ELF_LIBRARY)
|
||||
# Already in cache, be silent
|
||||
set(DWARF_FIND_QUIETLY TRUE)
|
||||
endif (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR AND DWARF_LIBRARY AND ELF_LIBRARY)
|
||||
|
||||
find_path(DWARF_INCLUDE_DIR dwarf.h
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/usr/include/libdwarf
|
||||
~/usr/local/include
|
||||
)
|
||||
|
||||
find_path(LIBDW_INCLUDE_DIR elfutils/libdw.h
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
~/usr/local/include
|
||||
)
|
||||
|
||||
find_library(DWARF_LIBRARY
|
||||
NAMES dw dwarf
|
||||
PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 ~/usr/local/lib ~/usr/local/lib64
|
||||
)
|
||||
|
||||
find_library(ELF_LIBRARY
|
||||
NAMES elf
|
||||
PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 ~/usr/local/lib ~/usr/local/lib64
|
||||
)
|
||||
|
||||
if (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR AND DWARF_LIBRARY AND ELF_LIBRARY)
|
||||
set(DWARF_FOUND TRUE)
|
||||
set(DWARF_LIBRARIES ${DWARF_LIBRARY} ${ELF_LIBRARY})
|
||||
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${DWARF_LIBRARIES})
|
||||
# check if libdw have the dwfl_module_build_id routine, i.e. if it supports the buildid
|
||||
# mechanism to match binaries to detached debug info sections (the -debuginfo packages
|
||||
# in distributions such as fedora). We do it against libelf because, IIRC, some distros
|
||||
# include libdw linked statically into libelf.
|
||||
check_library_exists(elf dwfl_module_build_id "" HAVE_DWFL_MODULE_BUILD_ID)
|
||||
else (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR AND DWARF_LIBRARY AND ELF_LIBRARY)
|
||||
set(DWARF_FOUND FALSE)
|
||||
set(DWARF_LIBRARIES)
|
||||
endif (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR AND DWARF_LIBRARY AND ELF_LIBRARY)
|
||||
|
||||
if (DWARF_FOUND)
|
||||
if (NOT DWARF_FIND_QUIETLY)
|
||||
message(STATUS "Found dwarf.h header: ${DWARF_INCLUDE_DIR}")
|
||||
message(STATUS "Found elfutils/libdw.h header: ${LIBDW_INCLUDE_DIR}")
|
||||
message(STATUS "Found libdw library: ${DWARF_LIBRARY}")
|
||||
message(STATUS "Found libelf library: ${ELF_LIBRARY}")
|
||||
endif (NOT DWARF_FIND_QUIETLY)
|
||||
else (DWARF_FOUND)
|
||||
if (DWARF_FIND_REQUIRED)
|
||||
# Check if we are in a Red Hat (RHEL) or Fedora system to tell
|
||||
# exactly which packages should be installed. Please send
|
||||
# patches for other distributions.
|
||||
find_path(FEDORA fedora-release /etc)
|
||||
find_path(REDHAT redhat-release /etc)
|
||||
if (FEDORA OR REDHAT)
|
||||
if (NOT DWARF_INCLUDE_DIR OR NOT LIBDW_INCLUDE_DIR)
|
||||
message(STATUS "Please install the elfutils-devel package")
|
||||
endif (NOT DWARF_INCLUDE_DIR OR NOT LIBDW_INCLUDE_DIR)
|
||||
if (NOT DWARF_LIBRARY)
|
||||
message(STATUS "Please install the elfutils-libs package")
|
||||
endif (NOT DWARF_LIBRARY)
|
||||
if (NOT ELF_LIBRARY)
|
||||
message(STATUS "Please install the elfutils-libelf package")
|
||||
endif (NOT ELF_LIBRARY)
|
||||
else (FEDORA OR REDHAT)
|
||||
if (NOT DWARF_INCLUDE_DIR)
|
||||
message(STATUS "Could NOT find dwarf include dir")
|
||||
endif (NOT DWARF_INCLUDE_DIR)
|
||||
if (NOT LIBDW_INCLUDE_DIR)
|
||||
message(STATUS "Could NOT find libdw include dir")
|
||||
endif (NOT LIBDW_INCLUDE_DIR)
|
||||
if (NOT DWARF_LIBRARY)
|
||||
message(STATUS "Could NOT find libdw library")
|
||||
endif (NOT DWARF_LIBRARY)
|
||||
if (NOT ELF_LIBRARY)
|
||||
message(STATUS "Could NOT find libelf library")
|
||||
endif (NOT ELF_LIBRARY)
|
||||
endif (FEDORA OR REDHAT)
|
||||
message(FATAL_ERROR "Could NOT find some ELF and DWARF libraries, please install the missing packages")
|
||||
endif (DWARF_FIND_REQUIRED)
|
||||
endif (DWARF_FOUND)
|
||||
|
||||
mark_as_advanced(DWARF_INCLUDE_DIR LIBDW_INCLUDE_DIR DWARF_LIBRARY ELF_LIBRARY)
|
||||
include_directories(${DWARF_INCLUDE_DIR} ${LIBDW_INCLUDE_DIR})
|
||||
|
||||
message(STATUS "Checking availability of DWARF and ELF development libraries - done")
|
||||
@@ -0,0 +1,19 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# cmake/InstantiationCache.cmake
|
||||
# Smart caching for instantiation analysis
|
||||
|
||||
function(should_process_file SOURCE_FILE SAFE_NAME OUT_VAR)
|
||||
# Get file modification time
|
||||
file(TIMESTAMP ${SOURCE_FILE} source_mtime)
|
||||
|
||||
# Check if cached results exist
|
||||
set(cache_file "${INST_TEMP_DIR}/${SAFE_NAME}.cache")
|
||||
|
||||
if(EXISTS ${cache_file})
|
||||
# Read cache timestamp
|
||||
file(READ ${cache_file} cache_content LIMIT 100)
|
||||
string(REGEX MATCH "timestamp:([0-9]+)" _ ${cache_content})
|
||||
set(cache_time ${CMAKE_MATCH_1})
|
||||
|
||||
# Compare timestamps
|
||||
if(cache_time AND source_mtime EQUAL cache_time)
|
||||
# Cache is valid, skip processing
|
||||
set(${OUT_VAR} FALSE PARENT_SCOPE)
|
||||
|
||||
# Load cached results
|
||||
if(EXISTS ${INST_USED_DIR}/${SAFE_NAME}.used.cached)
|
||||
file(COPY ${INST_USED_DIR}/${SAFE_NAME}.used.cached
|
||||
DESTINATION ${INST_USED_DIR}
|
||||
FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
|
||||
file(RENAME ${INST_USED_DIR}/${SAFE_NAME}.used.cached
|
||||
${INST_USED_DIR}/${SAFE_NAME}.used)
|
||||
endif()
|
||||
|
||||
if(EXISTS ${INST_PROVIDED_DIR}/${SAFE_NAME}.provided.cached)
|
||||
file(COPY ${INST_PROVIDED_DIR}/${SAFE_NAME}.provided.cached
|
||||
DESTINATION ${INST_PROVIDED_DIR}
|
||||
FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
|
||||
file(RENAME ${INST_PROVIDED_DIR}/${SAFE_NAME}.provided.cached
|
||||
${INST_PROVIDED_DIR}/${SAFE_NAME}.provided)
|
||||
endif()
|
||||
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Need to process this file
|
||||
set(${OUT_VAR} TRUE PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(cache_analysis_results SOURCE_FILE SAFE_NAME)
|
||||
file(TIMESTAMP ${SOURCE_FILE} source_mtime)
|
||||
|
||||
# Write cache marker
|
||||
set(cache_file "${INST_TEMP_DIR}/${SAFE_NAME}.cache")
|
||||
file(WRITE ${cache_file} "timestamp:${source_mtime}\n")
|
||||
|
||||
# Cache the analysis results
|
||||
if(EXISTS ${INST_USED_DIR}/${SAFE_NAME}.used)
|
||||
file(COPY ${INST_USED_DIR}/${SAFE_NAME}.used
|
||||
DESTINATION ${INST_USED_DIR}
|
||||
FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
|
||||
file(RENAME ${INST_USED_DIR}/${SAFE_NAME}.used
|
||||
${INST_USED_DIR}/${SAFE_NAME}.used.cached)
|
||||
endif()
|
||||
|
||||
if(EXISTS ${INST_PROVIDED_DIR}/${SAFE_NAME}.provided)
|
||||
file(COPY ${INST_PROVIDED_DIR}/${SAFE_NAME}.provided
|
||||
DESTINATION ${INST_PROVIDED_DIR}
|
||||
FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
|
||||
file(RENAME ${INST_PROVIDED_DIR}/${SAFE_NAME}.provided
|
||||
${INST_PROVIDED_DIR}/${SAFE_NAME}.provided.cached)
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -0,0 +1,612 @@
|
||||
# cmake/InstantiationHelpers.cmake
|
||||
# Helper functions for template instantiation extraction
|
||||
|
||||
# Function to setup compilation flags for instantiation extraction
|
||||
function(setup_instantiation_flags)
|
||||
# FIRST: Setup FlatBuffers EXACTLY like PostBuild.cmake does
|
||||
set(PREPROCESS_FLATBUFFERS_VERSION "25.2.10")
|
||||
set(PREPROCESS_FLATBUFFERS_URL "https://github.com/google/flatbuffers/archive/v${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz")
|
||||
set(PREPROCESS_FB_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/preprocess-flatbuffers-src")
|
||||
|
||||
# Check if we already have FlatBuffers headers
|
||||
set(PREPROCESS_FB_HEADER "${PREPROCESS_FB_SOURCE_DIR}/include/flatbuffers/flatbuffers.h")
|
||||
if(NOT EXISTS ${PREPROCESS_FB_HEADER})
|
||||
message("Downloading and extracting FlatBuffers for instantiation analysis...")
|
||||
|
||||
# Download and extract FlatBuffers
|
||||
file(DOWNLOAD ${PREPROCESS_FLATBUFFERS_URL}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz"
|
||||
SHOW_PROGRESS
|
||||
STATUS download_status)
|
||||
|
||||
list(GET download_status 0 download_result)
|
||||
if(NOT download_result EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to download FlatBuffers for instantiation analysis")
|
||||
endif()
|
||||
|
||||
# Extract the archive
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E tar xzf "flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
RESULT_VARIABLE extract_result
|
||||
)
|
||||
|
||||
if(NOT extract_result EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to extract FlatBuffers for instantiation analysis")
|
||||
endif()
|
||||
|
||||
# Move the extracted directory to our expected location
|
||||
file(RENAME "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}"
|
||||
"${PREPROCESS_FB_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
# NOW COPY THE EXACT INCLUDE SETUP FROM PostBuild.cmake
|
||||
# Get ALL subdirectories under include/ and add the root include directory first
|
||||
set(all_includes "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
file(GLOB_RECURSE all_dirs LIST_DIRECTORIES true "${CMAKE_CURRENT_SOURCE_DIR}/include/*")
|
||||
foreach(item ${all_dirs})
|
||||
if(IS_DIRECTORY ${item})
|
||||
list(APPEND all_includes ${item})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Add binary include directory
|
||||
list(APPEND all_includes "${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||
|
||||
# Also add build directories - EXACTLY AS IN PostBuild.cmake
|
||||
list(APPEND all_includes
|
||||
"${CMAKE_SOURCE_DIR}/include/"
|
||||
"${CMAKE_SOURCE_DIR}/include/system"
|
||||
"${CMAKE_BINARY_DIR}/compilation_units"
|
||||
"${CMAKE_BINARY_DIR}/cpu_instantiations"
|
||||
"${CMAKE_BINARY_DIR}/cuda_instantiations"
|
||||
"${CMAKE_BINARY_DIR}/include"
|
||||
)
|
||||
|
||||
# Add our self-contained FlatBuffers include directory - EXACTLY AS IN PostBuild.cmake
|
||||
list(APPEND all_includes "${PREPROCESS_FB_SOURCE_DIR}/include")
|
||||
|
||||
# Build include flags string
|
||||
set(include_flags "")
|
||||
foreach(dir IN LISTS all_includes)
|
||||
if(EXISTS ${dir})
|
||||
string(APPEND include_flags " -I${dir}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(defs_flags "")
|
||||
|
||||
# Add basic platform definitions
|
||||
string(APPEND defs_flags " -D__CPUBLAS__=true")
|
||||
if(SD_CUDA)
|
||||
string(APPEND defs_flags " -D__CUDABLAS__=true -DHAVE_CUDA=1")
|
||||
endif()
|
||||
if(HAVE_OPENBLAS)
|
||||
string(APPEND defs_flags " -DHAVE_OPENBLAS=1")
|
||||
endif()
|
||||
|
||||
if(SD_ALL_OPS OR "${SD_OPS_LIST}" STREQUAL "")
|
||||
string(APPEND defs_flags " -DSD_ALL_OPS=1")
|
||||
# When SD_ALL_OPS=1, NOT_EXCLUDED should evaluate to 1 for all ops
|
||||
string(APPEND defs_flags " -DNOT_EXCLUDED(x)=1")
|
||||
else()
|
||||
# Add specific operation definitions
|
||||
foreach(OP ${SD_OPS_LIST})
|
||||
string(APPEND defs_flags " -DOP_${OP}=1")
|
||||
endforeach()
|
||||
# Define NOT_EXCLUDED macro for selective ops
|
||||
string(APPEND defs_flags " -DNOT_EXCLUDED(x)=\\(defined\\(x\\)\\)")
|
||||
endif()
|
||||
|
||||
# Add build type definitions
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
string(APPEND defs_flags " -DDEBUG=1 -D_DEBUG=1")
|
||||
else()
|
||||
string(APPEND defs_flags " -DNDEBUG=1")
|
||||
endif()
|
||||
|
||||
# Add any additional compile definitions from the main build
|
||||
if(compile_defs AND NOT compile_defs STREQUAL "compile_defs-NOTFOUND")
|
||||
foreach(def IN LISTS compile_defs)
|
||||
string(APPEND defs_flags " -D${def}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Datatype definitions
|
||||
if(SD_TYPES_LIST)
|
||||
string(REPLACE ";" "," types_comma_list "${SD_TYPES_LIST}")
|
||||
string(APPEND defs_flags " -DSD_TYPES_LIST=\"${types_comma_list}\"")
|
||||
endif()
|
||||
|
||||
# Export to parent scope
|
||||
set(INST_INCLUDE_FLAGS ${include_flags} PARENT_SCOPE)
|
||||
set(INST_DEFS_FLAGS ${defs_flags} PARENT_SCOPE)
|
||||
set(INST_LANG_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}" PARENT_SCOPE)
|
||||
|
||||
# Find required tools
|
||||
find_program(NM_TOOL NAMES nm gcc-nm llvm-nm)
|
||||
find_program(CPPFILT_TOOL NAMES c++filt llvm-cxxfilt)
|
||||
|
||||
set(NM_TOOL ${NM_TOOL} PARENT_SCOPE)
|
||||
set(CPPFILT_TOOL ${CPPFILT_TOOL} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Function to get source list
|
||||
function(get_source_list OUT_VAR)
|
||||
if(DEFINED ALL_SOURCES AND ALL_SOURCES)
|
||||
set(${OUT_VAR} ${ALL_SOURCES} PARENT_SCOPE)
|
||||
elseif(DEFINED ALL_SOURCES_LIST AND ALL_SOURCES_LIST)
|
||||
set(${OUT_VAR} ${ALL_SOURCES_LIST} PARENT_SCOPE)
|
||||
else()
|
||||
set(${OUT_VAR} "" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to extract used templates from a source file - KEEP THE ORIGINAL WORKING VERSION
|
||||
function(extract_used_templates SOURCE_FILE OUTPUT_FILE SAFE_NAME)
|
||||
# Initialize empty result
|
||||
set(used_templates "")
|
||||
|
||||
# Check if source file exists
|
||||
if(NOT EXISTS "${SOURCE_FILE}")
|
||||
message(WARNING "Source file does not exist: ${SOURCE_FILE}")
|
||||
file(WRITE ${OUTPUT_FILE} "")
|
||||
set(EXTRACTED_USED_TEMPLATES "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Check if temp directory exists
|
||||
if(NOT EXISTS "${INST_TEMP_DIR}")
|
||||
file(MAKE_DIRECTORY "${INST_TEMP_DIR}")
|
||||
endif()
|
||||
|
||||
# Always preprocess the file to expand all macros
|
||||
set(preprocessed_file "${INST_TEMP_DIR}/${SAFE_NAME}_preprocessed.i")
|
||||
|
||||
# Determine compiler and flags based on file type
|
||||
if(SOURCE_FILE MATCHES "\\.cu$")
|
||||
set(compiler "${CMAKE_CUDA_COMPILER}")
|
||||
set(lang_flags "${CMAKE_CUDA_FLAGS} ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}}")
|
||||
elseif(SOURCE_FILE MATCHES "\\.c$")
|
||||
set(compiler "${CMAKE_C_COMPILER}")
|
||||
set(lang_flags "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}}")
|
||||
else()
|
||||
set(compiler "${CMAKE_CXX_COMPILER}")
|
||||
set(lang_flags "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}")
|
||||
endif()
|
||||
|
||||
# Check if compiler exists
|
||||
if(NOT EXISTS "${compiler}" AND NOT compiler)
|
||||
message(WARNING "Compiler not found for ${SOURCE_FILE}")
|
||||
file(WRITE ${OUTPUT_FILE} "")
|
||||
set(EXTRACTED_USED_TEMPLATES "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Preprocess the file to expand all macros - USING EXACT WORKING METHOD FROM PostBuild.cmake
|
||||
# Split the flags properly for execute_process
|
||||
separate_arguments(lang_flags_list UNIX_COMMAND "${lang_flags}")
|
||||
separate_arguments(defs_flags_list UNIX_COMMAND "${INST_DEFS_FLAGS}")
|
||||
separate_arguments(include_flags_list UNIX_COMMAND "${INST_INCLUDE_FLAGS}")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${compiler} -E -P -C ${lang_flags_list} ${defs_flags_list} ${include_flags_list} "${SOURCE_FILE}" -o "${preprocessed_file}"
|
||||
RESULT_VARIABLE preprocess_result
|
||||
ERROR_VARIABLE preprocess_errors
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
if(NOT preprocess_result EQUAL 0)
|
||||
message(WARNING "Failed to preprocess ${SOURCE_FILE}: ${preprocess_errors}")
|
||||
file(WRITE ${OUTPUT_FILE} "")
|
||||
set(EXTRACTED_USED_TEMPLATES "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ${preprocessed_file})
|
||||
message(WARNING "Preprocessed file not created for ${SOURCE_FILE}")
|
||||
file(WRITE ${OUTPUT_FILE} "")
|
||||
set(EXTRACTED_USED_TEMPLATES "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Method 1: Compile the preprocessed file with -fno-implicit-templates to find required templates
|
||||
execute_process(
|
||||
COMMAND ${compiler}
|
||||
-fsyntax-only
|
||||
-fno-implicit-templates
|
||||
-ftemplate-backtrace-limit=0
|
||||
${lang_flags}
|
||||
${INST_DEFS_FLAGS}
|
||||
${INST_INCLUDE_FLAGS}
|
||||
-x c++ # Force C++ mode since .i files might not be recognized
|
||||
${preprocessed_file}
|
||||
ERROR_VARIABLE compile_errors
|
||||
OUTPUT_QUIET
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
TIMEOUT 30
|
||||
)
|
||||
|
||||
if(compile_errors)
|
||||
# Parse undefined references from the preprocessed compilation
|
||||
string(REGEX MATCHALL "undefined reference to '[^']+'" undefined_refs "${compile_errors}")
|
||||
foreach(ref ${undefined_refs})
|
||||
string(REGEX REPLACE "undefined reference to '([^']+)'" "\\1" symbol "${ref}")
|
||||
# Filter for template instantiations
|
||||
if(symbol MATCHES ".*<.*>.*")
|
||||
# Demangle if needed
|
||||
if(symbol MATCHES "^_Z")
|
||||
if(CPPFILT_TOOL)
|
||||
execute_process(
|
||||
COMMAND ${CPPFILT_TOOL} "${symbol}"
|
||||
OUTPUT_VARIABLE demangled
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
if(demangled)
|
||||
set(symbol "${demangled}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND used_templates "${symbol}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Parse instantiation requirements
|
||||
string(REGEX MATCHALL "instantiation of '[^']+' required" inst_reqs "${compile_errors}")
|
||||
foreach(req ${inst_reqs})
|
||||
string(REGEX REPLACE "instantiation of '([^']+)' required" "\\1" tmpl "${req}")
|
||||
if(tmpl MATCHES ".*<.*>.*")
|
||||
list(APPEND used_templates "${tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Parse "error: explicit instantiation of '[^']+' but no definition available"
|
||||
string(REGEX MATCHALL "explicit instantiation of '[^']+' but no definition" missing_defs "${compile_errors}")
|
||||
foreach(def ${missing_defs})
|
||||
string(REGEX REPLACE "explicit instantiation of '([^']+)' but no definition" "\\1" tmpl "${def}")
|
||||
if(tmpl MATCHES ".*<.*>.*")
|
||||
list(APPEND used_templates "${tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Method 2: Parse the preprocessed source for template usage patterns
|
||||
file(READ ${preprocessed_file} source_content LIMIT 10485760) # Read up to 10MB
|
||||
|
||||
# Look for explicit template instantiation declarations (extern template)
|
||||
string(REGEX MATCHALL "extern[ \t]+template[ \t]+[^;]+<[^>]+>[^;]*;" extern_templates "${source_content}")
|
||||
foreach(ext_tmpl ${extern_templates})
|
||||
string(REGEX MATCH "[a-zA-Z_][a-zA-Z0-9_:]*<[^>]+>" tmpl "${ext_tmpl}")
|
||||
if(tmpl)
|
||||
list(APPEND used_templates "${tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Look for template instantiation patterns in expanded macros
|
||||
# These patterns commonly appear after macro expansion
|
||||
set(expanded_patterns
|
||||
"template[ \t]+class[ \t]+[a-zA-Z_][a-zA-Z0-9_:]*<[^>]+>"
|
||||
"template[ \t]+struct[ \t]+[a-zA-Z_][a-zA-Z0-9_:]*<[^>]+>"
|
||||
"template[ \t]+void[ \t]+[a-zA-Z_][a-zA-Z0-9_:]*<[^>]+>::[a-zA-Z_][a-zA-Z0-9_]*"
|
||||
"template[ \t]+[a-zA-Z_][a-zA-Z0-9_:]*[ \t]+[a-zA-Z_][a-zA-Z0-9_:]*<[^>]+>::[a-zA-Z_][a-zA-Z0-9_]*"
|
||||
)
|
||||
|
||||
foreach(pattern ${expanded_patterns})
|
||||
string(REGEX MATCHALL "${pattern}" matches "${source_content}")
|
||||
foreach(match ${matches})
|
||||
# Extract the template class/function signature
|
||||
string(REGEX MATCH "[a-zA-Z_][a-zA-Z0-9_:]*<[^>]+>" tmpl "${match}")
|
||||
if(tmpl)
|
||||
list(APPEND used_templates "${tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# Method 3: Look for template function calls and instantiations
|
||||
# Common template patterns that indicate usage
|
||||
set(usage_patterns
|
||||
"NDArray<[^>]+>"
|
||||
"DataBuffer<[^>]+>"
|
||||
"BroadcastHelper<[^>]+>"
|
||||
"BroadcastInt<[^>]+>"
|
||||
"BroadcastBool<[^>]+>"
|
||||
"Broadcast<[^>]+>"
|
||||
"LoopKind::Kind<[^>]+>"
|
||||
"LaunchContext<[^>]+>"
|
||||
"ResultSet<[^>]+>"
|
||||
"ShapeList<[^>]+>"
|
||||
"SpecialMethods<[^>]+>"
|
||||
"TypeCast::convertGeneric<[^>]+>"
|
||||
"PairWiseTransform<[^>]+>"
|
||||
"ScalarTransform<[^>]+>"
|
||||
"RandomFunction<[^>]+>"
|
||||
"ReduceSameFunction<[^>]+>"
|
||||
"ReduceFloatFunction<[^>]+>"
|
||||
"ReduceBoolFunction<[^>]+>"
|
||||
"ReduceLongFunction<[^>]+>"
|
||||
"Reduce3<[^>]+>"
|
||||
"IndexReduce<[^>]+>"
|
||||
"ReductionLoops<[^>]+>"
|
||||
"IndexReductionLoops<[^>]+>"
|
||||
"std::vector<[^>]+>"
|
||||
"std::unique_ptr<[^>]+>"
|
||||
"std::shared_ptr<[^>]+>"
|
||||
)
|
||||
|
||||
foreach(pattern ${usage_patterns})
|
||||
string(REGEX MATCHALL "${pattern}" matches "${source_content}")
|
||||
list(APPEND used_templates ${matches})
|
||||
endforeach()
|
||||
|
||||
# Method 4: Try to compile to object and extract undefined symbols
|
||||
set(temp_obj "${INST_TEMP_DIR}/${SAFE_NAME}_test.o")
|
||||
execute_process(
|
||||
COMMAND ${compiler}
|
||||
-c
|
||||
-o ${temp_obj}
|
||||
${lang_flags}
|
||||
${INST_DEFS_FLAGS}
|
||||
${INST_INCLUDE_FLAGS}
|
||||
-x c++
|
||||
${preprocessed_file}
|
||||
ERROR_VARIABLE obj_errors
|
||||
OUTPUT_QUIET
|
||||
RESULT_VARIABLE obj_result
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
TIMEOUT 30
|
||||
)
|
||||
|
||||
# Extract undefined symbols from linker errors
|
||||
if(obj_errors)
|
||||
string(REGEX MATCHALL "undefined reference to `[^']+'" undef_symbols "${obj_errors}")
|
||||
foreach(symbol ${undef_symbols})
|
||||
string(REGEX REPLACE "undefined reference to `([^']+)'" "\\1" sym "${symbol}")
|
||||
if(sym MATCHES ".*<.*>.*")
|
||||
# Try to demangle if it's mangled
|
||||
if(sym MATCHES "^_Z" AND CPPFILT_TOOL)
|
||||
execute_process(
|
||||
COMMAND ${CPPFILT_TOOL} "${sym}"
|
||||
OUTPUT_VARIABLE demangled
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
if(demangled)
|
||||
set(sym "${demangled}")
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND used_templates "${sym}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# If object was created, also check with nm for undefined symbols
|
||||
if(obj_result EQUAL 0 AND EXISTS ${temp_obj} AND NM_TOOL)
|
||||
execute_process(
|
||||
COMMAND ${NM_TOOL} -u ${temp_obj}
|
||||
OUTPUT_VARIABLE nm_undefined
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
if(nm_undefined)
|
||||
string(REGEX MATCHALL "_Z[A-Za-z0-9_]+" mangled_symbols "${nm_undefined}")
|
||||
foreach(mangled ${mangled_symbols})
|
||||
if(CPPFILT_TOOL)
|
||||
execute_process(
|
||||
COMMAND ${CPPFILT_TOOL} ${mangled}
|
||||
OUTPUT_VARIABLE demangled
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
if(demangled AND demangled MATCHES ".*<.*>.*")
|
||||
list(APPEND used_templates "${demangled}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
file(REMOVE ${temp_obj})
|
||||
endif()
|
||||
|
||||
# Clean up preprocessed file
|
||||
file(REMOVE ${preprocessed_file})
|
||||
|
||||
# Remove duplicates and filter out noise
|
||||
if(used_templates)
|
||||
list(REMOVE_DUPLICATES used_templates)
|
||||
|
||||
# Filter out standard library internals and compiler intrinsics
|
||||
set(filtered_templates "")
|
||||
foreach(tmpl ${used_templates})
|
||||
if(NOT tmpl MATCHES "^__" AND
|
||||
NOT tmpl MATCHES "^std::__" AND
|
||||
NOT tmpl MATCHES "^__gnu" AND
|
||||
NOT tmpl MATCHES "^__builtin" AND
|
||||
NOT tmpl MATCHES "^operator")
|
||||
list(APPEND filtered_templates "${tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
string(REPLACE ";" "\n" used_content "${filtered_templates}")
|
||||
file(WRITE ${OUTPUT_FILE} "${used_content}")
|
||||
set(EXTRACTED_USED_TEMPLATES ${filtered_templates} PARENT_SCOPE)
|
||||
else()
|
||||
file(WRITE ${OUTPUT_FILE} "")
|
||||
set(EXTRACTED_USED_TEMPLATES "" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(extract_provided_templates SOURCE_FILE OUTPUT_FILE SAFE_NAME)
|
||||
set(provided_templates "")
|
||||
|
||||
# Check if source file exists
|
||||
if(NOT EXISTS "${SOURCE_FILE}")
|
||||
message(WARNING "Source file does not exist: ${SOURCE_FILE}")
|
||||
file(WRITE ${OUTPUT_FILE} "")
|
||||
set(EXTRACTED_PROVIDED_TEMPLATES "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Check if temp directory exists
|
||||
if(NOT EXISTS "${INST_TEMP_DIR}")
|
||||
file(MAKE_DIRECTORY "${INST_TEMP_DIR}")
|
||||
endif()
|
||||
|
||||
# Method 1: Check for explicit instantiations in source
|
||||
file(READ ${SOURCE_FILE} source_content LIMIT 1048576)
|
||||
|
||||
string(REGEX MATCHALL "template[ \t]+class[ \t]+[^;]+<[^>]+>[^;]*;"
|
||||
explicit_class "${source_content}")
|
||||
string(REGEX MATCHALL "template[ \t]+struct[ \t]+[^;]+<[^>]+>[^;]*;"
|
||||
explicit_struct "${source_content}")
|
||||
|
||||
foreach(inst ${explicit_class} ${explicit_struct})
|
||||
string(REGEX MATCH "[a-zA-Z_][a-zA-Z0-9_]*<[^>]+>" tmpl "${inst}")
|
||||
if(tmpl)
|
||||
list(APPEND provided_templates "${tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Method 2: Compile to object and extract symbols
|
||||
set(temp_obj "${INST_TEMP_DIR}/${SAFE_NAME}.o")
|
||||
|
||||
# Determine compiler based on file type
|
||||
if(SOURCE_FILE MATCHES "\\.cu$")
|
||||
set(compiler "${CMAKE_CUDA_COMPILER}")
|
||||
elseif(SOURCE_FILE MATCHES "\\.c$")
|
||||
set(compiler "${CMAKE_C_COMPILER}")
|
||||
else()
|
||||
set(compiler "${CMAKE_CXX_COMPILER}")
|
||||
endif()
|
||||
|
||||
# Check if compiler exists
|
||||
if(NOT EXISTS "${compiler}" AND NOT compiler)
|
||||
message(WARNING "Compiler not found for ${SOURCE_FILE}")
|
||||
# Still write what we found from method 1
|
||||
if(provided_templates)
|
||||
list(REMOVE_DUPLICATES provided_templates)
|
||||
string(REPLACE ";" "\n" provided_content "${provided_templates}")
|
||||
file(WRITE ${OUTPUT_FILE} "${provided_content}")
|
||||
set(EXTRACTED_PROVIDED_TEMPLATES ${provided_templates} PARENT_SCOPE)
|
||||
else()
|
||||
file(WRITE ${OUTPUT_FILE} "")
|
||||
set(EXTRACTED_PROVIDED_TEMPLATES "" PARENT_SCOPE)
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${compiler}
|
||||
-c
|
||||
-o ${temp_obj}
|
||||
${INST_LANG_FLAGS}
|
||||
${INST_DEFS_FLAGS}
|
||||
${INST_INCLUDE_FLAGS}
|
||||
${SOURCE_FILE}
|
||||
ERROR_QUIET
|
||||
OUTPUT_QUIET
|
||||
RESULT_VARIABLE compile_result
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
|
||||
if(compile_result EQUAL 0 AND EXISTS ${temp_obj})
|
||||
if(NM_TOOL AND CPPFILT_TOOL)
|
||||
# Extract defined symbols
|
||||
execute_process(
|
||||
COMMAND ${NM_TOOL} --defined-only ${temp_obj}
|
||||
OUTPUT_VARIABLE nm_output
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
if(nm_output)
|
||||
# Extract and demangle template symbols
|
||||
string(REGEX MATCHALL "_Z[A-Za-z0-9_]+" mangled_symbols "${nm_output}")
|
||||
|
||||
foreach(mangled ${mangled_symbols})
|
||||
execute_process(
|
||||
COMMAND ${CPPFILT_TOOL} ${mangled}
|
||||
OUTPUT_VARIABLE demangled
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
if(demangled MATCHES ".*<.*>.*")
|
||||
# Filter out std:: and internal templates
|
||||
if(NOT demangled MATCHES "^std::" AND
|
||||
NOT demangled MATCHES "^__" AND
|
||||
NOT demangled MATCHES "^operator")
|
||||
list(APPEND provided_templates "${demangled}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
file(REMOVE ${temp_obj})
|
||||
endif()
|
||||
|
||||
# Method 3: Parse assembly output for template instantiations
|
||||
execute_process(
|
||||
COMMAND ${compiler}
|
||||
-S
|
||||
-o -
|
||||
-fverbose-asm
|
||||
${INST_LANG_FLAGS}
|
||||
${INST_DEFS_FLAGS}
|
||||
${INST_INCLUDE_FLAGS}
|
||||
${SOURCE_FILE}
|
||||
OUTPUT_VARIABLE asm_output
|
||||
ERROR_QUIET
|
||||
RESULT_VARIABLE asm_result
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
||||
if(asm_result EQUAL 0 AND asm_output)
|
||||
# Extract template info from assembly comments
|
||||
string(LENGTH "${asm_output}" asm_length)
|
||||
if(asm_length LESS 10000000) # Only process if under 10MB
|
||||
string(REGEX MATCHALL "#.*<[^>]+>.*" asm_templates "${asm_output}")
|
||||
foreach(comment ${asm_templates})
|
||||
string(REGEX MATCH "[a-zA-Z_][a-zA-Z0-9_]*<[^>]+>" tmpl "${comment}")
|
||||
if(tmpl AND NOT tmpl MATCHES "^std::")
|
||||
list(APPEND provided_templates "${tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Remove duplicates and write to file
|
||||
if(provided_templates)
|
||||
list(REMOVE_DUPLICATES provided_templates)
|
||||
string(REPLACE ";" "\n" provided_content "${provided_templates}")
|
||||
file(WRITE ${OUTPUT_FILE} "${provided_content}")
|
||||
set(EXTRACTED_PROVIDED_TEMPLATES ${provided_templates} PARENT_SCOPE)
|
||||
else()
|
||||
file(WRITE ${OUTPUT_FILE} "")
|
||||
set(EXTRACTED_PROVIDED_TEMPLATES "" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to normalize template names for comparison
|
||||
function(normalize_template_name TEMPLATE OUT_VAR)
|
||||
set(normalized "${TEMPLATE}")
|
||||
|
||||
# Remove extra spaces
|
||||
string(REGEX REPLACE "[ \t]+" " " normalized "${normalized}")
|
||||
string(STRIP "${normalized}" normalized)
|
||||
|
||||
# Normalize const placement
|
||||
string(REPLACE "const " "" normalized "${normalized}")
|
||||
string(REPLACE " const" "" normalized "${normalized}")
|
||||
|
||||
# Remove allocator specifications from std containers
|
||||
string(REGEX REPLACE "std::allocator<[^>]+>" "" normalized "${normalized}")
|
||||
|
||||
# Normalize pointer/reference spacing
|
||||
string(REPLACE " *" "*" normalized "${normalized}")
|
||||
string(REPLACE " &" "&" normalized "${normalized}")
|
||||
|
||||
set(${OUT_VAR} "${normalized}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
@@ -0,0 +1,853 @@
|
||||
# =============================================================================
|
||||
# UNIFIED BUILD ORCHESTRATION SCRIPT WITH CUDA TEMPLATE PARITY
|
||||
#
|
||||
# This enhanced version includes support for CUDA template processing
|
||||
# to achieve complete parity between CPU and CUDA template systems.
|
||||
# UPDATED with modern cuDNN integration
|
||||
#
|
||||
# CACHE INVALIDATION: Modified to force CMake reconfiguration after
|
||||
# PCH disabling in session #1002. Resolves Makefile2 having stale
|
||||
# progress count (99 steps) while build.make has correct count (1251 steps).
|
||||
# This inconsistency caused build to stop at 98% missing files 48-64.
|
||||
# =============================================================================
|
||||
|
||||
# =============================================================================
|
||||
# SECTION 1: HELPER FUNCTION DEFINITIONS
|
||||
# All functions are defined first to ensure they are available when called.
|
||||
# =============================================================================
|
||||
|
||||
|
||||
|
||||
# --- Helper for colored status messages ---
|
||||
function(print_status_colored type message)
|
||||
if(type STREQUAL "ERROR")
|
||||
message(FATAL_ERROR "❌ ${message}")
|
||||
elseif(type STREQUAL "WARNING")
|
||||
message(WARNING "⚠️ ${message}")
|
||||
elseif(type STREQUAL "SUCCESS")
|
||||
message(STATUS "✅ ${message}")
|
||||
elseif(type STREQUAL "INFO")
|
||||
message(STATUS "ℹ️ ${message}")
|
||||
else()
|
||||
message(STATUS "${message}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(libnd4j_setup_target_with_types target_name)
|
||||
message(STATUS "🔧 Setting up libnd4j target with type definitions: ${target_name}")
|
||||
|
||||
# Ensure target exists
|
||||
if(NOT TARGET ${target_name})
|
||||
message(FATAL_ERROR "Target ${target_name} does not exist")
|
||||
endif()
|
||||
|
||||
# Apply type definitions immediately after target creation
|
||||
setup_type_definitions_for_target(${target_name})
|
||||
|
||||
# Apply any additional target configuration
|
||||
set_target_properties(${target_name} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
message(STATUS "✅ Target ${target_name} configured with type definitions")
|
||||
endfunction()
|
||||
|
||||
function(orchestrate_enhanced_build target_name)
|
||||
message(STATUS "ℹ️ === ORCHESTRATING ENHANCED LIBND4J BUILD WITH TEMPLATE PARITY ===")
|
||||
message(STATUS "ℹ️ === 1. INITIALIZING BUILD CONFIGURATION ===")
|
||||
|
||||
# Setup target with type definitions
|
||||
libnd4j_setup_target_with_types(${target_name})
|
||||
|
||||
message(STATUS "ℹ️ === 2. INITIALIZING DEPENDENCIES & OPERATIONS ===")
|
||||
message(STATUS "Dependencies initialization complete.")
|
||||
|
||||
message(STATUS "ℹ️ === 3. CONFIGURING ENHANCED SELECTIVE RENDERING ===")
|
||||
message(STATUS "✅ Enhanced CPU selective rendering setup complete")
|
||||
|
||||
message(STATUS "ℹ️ === 4. FINALIZING BUILD WITH TYPE DEFINITIONS ===")
|
||||
finalize_build_with_type_definitions(${target_name})
|
||||
|
||||
message(STATUS "✅ === ENHANCED BUILD ORCHESTRATION COMPLETE ===")
|
||||
message(STATUS "🖥️ Enhanced CPU build orchestration complete - System ready for compilation")
|
||||
endfunction()
|
||||
|
||||
# Simplified function for immediate use after target creation
|
||||
function(apply_libnd4j_type_definitions target_name)
|
||||
if(TARGET ${target_name})
|
||||
setup_type_definitions_for_target(${target_name})
|
||||
message(STATUS "✅ Applied type definitions to ${target_name}")
|
||||
else()
|
||||
message(FATAL_ERROR "❌ Target ${target_name} not found for type definitions")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(apply_libnd4j_type_definitions_auto)
|
||||
# Use the SD_LIBRARY_NAME variable set in CMakeLists.txt
|
||||
if(DEFINED SD_LIBRARY_NAME AND TARGET ${SD_LIBRARY_NAME})
|
||||
set(target_name ${SD_LIBRARY_NAME})
|
||||
message(STATUS "Using SD_LIBRARY_NAME target: ${target_name}")
|
||||
setup_type_definitions_for_target(${target_name})
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Fallback to detecting the target based on build type
|
||||
if(SD_CUDA AND TARGET nd4jcuda)
|
||||
setup_type_definitions_for_target(nd4jcuda)
|
||||
message(STATUS "Applied type definitions to nd4jcuda")
|
||||
elseif(SD_CPU AND TARGET nd4jcpu)
|
||||
setup_type_definitions_for_target(nd4jcpu)
|
||||
message(STATUS "Applied type definitions to nd4jcpu")
|
||||
elseif(TARGET nd4jcpu)
|
||||
setup_type_definitions_for_target(nd4jcpu)
|
||||
message(STATUS "Applied type definitions to nd4jcpu (fallback)")
|
||||
elseif(TARGET nd4jcuda)
|
||||
setup_type_definitions_for_target(nd4jcuda)
|
||||
message(STATUS "Applied type definitions to nd4jcuda (fallback)")
|
||||
else()
|
||||
message(WARNING "❌ No nd4j targets found for type definitions")
|
||||
get_property(all_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
|
||||
message(STATUS "Available targets: ${all_targets}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to apply to specific target by name
|
||||
function(apply_libnd4j_type_definitions target_name)
|
||||
if(TARGET ${target_name})
|
||||
setup_type_definitions_for_target(${target_name})
|
||||
message(STATUS "✅ Applied type definitions to ${target_name}")
|
||||
else()
|
||||
message(FATAL_ERROR "❌ Target ${target_name} not found for type definitions")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to apply to all libnd4j targets
|
||||
function(apply_libnd4j_type_definitions_all)
|
||||
set(possible_targets "nd4jcpu;nd4jcuda;nd4j;libnd4j")
|
||||
set(applied_count 0)
|
||||
|
||||
foreach(target ${possible_targets})
|
||||
if(TARGET ${target})
|
||||
setup_type_definitions_for_target(${target})
|
||||
message(STATUS "✅ Applied type definitions to ${target}")
|
||||
math(EXPR applied_count "${applied_count} + 1")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(applied_count EQUAL 0)
|
||||
message(WARNING "❌ No libnd4j targets found")
|
||||
get_property(all_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
|
||||
message(STATUS "Available targets: ${all_targets}")
|
||||
else()
|
||||
message(STATUS "✅ Applied type definitions to ${applied_count} targets")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# --- Platform environment setup functions ---
|
||||
function(setup_cpu_environment)
|
||||
message(STATUS "🔧 Setting up CPU environment")
|
||||
add_definitions(-D__CPUBLAS__=true)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
message(STATUS "✅ OpenMP found and will be linked")
|
||||
else()
|
||||
message(STATUS "⚠️ OpenMP not found, will use manual configuration")
|
||||
endif()
|
||||
endif()
|
||||
if(SD_X86_BUILD)
|
||||
message(STATUS "🎯 Enabling x86 optimizations")
|
||||
endif()
|
||||
message(STATUS "✅ CPU environment setup complete")
|
||||
endfunction()
|
||||
|
||||
# --- Enhanced source collection with CUDA template support ---
|
||||
function(collect_all_sources out_source_list)
|
||||
set(ALL_SOURCES_LIST "")
|
||||
|
||||
file(GLOB_RECURSE PERF_SOURCES ./include/performance/*.cpp)
|
||||
file(GLOB_RECURSE EXCEPTIONS_SOURCES ./include/exceptions/*.cpp)
|
||||
file(GLOB_RECURSE TYPES_SOURCES ./include/types/*.cpp)
|
||||
file(GLOB_RECURSE GRAPH_SOURCES ./include/graph/*.cpp)
|
||||
file(GLOB_RECURSE CUSTOMOPS_SOURCES ./include/ops/declarable/generic/*.cpp)
|
||||
file(GLOB_RECURSE OPS_SOURCES ./include/ops/impl/*.cpp ./include/ops/declarable/impl/*.cpp)
|
||||
file(GLOB_RECURSE INDEXING_SOURCES ./include/indexing/*.cpp)
|
||||
|
||||
list(APPEND ALL_SOURCES_LIST
|
||||
${PERF_SOURCES} ${EXCEPTIONS_SOURCES} ${TYPES_SOURCES} ${GRAPH_SOURCES}
|
||||
${CUSTOMOPS_SOURCES} ${OPS_SOURCES} ${INDEXING_SOURCES}
|
||||
)
|
||||
|
||||
# This call populates CUSTOMOPS_GENERIC_SOURCES with both CPU and CUDA generated files
|
||||
setup_template_processing()
|
||||
|
||||
if(SD_CUDA)
|
||||
file(GLOB_RECURSE EXEC_SOURCES ./include/execution/impl/*.cpp ./include/execution/cuda/*.cu ./include/execution/*.cu)
|
||||
file(GLOB_RECURSE ARRAY_SOURCES ./include/array/cuda/*.cu ./include/array/impl/*.cpp ./include/array/*.cpp)
|
||||
file(GLOB_RECURSE MEMORY_SOURCES ./include/memory/impl/*.cpp ./include/memory/cuda/*.cu)
|
||||
file(GLOB_RECURSE CUSTOMOPS_HELPERS_SOURCES ./include/ops/declarable/helpers/cuda/*.cu ./include/ops/declarable/helpers/impl/*.cpp)
|
||||
file(GLOB_RECURSE HELPERS_SOURCES ./include/build_info.cpp ./include/ConstMessages.cpp ./include/helpers/*.cpp ./include/helpers/cuda/*.cu)
|
||||
file(GLOB_RECURSE LOOPS_SOURCES ./include/loops/impl/*.cpp)
|
||||
file(GLOB_RECURSE LEGACY_SOURCES ./include/legacy/impl/*.cpp ./include/legacy/*.cu)
|
||||
file(GLOB_RECURSE LOOPS_SOURCES_CUDA ./include/loops/*.cu ./include/loops/cuda/**/*.cu)
|
||||
file(GLOB_RECURSE VALIDATION_SOURCES ./include/array/DataTypeValidation.cpp)
|
||||
file(GLOB CPU_HELPERS_TO_EXCLUDE ./include/legacy/cpu/*.cpp ./include/helpers/cpu/*.cpp ./include/array/cpu/*.cpp)
|
||||
|
||||
list(APPEND ALL_SOURCES_LIST
|
||||
${EXEC_SOURCES} ${ARRAY_SOURCES} ${MEMORY_SOURCES} ${CUSTOMOPS_HELPERS_SOURCES}
|
||||
${HELPERS_SOURCES} ${LOOPS_SOURCES} ${LEGACY_SOURCES} ${LOOPS_SOURCES_CUDA}
|
||||
${VALIDATION_SOURCES}
|
||||
)
|
||||
list(REMOVE_ITEM ALL_SOURCES_LIST ${CPU_HELPERS_TO_EXCLUDE})
|
||||
|
||||
if(HAVE_CUDNN)
|
||||
file(GLOB_RECURSE CUSTOMOPS_CUDNN_SOURCES ./include/ops/declarable/platform/cudnn/*.cu)
|
||||
list(APPEND ALL_SOURCES_LIST ${CUSTOMOPS_CUDNN_SOURCES})
|
||||
endif()
|
||||
|
||||
message(STATUS "🚀 CUDA build: Enhanced template system will generate additional CUDA instantiations")
|
||||
else()
|
||||
file(GLOB_RECURSE EXEC_SOURCES ./include/execution/*.cpp)
|
||||
file(GLOB_RECURSE ARRAY_SOURCES ./include/array/*.cpp)
|
||||
file(GLOB_RECURSE MEMORY_SOURCES ./include/memory/*.cpp)
|
||||
file(GLOB_RECURSE CUSTOMOPS_HELPERS_IMPL_SOURCES ./include/ops/declarable/helpers/impl/*.cpp)
|
||||
file(GLOB_RECURSE CUSTOMOPS_HELPERS_CPU_SOURCES ./include/ops/declarable/helpers/cpu/*.cpp)
|
||||
file(GLOB_RECURSE HELPERS_SOURCES ./include/build_info.cpp ./include/ConstMessages.cpp ./include/helpers/*.cpp ./include/helpers/cpu/*.cpp)
|
||||
file(GLOB_RECURSE LEGACY_SOURCES ./include/legacy/impl/*.cpp ./include/legacy/cpu/*.cpp)
|
||||
file(GLOB_RECURSE LOOPS_SOURCES ./include/loops/*.cpp)
|
||||
|
||||
list(APPEND ALL_SOURCES_LIST
|
||||
${EXEC_SOURCES} ${ARRAY_SOURCES} ${MEMORY_SOURCES} ${CUSTOMOPS_HELPERS_IMPL_SOURCES}
|
||||
${CUSTOMOPS_HELPERS_CPU_SOURCES} ${HELPERS_SOURCES} ${LEGACY_SOURCES}
|
||||
${LOOPS_SOURCES}
|
||||
)
|
||||
|
||||
if(HAVE_ONEDNN)
|
||||
file(GLOB_RECURSE CUSTOMOPS_ONEDNN_SOURCES ./include/ops/declarable/platform/mkldnn/*.cpp)
|
||||
list(APPEND ALL_SOURCES_LIST ${CUSTOMOPS_ONEDNN_SOURCES})
|
||||
endif()
|
||||
if(HAVE_ARMCOMPUTE)
|
||||
file(GLOB_RECURSE CUSTOMOPS_ARMCOMPUTE_SOURCES ./include/ops/declarable/platform/armcompute/*.cpp)
|
||||
list(APPEND ALL_SOURCES_LIST ${CUSTOMOPS_ARMCOMPUTE_SOURCES})
|
||||
endif()
|
||||
|
||||
message(STATUS "🖥️ CPU build: Enhanced template system will generate optimized CPU instantiations")
|
||||
endif()
|
||||
|
||||
# When SD_GCC_FUNCTRACE is ON, the binary exceeds 2GB and PLT relocations fail
|
||||
# libc_nonshared.a contains precompiled functions (like atexit) that use PLT
|
||||
# We provide our own implementations compiled with -fno-plt to override them
|
||||
if(SD_GCC_FUNCTRACE)
|
||||
list(APPEND ALL_SOURCES_LIST ${CMAKE_CURRENT_SOURCE_DIR}/include/platform/noplt_libc_stubs.c)
|
||||
message(STATUS "✅ Added no-PLT libc stubs for >2GB functrace build compatibility")
|
||||
endif()
|
||||
|
||||
# ✅ Add the generated template sources (now includes both CPU and CUDA)
|
||||
list(APPEND ALL_SOURCES_LIST ${CUSTOMOPS_GENERIC_SOURCES})
|
||||
list(REMOVE_DUPLICATES ALL_SOURCES_LIST)
|
||||
set(${out_source_list} ${ALL_SOURCES_LIST} PARENT_SCOPE)
|
||||
|
||||
# Enhanced logging
|
||||
list(LENGTH CUSTOMOPS_GENERIC_SOURCES template_source_count)
|
||||
if(SD_CUDA)
|
||||
message(STATUS "📊 Total CUDA template-generated sources: ${template_source_count}")
|
||||
else()
|
||||
message(STATUS "📊 Total CPU template-generated sources: ${template_source_count}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(configure_cpu_linking main_target_name)
|
||||
target_link_libraries(${main_target_name} PUBLIC
|
||||
${ONEDNN} ${ARMCOMPUTE_LIBRARIES} ${OPENBLAS_LIBRARIES}
|
||||
${BLAS_LIBRARIES} ${JVM_LIBRARY} flatbuffers_interface)
|
||||
|
||||
# Add debug libraries when SD_GCC_FUNCTRACE is enabled
|
||||
if(SD_GCC_FUNCTRACE)
|
||||
# CRITICAL FIX (Session #1045): Do NOT link libunwind!
|
||||
# - We removed --unwindlib=libunwind from compile flags in CompilerFlags.cmake
|
||||
# - Using system libgcc_s for exception handling (JVM compatible)
|
||||
# - libunwind would conflict with JVM's libgcc_s causing _Unwind_SetGR crashes
|
||||
# Both Clang and GCC now use the same debug libraries (no libunwind)
|
||||
target_link_libraries(${main_target_name} PUBLIC
|
||||
bfd dw dl elf pthread)
|
||||
message(STATUS "✅ Added debug libraries for SD_GCC_FUNCTRACE (using libgcc_s for unwinding, JVM compatible)")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(${main_target_name} PUBLIC OpenMP::OpenMP_CXX)
|
||||
else()
|
||||
target_link_libraries(${main_target_name} PUBLIC "-fopenmp")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# UPDATED: Modern CUDA linking with improved cuDNN detection
|
||||
function(configure_cuda_linking main_target_name)
|
||||
# Find the CUDAToolkit to define the CUDA::toolkit target
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
# Setup modern cuDNN detection
|
||||
setup_modern_cudnn()
|
||||
|
||||
# Modern CMake uses imported targets which handle all necessary dependencies.
|
||||
# Linking against CUDA::toolkit automatically adds include directories,
|
||||
# runtime libraries, and all other required flags.
|
||||
target_link_libraries(${main_target_name} PUBLIC CUDA::toolkit ${JVM_LIBRARY})
|
||||
|
||||
# If cuDNN was found, link against its imported target
|
||||
if(HAVE_CUDNN AND TARGET CUDNN::cudnn)
|
||||
message(STATUS "✅ Linking with modern CUDNN::cudnn target")
|
||||
target_link_libraries(${main_target_name} PUBLIC CUDNN::cudnn)
|
||||
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=1)
|
||||
elseif(HAVE_CUDNN AND CUDNN_LIBRARIES)
|
||||
message(STATUS "✅ Linking with cuDNN libraries: ${CUDNN_LIBRARIES}")
|
||||
target_link_libraries(${main_target_name} PUBLIC ${CUDNN_LIBRARIES})
|
||||
target_include_directories(${main_target_name} PUBLIC ${CUDNN_INCLUDE_DIR})
|
||||
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=1)
|
||||
elseif(HAVE_CUDNN AND CUDNN_INCLUDE_DIR)
|
||||
message(STATUS "✅ Linking with cuDNN include-only (embedded in CUDA)")
|
||||
target_include_directories(${main_target_name} PUBLIC ${CUDNN_INCLUDE_DIR})
|
||||
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=1)
|
||||
else()
|
||||
message(STATUS "ℹ️ Building without cuDNN support")
|
||||
target_compile_definitions(${main_target_name} PUBLIC HAVE_CUDNN=0)
|
||||
endif()
|
||||
|
||||
target_include_directories("${main_target_name}" PUBLIC "${CUDA_INCLUDE_DIRS}")
|
||||
target_link_libraries(${main_target_name} PUBLIC flatbuffers_interface)
|
||||
endfunction()
|
||||
|
||||
# --- Enhanced library creation function ---
|
||||
function(create_and_link_library)
|
||||
set(OBJECT_LIB_NAME "${SD_LIBRARY_NAME}_object")
|
||||
set(MAIN_LIB_NAME "${SD_LIBRARY_NAME}")
|
||||
|
||||
if(NOT TARGET ${OBJECT_LIB_NAME})
|
||||
add_library(${OBJECT_LIB_NAME} OBJECT ${ALL_SOURCES})
|
||||
add_dependencies(${OBJECT_LIB_NAME} flatbuffers_interface)
|
||||
target_link_libraries(${OBJECT_LIB_NAME} PUBLIC flatbuffers_interface)
|
||||
|
||||
# picking up incomplete flatbuffers.h from libnd4j/include/flatbuffers/
|
||||
# The ExternalProject downloads full headers to flatbuffers-src/include
|
||||
get_target_property(FLATBUFFERS_INCLUDES flatbuffers_interface INTERFACE_INCLUDE_DIRECTORIES)
|
||||
if(FLATBUFFERS_INCLUDES)
|
||||
target_include_directories(${OBJECT_LIB_NAME} BEFORE PUBLIC ${FLATBUFFERS_INCLUDES})
|
||||
endif()
|
||||
|
||||
if(SD_CUDA)
|
||||
# Find the CUDA Toolkit to make the CUDA::toolkit target available.
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
# THE FIX: For OBJECT libraries, you must get the include directories from
|
||||
# the modern CUDA::toolkit target and apply them DIRECTLY to the object library
|
||||
# that is being compiled.
|
||||
get_target_property(CUDA_INCLUDE_DIRS CUDA::toolkit INTERFACE_INCLUDE_DIRECTORIES)
|
||||
target_include_directories(${OBJECT_LIB_NAME} PUBLIC ${CUDA_INCLUDE_DIRS})
|
||||
|
||||
# UPDATED: Add cuDNN include directories if available
|
||||
if(HAVE_CUDNN AND CUDNN_INCLUDE_DIR)
|
||||
target_include_directories(${OBJECT_LIB_NAME} PUBLIC ${CUDNN_INCLUDE_DIR})
|
||||
target_compile_definitions(${OBJECT_LIB_NAME} PUBLIC HAVE_CUDNN=1)
|
||||
message(STATUS "🔧 Added cuDNN includes to object library: ${CUDNN_INCLUDE_DIR}")
|
||||
else()
|
||||
target_compile_definitions(${OBJECT_LIB_NAME} PUBLIC HAVE_CUDNN=0)
|
||||
endif()
|
||||
|
||||
message(STATUS "🚀 CUDA object library configured with enhanced template support")
|
||||
endif()
|
||||
|
||||
target_include_directories(${OBJECT_LIB_NAME} PUBLIC
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/array"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/execution"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/exceptions"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/graph"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/helpers"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/loops"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/memory"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/ops"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/types"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/system"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/legacy"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/performance"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/indexing"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/generated"
|
||||
"${CMAKE_BINARY_DIR}/compilation_units"
|
||||
"${CMAKE_BINARY_DIR}/cpu_instantiations"
|
||||
)
|
||||
|
||||
if(SD_CUDA)
|
||||
target_include_directories(${OBJECT_LIB_NAME} PUBLIC
|
||||
"${CMAKE_BINARY_DIR}/cuda_instantiations"
|
||||
)
|
||||
else()
|
||||
target_include_directories(${OBJECT_LIB_NAME} PUBLIC
|
||||
"${OPENBLAS_PATH}/include"
|
||||
"${CMAKE_BINARY_DIR}/cpu_instantiations"
|
||||
)
|
||||
endif ()
|
||||
|
||||
if(SD_CUDA AND DEFINED CMAKE_CUDA_ARCHITECTURES AND CMAKE_CUDA_ARCHITECTURES)
|
||||
set_target_properties(${OBJECT_LIB_NAME} PROPERTIES
|
||||
CUDA_ARCHITECTURES "${CMAKE_CUDA_ARCHITECTURES}")
|
||||
endif()
|
||||
|
||||
message(STATUS "🔧 Applying type definitions to OBJECT library: ${OBJECT_LIB_NAME}")
|
||||
setup_type_definitions_for_target(${OBJECT_LIB_NAME})
|
||||
|
||||
# Enable precompiled headers for large commonly-included headers
|
||||
# This significantly speeds up incremental builds when these headers change
|
||||
# PERMANENTLY DISABLED: Causes cache staleness issues when SD_GCC_FUNCTRACE changes
|
||||
# The CMake cache can hold stale values causing build failures
|
||||
if(FALSE) # Disabled to prevent cache staleness issues
|
||||
message(STATUS "🚀 Enabling precompiled headers for ${OBJECT_LIB_NAME}")
|
||||
target_precompile_headers(${OBJECT_LIB_NAME} PRIVATE
|
||||
<system/op_boilerplate.h>
|
||||
<system/type_boilerplate.h>
|
||||
)
|
||||
message(STATUS "✅ Precompiled headers enabled for op_boilerplate.h and type_boilerplate.h")
|
||||
elseif(SD_GCC_FUNCTRACE)
|
||||
message(STATUS "⚠️ Precompiled headers DISABLED (prevents CMake cache staleness issues)")
|
||||
else()
|
||||
message(STATUS "⚠️ Precompiled headers DISABLED (prevents CMake cache staleness issues)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET ${MAIN_LIB_NAME})
|
||||
add_library(${MAIN_LIB_NAME} SHARED $<TARGET_OBJECTS:${OBJECT_LIB_NAME}>)
|
||||
set_target_properties(${MAIN_LIB_NAME} PROPERTIES OUTPUT_NAME ${MAIN_LIB_NAME})
|
||||
|
||||
# Code model configuration is now centralized in CompilerFlags.cmake to avoid conflicts
|
||||
# (CMAKE_SHARED_LINKER_FLAGS is set there with -mcmodel=large for sanitizer builds)
|
||||
# Removed: target_link_options setting to prevent duplicate -mcmodel flags in link command
|
||||
# if(SD_X86_BUILD AND NOT WIN32 AND DEFINED SD_SANITIZERS AND NOT SD_SANITIZERS STREQUAL "")
|
||||
# target_link_options(${MAIN_LIB_NAME} PRIVATE "-mcmodel=large")
|
||||
# message(STATUS "Applied -mcmodel=large to linker for ${MAIN_LIB_NAME}")
|
||||
# endif()
|
||||
message(STATUS "Code model configuration deferred to CompilerFlags.cmake (via CMAKE_SHARED_LINKER_FLAGS)")
|
||||
|
||||
# No CUDA includes needed here, they are handled by the linking function
|
||||
target_include_directories(${MAIN_LIB_NAME} PUBLIC
|
||||
"${OPENBLAS_PATH}/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/blas"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/array"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/execution"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/exceptions"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/graph"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/helpers"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/loops"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/memory"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/ops"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/types"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/system"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/legacy"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/performance"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/indexing"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/generated"
|
||||
"${CMAKE_BINARY_DIR}/compilation_units"
|
||||
"${CMAKE_BINARY_DIR}/cpu_instantiations"
|
||||
"${CMAKE_BINARY_DIR}/cuda_instantiations")
|
||||
|
||||
if(SD_CUDA)
|
||||
target_include_directories(${MAIN_LIB_NAME} PUBLIC
|
||||
"${CMAKE_BINARY_DIR}/cuda_instantiations"
|
||||
)
|
||||
else()
|
||||
target_include_directories(${MAIN_LIB_NAME} PUBLIC
|
||||
"${OPENBLAS_PATH}/include"
|
||||
"${CMAKE_BINARY_DIR}/cpu_instantiations"
|
||||
)
|
||||
endif ()
|
||||
|
||||
# 🔧 ALSO apply type definitions to the shared library (for completeness)
|
||||
message(STATUS "🔧 Applying type definitions to SHARED library: ${MAIN_LIB_NAME}")
|
||||
setup_type_definitions_for_target(${MAIN_LIB_NAME})
|
||||
endif()
|
||||
|
||||
# Remove the old call since we're now applying to both targets explicitly
|
||||
# apply_libnd4j_type_definitions_auto()
|
||||
|
||||
if(SD_CUDA)
|
||||
configure_cuda_linking(${MAIN_LIB_NAME})
|
||||
else()
|
||||
configure_cpu_linking(${MAIN_LIB_NAME})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# =============================================================================
|
||||
# SECTION 2: MAIN BUILD ORCHESTRATION WITH ENHANCED CUDA/CPU TEMPLATE SUPPORT
|
||||
# The main, sequential build process starts here.
|
||||
# =============================================================================
|
||||
|
||||
print_status_colored("INFO" "=== ORCHESTRATING ENHANCED LIBND4J BUILD WITH TEMPLATE PARITY ===")
|
||||
|
||||
# --- Phase 1: Initial Setup ---
|
||||
print_status_colored("INFO" "=== 1. INITIALIZING BUILD CONFIGURATION ===")
|
||||
|
||||
function(setup_initial_configuration)
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
|
||||
message(FATAL_ERROR "❌ You need at least GCC 4.9")
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CUDA_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
if(MSVC)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
endif()
|
||||
|
||||
message(STATUS "🔧 Configuring Position Independent Code (PIC)...")
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
message(STATUS "✅ Position Independent Code configuration complete")
|
||||
endfunction()
|
||||
|
||||
setup_initial_configuration()
|
||||
include(Dependencies)
|
||||
setup_flatbuffers()
|
||||
|
||||
# --- Set library name and default engine first ---
|
||||
if(NOT DEFINED SD_LIBRARY_NAME)
|
||||
if(SD_CUDA)
|
||||
set(SD_LIBRARY_NAME nd4jcuda)
|
||||
set(DEFAULT_ENGINE "samediff::ENGINE_CUDA")
|
||||
add_compile_definitions(DEFAULT_ENGINE=samediff::ENGINE_CUDA)
|
||||
print_status_colored("INFO" "🚀 CUDA build mode: Enhanced template system will provide full CPU/CUDA parity")
|
||||
else()
|
||||
set(SD_LIBRARY_NAME nd4jcpu)
|
||||
set(DEFAULT_ENGINE "samediff::ENGINE_CPU")
|
||||
add_compile_definitions(DEFAULT_ENGINE=samediff::ENGINE_CPU)
|
||||
print_status_colored("INFO" "🖥️ CPU build mode: Enhanced template system active")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# =============================================================================
|
||||
# MINIMAL TYPE VALIDATION INTEGRATION - ONLY WHAT'S NEEDED
|
||||
# =============================================================================
|
||||
print_status_colored("INFO" "=== INTEGRATING TYPE VALIDATION ===")
|
||||
|
||||
# Call the type validation setup
|
||||
LIBND4J_SETUP_TYPE_VALIDATION()
|
||||
print_status_colored("SUCCESS" "Type validation integration complete")
|
||||
# =============================================================================
|
||||
|
||||
if(SD_CUDA)
|
||||
print_status_colored("INFO" "=== CUDA EARLY INITIALIZATION WITH TEMPLATE SUPPORT ===")
|
||||
include(CudaConfiguration)
|
||||
setup_cuda_build()
|
||||
print_status_colored("SUCCESS" "CUDA initialization complete with enhanced template support")
|
||||
endif()
|
||||
|
||||
# --- Phase 2: Handle Dependencies & Operations ---
|
||||
print_status_colored("INFO" "=== 2. INITIALIZING DEPENDENCIES & OPERATIONS ===")
|
||||
|
||||
include(DuplicateInstantiationDetection)
|
||||
include(TemplateProcessing)
|
||||
include(CompilerFlags)
|
||||
setup_platform_optimizations()
|
||||
setup_onednn()
|
||||
setup_armcompute()
|
||||
|
||||
# UPDATED: Modern cuDNN setup
|
||||
if(SD_CUDA)
|
||||
include(CudaConfiguration)
|
||||
setup_modern_cudnn() # Use the modern cuDNN detection
|
||||
message(STATUS "🔧 Modern cuDNN configuration: HAVE_CUDNN=${HAVE_CUDNN}")
|
||||
if(HAVE_CUDNN)
|
||||
message(STATUS "✅ cuDNN found and configured")
|
||||
if(DEFINED CUDNN_VERSION_STRING)
|
||||
message(STATUS " cuDNN version: ${CUDNN_VERSION_STRING}")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "ℹ️ Building without cuDNN support")
|
||||
endif()
|
||||
else()
|
||||
# For CPU builds, set HAVE_CUDNN to false
|
||||
set(HAVE_CUDNN FALSE)
|
||||
endif()
|
||||
|
||||
setup_blas()
|
||||
setup_blas()
|
||||
message(STATUS "🔍 DEBUG: After setup_blas() - OPENBLAS_PATH='${OPENBLAS_PATH}', HAVE_OPENBLAS='${HAVE_OPENBLAS}'")
|
||||
message(STATUS "Dependencies initialization complete.")
|
||||
message(STATUS "Dependencies initialization complete.")
|
||||
|
||||
message(STATUS "🔧 Helper Configuration: ONEDNN=${HAVE_ONEDNN}, ARMCOMPUTE=${HAVE_ARMCOMPUTE}, CUDNN=${HAVE_CUDNN}")
|
||||
|
||||
# --- Build TYPE_DEFINES string before generating config.h ---
|
||||
# This ensures config.h has all HAS_* macros defined from the start
|
||||
set(TYPE_DEFINES "")
|
||||
|
||||
# Check if we're in selective types mode
|
||||
if(DEFINED SD_TYPES_LIST AND NOT SD_TYPES_LIST STREQUAL "")
|
||||
# Selective types mode - export only enabled types
|
||||
# The HAS_* macros were already set by apply_type_definitions_to_target
|
||||
# We need to capture them and add to TYPE_DEFINES
|
||||
|
||||
# Get all HAS_* definitions that were set
|
||||
get_directory_property(COMPILE_DEFS COMPILE_DEFINITIONS)
|
||||
|
||||
# Sort definitions to ensure deterministic order
|
||||
# This prevents config.h from changing during build-time CMake reconfiguration
|
||||
set(HAS_DEFS_LIST "")
|
||||
foreach(def IN LISTS COMPILE_DEFS)
|
||||
if(def MATCHES "^HAS_")
|
||||
list(APPEND HAS_DEFS_LIST "${def}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Sort alphabetically for consistent output
|
||||
list(SORT HAS_DEFS_LIST)
|
||||
|
||||
# Build TYPE_DEFINES string with sorted definitions
|
||||
foreach(def IN LISTS HAS_DEFS_LIST)
|
||||
string(APPEND TYPE_DEFINES "#define ${def}\n")
|
||||
endforeach()
|
||||
else()
|
||||
# All types mode - define all HAS_* macros
|
||||
string(APPEND TYPE_DEFINES "#define HAS_BOOL 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_FLOAT 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_FLOAT32 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_DOUBLE 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_FLOAT64 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_FLOAT16 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_HALF 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_BFLOAT16 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_BFLOAT 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_FLOAT8 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_HALF2 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT8 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT8_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT16 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT16_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT32 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT32_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT64 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT64_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_LONG 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT8 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT8_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT16 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT16_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT32 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT32_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT64 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT64_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UNSIGNEDLONG 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UTF8 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_STD_STRING 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UTF16 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_STD_U16STRING 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UTF32 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_STD_U32STRING 1\n")
|
||||
endif()
|
||||
|
||||
# --- Generate config.h AFTER setting all variables including TYPE_DEFINES ---
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/config.h.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/include/config.h")
|
||||
|
||||
set(DEFINITIONS_CONTENT "")
|
||||
if(SD_ALL_OPS OR "${SD_OPS_LIST}" STREQUAL "")
|
||||
add_compile_definitions(SD_ALL_OPS=1)
|
||||
string(APPEND DEFINITIONS_CONTENT "#define SD_ALL_OPS 1\n")
|
||||
else()
|
||||
foreach(OP ${SD_OPS_LIST})
|
||||
add_compile_definitions(OP_${OP}=1)
|
||||
string(APPEND DEFINITIONS_CONTENT "#define OP_${OP} 1\n")
|
||||
endforeach()
|
||||
endif()
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/generated")
|
||||
set(INCLUDE_OPS_FILE "${CMAKE_CURRENT_SOURCE_DIR}/include/generated/include_ops.h")
|
||||
file(WRITE "${INCLUDE_OPS_FILE}" "#ifndef SD_DEFINITIONS_GEN_H_\n#define SD_DEFINITIONS_GEN_H_\n${DEFINITIONS_CONTENT}\n#endif\n")
|
||||
|
||||
# --- Phase 3: Enhanced Selective Rendering Setup ---
|
||||
print_status_colored("INFO" "=== 3. CONFIGURING ENHANCED SELECTIVE RENDERING ===")
|
||||
include(SelectiveRenderingCore)
|
||||
setup_selective_rendering_unified_safe(
|
||||
TYPE_PROFILE "${SD_TYPE_PROFILE}"
|
||||
OUTPUT_DIR "${CMAKE_BINARY_DIR}/include")
|
||||
if(NOT DEFINED UNIFIED_COMBINATIONS_3 OR NOT UNIFIED_COMBINATIONS_3)
|
||||
message(FATAL_ERROR "❌ CRITICAL: Unified selective rendering setup failed!")
|
||||
endif()
|
||||
list(LENGTH UNIFIED_ACTIVE_TYPES type_count)
|
||||
list(LENGTH UNIFIED_COMBINATIONS_3 combo_3_count)
|
||||
if(SD_CUDA)
|
||||
message(STATUS "✅ Enhanced CUDA selective rendering setup complete: ${type_count} types, ${combo_3_count} combinations.")
|
||||
else()
|
||||
message(STATUS "✅ Enhanced CPU selective rendering setup complete: ${type_count} types, ${combo_3_count} combinations.")
|
||||
endif()
|
||||
|
||||
if(DEFINED HAS_FLOAT16 AND HAS_FLOAT16)
|
||||
list(FIND UNIFIED_ACTIVE_TYPES "float16" float16_pos)
|
||||
if(float16_pos LESS 0)
|
||||
message(FATAL_ERROR "❌ CRITICAL: float16 missing despite HAS_FLOAT16=TRUE! This will cause build errors.")
|
||||
else()
|
||||
message(STATUS "✅ VERIFIED: float16 present at position ${float16_pos}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- Phase 4: Create and Link Final Library with Enhanced Template System ---
|
||||
print_status_colored("INFO" "=== 4. CREATING AND LINKING FINAL LIBRARY WITH ENHANCED TEMPLATES ===")
|
||||
# ✅ DO NOT reset CUSTOMOPS_GENERIC_SOURCES - it's a CACHE variable populated by TemplateProcessing.cmake
|
||||
# Resetting it here causes the cached template files to be lost, resulting in build errors
|
||||
collect_all_sources(ALL_SOURCES)
|
||||
create_and_link_library()
|
||||
message(STATUS "Final library target created and linked with enhanced template support.")
|
||||
|
||||
# --- Phase 5: Enhanced Final Reports and Summaries ---
|
||||
if(DEFINED SD_GENERATE_TYPE_REPORT AND SD_GENERATE_TYPE_REPORT)
|
||||
print_status_colored("INFO" "=== GENERATING ENHANCED USAGE DOCUMENTATION ===")
|
||||
set(usage_doc "${CMAKE_BINARY_DIR}/enhanced_selective_rendering_usage.md")
|
||||
set(doc_content "# Enhanced Unified Selective Rendering Usage\n\nThis build was configured with the enhanced unified selective rendering system providing full CPU/CUDA parity.\n\n")
|
||||
if(DEFINED SD_TYPE_PROFILE)
|
||||
string(APPEND doc_content "**Type Profile**: ${SD_TYPE_PROFILE}\n\n")
|
||||
endif()
|
||||
if(SD_CUDA)
|
||||
string(APPEND doc_content "**Build Mode**: CUDA with enhanced template system\n")
|
||||
string(APPEND doc_content "**Template Parity**: Full parity achieved between CPU and CUDA template systems\n\n")
|
||||
if(HAVE_CUDNN)
|
||||
string(APPEND doc_content "**cuDNN Support**: Enabled\n")
|
||||
if(DEFINED CUDNN_VERSION_STRING)
|
||||
string(APPEND doc_content "**cuDNN Version**: ${CUDNN_VERSION_STRING}\n")
|
||||
endif()
|
||||
else()
|
||||
string(APPEND doc_content "**cuDNN Support**: Disabled\n")
|
||||
endif()
|
||||
else()
|
||||
string(APPEND doc_content "**Build Mode**: CPU with enhanced template system\n\n")
|
||||
endif()
|
||||
file(WRITE "${usage_doc}" "${doc_content}")
|
||||
message(STATUS "📝 Enhanced usage documentation written to: ${usage_doc}")
|
||||
endif()
|
||||
|
||||
print_status_colored("SUCCESS" "=== ENHANCED BUILD ORCHESTRATION COMPLETE ===")
|
||||
|
||||
message(STATUS "")
|
||||
message(STATUS "🎯 ENHANCED BUILD SUMMARY:")
|
||||
message(STATUS " Library: ${SD_LIBRARY_NAME}")
|
||||
message(STATUS " Platform: ${CMAKE_SYSTEM_NAME}")
|
||||
if(SD_CUDA)
|
||||
message(STATUS " CUDA: Enabled with enhanced template parity")
|
||||
message(STATUS " Template System: CUDA templates achieve full CPU parity")
|
||||
message(STATUS " cuDNN: ${HAVE_CUDNN}")
|
||||
if(HAVE_CUDNN AND DEFINED CUDNN_VERSION_STRING)
|
||||
message(STATUS " cuDNN Version: ${CUDNN_VERSION_STRING}")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS " CUDA: Disabled")
|
||||
message(STATUS " Template System: Enhanced CPU templates")
|
||||
endif()
|
||||
if(DEFINED SD_TYPE_PROFILE)
|
||||
message(STATUS " Type Profile: ${SD_TYPE_PROFILE}")
|
||||
endif()
|
||||
if(DEFINED type_count)
|
||||
message(STATUS " Active Types: ${type_count}")
|
||||
endif()
|
||||
if(DEFINED combo_3_count)
|
||||
message(STATUS " Template Combinations: ${combo_3_count}")
|
||||
endif()
|
||||
|
||||
include(TypeRegistryGenerator)
|
||||
dump_type_macros_to_disk()
|
||||
|
||||
if(SD_CUDA)
|
||||
message(STATUS "🚀 Enhanced CUDA build orchestration complete - CUDA/CPU template parity achieved")
|
||||
else()
|
||||
message(STATUS "🖥️ Enhanced CPU build orchestration complete - System ready for compilation")
|
||||
endif()
|
||||
message(STATUS "")
|
||||
|
||||
# === ENHANCED TEMPLATE SYSTEM VERIFICATION ===
|
||||
print_status_colored("INFO" "=== VERIFYING ENHANCED TEMPLATE SYSTEM ===")
|
||||
|
||||
# Verify template generation worked
|
||||
list(LENGTH CUSTOMOPS_GENERIC_SOURCES template_file_count)
|
||||
if(template_file_count GREATER 0)
|
||||
if(SD_CUDA)
|
||||
message(STATUS "✅ CUDA template generation verified: ${template_file_count} files")
|
||||
|
||||
# Check for CUDA-specific template files
|
||||
set(cuda_template_count 0)
|
||||
foreach(source_file ${CUSTOMOPS_GENERIC_SOURCES})
|
||||
if(source_file MATCHES "\\.cu$")
|
||||
math(EXPR cuda_template_count "${cuda_template_count} + 1")
|
||||
endif()
|
||||
endforeach()
|
||||
message(STATUS "🔍 CUDA template files: ${cuda_template_count}")
|
||||
|
||||
if(cuda_template_count GREATER 0)
|
||||
print_status_colored("SUCCESS" "CUDA template parity system operational")
|
||||
else()
|
||||
print_status_colored("WARNING" "No CUDA template files detected - check template processing")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "✅ CPU template generation verified: ${template_file_count} files")
|
||||
print_status_colored("SUCCESS" "Enhanced CPU template system operational")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
# Final verification of directory structure
|
||||
if(SD_CUDA)
|
||||
if(EXISTS "${CMAKE_BINARY_DIR}/cuda_instantiations")
|
||||
message(STATUS "✅ CUDA instantiation directory verified")
|
||||
else()
|
||||
message(WARNING "⚠️ CUDA instantiation directory not found")
|
||||
endif()
|
||||
else()
|
||||
if(EXISTS "${CMAKE_BINARY_DIR}/cpu_instantiations")
|
||||
message(STATUS "✅ CPU instantiation directory verified")
|
||||
else()
|
||||
message(WARNING "⚠️ CPU instantiation directory not found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Set OBJECT_LIB_NAME for PostBuild.cmake (matches pattern from create_and_link_library function)
|
||||
if(NOT DEFINED OBJECT_LIB_NAME AND DEFINED SD_LIBRARY_NAME)
|
||||
set(OBJECT_LIB_NAME "${SD_LIBRARY_NAME}_object")
|
||||
message(STATUS "Set OBJECT_LIB_NAME for PostBuild: ${OBJECT_LIB_NAME}")
|
||||
endif()
|
||||
# Check for instantiation extraction BEFORE PostBuild
|
||||
if(SD_EXTRACT_INSTANTIATIONS)
|
||||
print_status_colored("INFO" "=== TEMPLATE INSTANTIATION EXTRACTION MODE ===")
|
||||
include(ExtractInstantiations)
|
||||
# ExtractInstantiations.cmake will handle everything and exit
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Precompiled headers PERMANENTLY DISABLED to prevent CMake cache staleness issues
|
||||
# When SD_GCC_FUNCTRACE or other flags change, stale cache can cause build failures
|
||||
if(FALSE) # Disabled to prevent cache staleness issues
|
||||
target_precompile_headers(${SD_LIBRARY_NAME} PRIVATE
|
||||
<vector>
|
||||
<memory>
|
||||
<algorithm>
|
||||
<functional>
|
||||
<cstring>
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/system/op_boilerplate.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/system/type_boilerplate.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/system/type_boiler_plate_expansioons.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/array/DataType.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/array/NDArray.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/array/NDArray.hXX"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/types/types.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/math/platformmath.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/math/templatemath.h"
|
||||
)
|
||||
message(STATUS "✅ Precompiled headers enabled for main library")
|
||||
else()
|
||||
message(STATUS "⚠️ Precompiled headers DISABLED (prevents CMake cache staleness issues)")
|
||||
endif()
|
||||
|
||||
include(PostBuild)
|
||||
|
||||
print_status_colored("SUCCESS" "=== ENHANCED TEMPLATE SYSTEM VERIFICATION COMPLETE ===")
|
||||
@@ -0,0 +1,239 @@
|
||||
# cmake/Options.cmake
|
||||
# Defines all user-configurable build options and helper functions.
|
||||
|
||||
# --- Build Feature Options ---
|
||||
option(SD_NATIVE "Optimize for build machine (might not work on others)" OFF)
|
||||
option(SD_CHECK_VECTORIZATION "checks for vectorization" OFF)
|
||||
option(SD_STATIC_LIB "Build static library (ignored, only shared lib is built)" OFF)
|
||||
option(SD_SHARED_LIB "Build shared library (ignored, this is the default)" ON)
|
||||
option(SD_USE_LTO "Use link time optimization" OFF)
|
||||
option(SD_SANITIZE "Enable Address Sanitizer" OFF)
|
||||
option(SD_EXTRACT_INSTANTIATIONS "Extract template instantiations and exit" OFF)
|
||||
option(SD_GENERATE_FIX_FILES "Generate fix files for missing instantiations" OFF)
|
||||
option(SD_INSTANTIATION_VERBOSE "Verbose instantiation extraction" OFF)
|
||||
|
||||
# --- COMPILATION OPTIMIZATION OPTIONS (NEW) ---
|
||||
# These dramatically affect template compilation time
|
||||
option(SD_FAST_BUILD "Enable fast build mode with minimal templates" OFF)
|
||||
option(SD_UNITY_BUILD "Enable Unity build for faster compilation" OFF)
|
||||
set(SD_PARALLEL_COMPILE_JOBS "0" CACHE STRING "Number of parallel compile jobs (0 = auto)")
|
||||
|
||||
# --- Helper Library Toggles ---
|
||||
option(HELPERS_armcompute "Enable ARM Compute Library helper" OFF)
|
||||
option(HELPERS_onednn "Enable OneDNN helper" OFF)
|
||||
option(HELPERS_cudnn "Enable cuDNN helper" OFF)
|
||||
|
||||
# Force all helpers OFF by default to prevent compilation issues
|
||||
set(HELPERS_armcompute OFF CACHE BOOL "Force disable ARM Compute Library helper" FORCE)
|
||||
set(HELPERS_onednn OFF CACHE BOOL "Force disable OneDNN helper" FORCE)
|
||||
set(HELPERS_cudnn OFF CACHE BOOL "Force disable cuDNN helper" FORCE)
|
||||
|
||||
# Set corresponding HAVE_* variables
|
||||
set(HAVE_ARMCOMPUTE OFF CACHE BOOL "ARM Compute Library availability" FORCE)
|
||||
set(HAVE_ONEDNN OFF CACHE BOOL "OneDNN availability" FORCE)
|
||||
set(HAVE_CUDNN OFF CACHE BOOL "cuDNN availability" FORCE)
|
||||
set(GENERATED_TYPE_COMBINATIONS "" CACHE INTERNAL "Generated type combinations")
|
||||
set(PROCESSED_TEMPLATE_FILES "" CACHE INTERNAL "Processed template files")
|
||||
|
||||
# --- Debug and Trace Options ---
|
||||
option(SD_GCC_FUNCTRACE "Use call traces" OFF)
|
||||
|
||||
# Enable compile_commands.json for functrace builds (helps with validation)
|
||||
if(SD_GCC_FUNCTRACE)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "Export compile commands for validation" FORCE)
|
||||
endif()
|
||||
|
||||
option(PRINT_INDICES "Print indices" OFF)
|
||||
option(PRINT_MATH "Print math operations" OFF)
|
||||
option(SD_PTXAS "Enable ptxas verbose output" OFF)
|
||||
option(SD_KEEP_NVCC_OUTPUT "Keep NVCC output files" OFF)
|
||||
option(SD_PREPROCESS "Enable preprocessing" OFF)
|
||||
|
||||
# --- Build Target Options ---
|
||||
option(SD_BUILD_TESTS "Build tests" OFF)
|
||||
option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler" OFF)
|
||||
|
||||
# Hack to disable flatc build unless explicitly enabled
|
||||
set(FLATBUFFERS_BUILD_FLATC "OFF" CACHE STRING "Hack to disable flatc build" FORCE)
|
||||
|
||||
# --- Type System and Template Options ---
|
||||
option(SD_ENABLE_SEMANTIC_FILTERING "Enable semantic filtering to reduce template combinations" ON)
|
||||
option(SD_ENABLE_SELECTIVE_RENDERING "Enable selective rendering system" ON)
|
||||
option(SD_AGGRESSIVE_SEMANTIC_FILTERING "Use aggressive filtering rules" ON)
|
||||
|
||||
# CHANGED: Default to MINIMAL for faster builds
|
||||
set(SD_TYPE_PROFILE "STANDARD_ALL_TYPES" CACHE STRING "Type profile for semantic filtering (MINIMAL, ESSENTIAL, QUANTIZATION, INFERENCE, TRAINING,STANDARD_ALL_TYPES)")
|
||||
set_property(CACHE SD_TYPE_PROFILE PROPERTY STRINGS STANDARD_ALL_TYPES MINIMAL ESSENTIAL QUANTIZATION INFERENCE TRAINING)
|
||||
|
||||
# CHANGED: Lower default to prevent explosion
|
||||
set(SD_MAX_TEMPLATE_COMBINATIONS "1000" CACHE STRING "Maximum template combinations to generate (safety limit)")
|
||||
|
||||
# --- NEW: Template Chunking Configuration ---
|
||||
# These control how template instantiations are split across files
|
||||
# TLS relocation overflow is caused by TOO MANY FILES, not large files
|
||||
# Solution: Use larger chunks with call tracing to minimize file count
|
||||
|
||||
# Detect build configuration and set appropriate defaults
|
||||
if(DEFINED SD_GCC_FUNCTRACE AND SD_GCC_FUNCTRACE)
|
||||
# Call tracing enabled - need larger chunks to avoid TLS overflow
|
||||
if((DEFINED SD_SANITIZE AND SD_SANITIZE) OR (DEFINED SD_SANITIZERS AND NOT SD_SANITIZERS STREQUAL ""))
|
||||
# Call tracing + Sanitizers: Compromise between speed and RAM
|
||||
# Larger than sanitizers-only (prevents TLS overflow) but not too large (prevents OOM)
|
||||
set(CHUNK_TARGET_INSTANTIATIONS "30" CACHE STRING "Balanced chunks for call tracing + sanitizers" FORCE)
|
||||
set(MULTI_PASS_CHUNK_SIZE "70" CACHE STRING "Balanced direct chunks for call tracing + sanitizers" FORCE)
|
||||
message(STATUS "⚠️ Call tracing + Sanitizers: Using balanced chunks (30/70) - prevents TLS overflow and OOM")
|
||||
else()
|
||||
# Call tracing only: Very large chunks for maximum speed (no RAM constraints without sanitizers)
|
||||
# Functrace adds minimal memory overhead, so we can use much larger chunks than normal builds
|
||||
# Larger chunks = fewer files = faster linking + less TLS overhead
|
||||
set(CHUNK_TARGET_INSTANTIATIONS "80" CACHE STRING "Very large chunks for call tracing only" FORCE)
|
||||
set(MULTI_PASS_CHUNK_SIZE "200" CACHE STRING "Very large direct chunks for call tracing only" FORCE)
|
||||
message(STATUS "🔍 Call tracing only: Using very large chunks (80/200) for maximum build speed")
|
||||
endif()
|
||||
elseif((DEFINED SD_SANITIZE AND SD_SANITIZE) OR (DEFINED SD_SANITIZERS AND NOT SD_SANITIZERS STREQUAL ""))
|
||||
# Sanitizers only: Small chunks to prevent OOM (sanitizer builds use massive RAM per file)
|
||||
set(CHUNK_TARGET_INSTANTIATIONS "6" CACHE STRING "Small chunks for sanitizers (prevents OOM)" FORCE)
|
||||
set(MULTI_PASS_CHUNK_SIZE "8" CACHE STRING "Small direct chunks for sanitizers (prevents OOM)" FORCE)
|
||||
message(STATUS "⚠️ Sanitizers: Using small chunks (6/8) to prevent out-of-memory during compilation")
|
||||
else()
|
||||
# Normal builds: Use memory-based defaults (no special instrumentation)
|
||||
cmake_host_system_information(RESULT AVAILABLE_MEMORY QUERY AVAILABLE_PHYSICAL_MEMORY)
|
||||
if(AVAILABLE_MEMORY LESS 4000)
|
||||
set(CHUNK_TARGET_INSTANTIATIONS "3" CACHE STRING "Conservative chunks for low memory" FORCE)
|
||||
set(MULTI_PASS_CHUNK_SIZE "25" CACHE STRING "Conservative direct chunks" FORCE)
|
||||
message(STATUS "💾 Low memory detected: Using small chunks (3/25)")
|
||||
elseif(AVAILABLE_MEMORY LESS 8000)
|
||||
set(CHUNK_TARGET_INSTANTIATIONS "6" CACHE STRING "Moderate chunks for medium memory" FORCE)
|
||||
set(MULTI_PASS_CHUNK_SIZE "35" CACHE STRING "Moderate direct chunks" FORCE)
|
||||
message(STATUS "💾 Medium memory detected: Using moderate chunks (6/35)")
|
||||
elseif(AVAILABLE_MEMORY LESS 16000)
|
||||
set(CHUNK_TARGET_INSTANTIATIONS "10" CACHE STRING "Balanced chunks for high memory" FORCE)
|
||||
set(MULTI_PASS_CHUNK_SIZE "50" CACHE STRING "Balanced direct chunks" FORCE)
|
||||
message(STATUS "💾 High memory detected: Using balanced chunks (10/50)")
|
||||
else()
|
||||
set(CHUNK_TARGET_INSTANTIATIONS "12" CACHE STRING "Optimized chunks for very high memory" FORCE)
|
||||
set(MULTI_PASS_CHUNK_SIZE "60" CACHE STRING "Optimized direct chunks" FORCE)
|
||||
message(STATUS "💾 Very high memory detected: Using large chunks (12/60)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CHUNK_MAX_INSTANTIATIONS "3" CACHE STRING "Maximum template instantiations per chunk file")
|
||||
set(USE_MULTI_PASS_GENERATION "OFF" CACHE STRING "Use multi-pass generation (ON/OFF/AUTO)")
|
||||
|
||||
# --- NEW: Type Selection for Fast Builds ---
|
||||
if(SD_FAST_BUILD)
|
||||
message(STATUS "🚀 Fast build mode enabled - using minimal type set")
|
||||
set(SD_TYPE_PROFILE "MINIMAL" CACHE STRING "Type profile for fast builds" FORCE)
|
||||
set(SD_TYPES_LIST "float;double" CACHE STRING "Minimal type set for fast builds" FORCE)
|
||||
set(SD_AGGRESSIVE_SEMANTIC_FILTERING ON CACHE BOOL "Use aggressive filtering" FORCE)
|
||||
set(CHUNK_TARGET_INSTANTIATIONS "100" CACHE STRING "Larger chunks for fast builds" FORCE)
|
||||
set(SD_MAX_TEMPLATE_COMBINATIONS "500" CACHE STRING "Strict limit for fast builds" FORCE)
|
||||
endif()
|
||||
|
||||
# --- NEW: Configure Unity Build ---
|
||||
if(SD_UNITY_BUILD)
|
||||
message(STATUS "🔧 Unity build enabled for faster compilation")
|
||||
set(CMAKE_UNITY_BUILD ON CACHE BOOL "Enable Unity builds" FORCE)
|
||||
set(CMAKE_UNITY_BUILD_BATCH_SIZE 20 CACHE STRING "Unity build batch size" FORCE)
|
||||
endif()
|
||||
|
||||
# --- NEW: Configure Parallel Compilation ---
|
||||
if(NOT SD_PARALLEL_COMPILE_JOBS STREQUAL "0")
|
||||
set(CMAKE_BUILD_PARALLEL_LEVEL ${SD_PARALLEL_COMPILE_JOBS} CACHE STRING "Parallel build level" FORCE)
|
||||
message(STATUS "🔧 Parallel compilation set to ${SD_PARALLEL_COMPILE_JOBS} jobs")
|
||||
else()
|
||||
# Auto-detect number of cores
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(N)
|
||||
if(NOT N EQUAL 0)
|
||||
set(CMAKE_BUILD_PARALLEL_LEVEL ${N} CACHE STRING "Parallel build level" FORCE)
|
||||
message(STATUS "🔧 Auto-detected ${N} cores for parallel compilation")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- NEW: Compiler-specific optimizations for template compilation ---
|
||||
# Template depth: 512 for release (faster compilation), 1024 for debug (deeper nesting support)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||
add_compile_options(-ftemplate-depth=1024)
|
||||
message(STATUS "Using template depth 1024 for ${CMAKE_BUILD_TYPE} build")
|
||||
else()
|
||||
add_compile_options(-ftemplate-depth=512)
|
||||
message(STATUS "Using template depth 512 for ${CMAKE_BUILD_TYPE} build")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
# Enable faster template compilation in GCC 10+
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0)
|
||||
add_compile_options(-fconcepts-diagnostics-depth=2)
|
||||
endif()
|
||||
|
||||
# For development builds, use faster but less optimized compilation
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR SD_FAST_BUILD)
|
||||
add_compile_options(-O0 -fno-inline-functions)
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# For development builds, use faster but less optimized compilation
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR SD_FAST_BUILD)
|
||||
add_compile_options(-O0 -fno-inline-functions)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(BUILD_PPSTEP "Build ppstep preprocessor debugging tool" OFF)
|
||||
|
||||
# --- Helper function for colored status messages ---
|
||||
function(print_status_colored type message)
|
||||
if(type STREQUAL "ERROR")
|
||||
message(FATAL_ERROR "❌ ${message}")
|
||||
elseif(type STREQUAL "WARNING")
|
||||
message(WARNING "⚠️ ${message}")
|
||||
elseif(type STREQUAL "SUCCESS")
|
||||
message(STATUS "✅ ${message}")
|
||||
elseif(type STREQUAL "INFO")
|
||||
message(STATUS "ℹ️ ${message}")
|
||||
elseif(type STREQUAL "DEBUG")
|
||||
message(STATUS "🔍 ${message}")
|
||||
elseif(type STREQUAL "NOTICE")
|
||||
message(NOTICE "📢 ${message}")
|
||||
else()
|
||||
message(STATUS "${message}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# --- NEW: Print build configuration summary ---
|
||||
function(print_build_configuration)
|
||||
message(STATUS "")
|
||||
message(STATUS "=== Template Compilation Configuration ===")
|
||||
message(STATUS "Type Profile: ${SD_TYPE_PROFILE}")
|
||||
message(STATUS "Semantic Filtering: ${SD_ENABLE_SEMANTIC_FILTERING}")
|
||||
message(STATUS "Aggressive Filtering: ${SD_AGGRESSIVE_SEMANTIC_FILTERING}")
|
||||
message(STATUS "Max Template Combinations: ${SD_MAX_TEMPLATE_COMBINATIONS}")
|
||||
message(STATUS "Chunk Target Size: ${CHUNK_TARGET_INSTANTIATIONS}")
|
||||
message(STATUS "Unity Build: ${SD_UNITY_BUILD}")
|
||||
message(STATUS "Fast Build Mode: ${SD_FAST_BUILD}")
|
||||
|
||||
if(DEFINED SD_TYPES_LIST)
|
||||
message(STATUS "Active Types: ${SD_TYPES_LIST}")
|
||||
endif()
|
||||
|
||||
message(STATUS "==========================================")
|
||||
message(STATUS "")
|
||||
endfunction()
|
||||
|
||||
# --- Macro for debugging all CMake variables ---
|
||||
macro(print_all_variables)
|
||||
message(STATUS "print_all_variables------------------------------------------{")
|
||||
get_cmake_property(_variableNames VARIABLES)
|
||||
foreach(_variableName ${_variableNames})
|
||||
message(STATUS "${_variableName}=${${_variableName}}")
|
||||
endforeach()
|
||||
message(STATUS "print_all_variables------------------------------------------}")
|
||||
endmacro()
|
||||
|
||||
# --- NEW: Validation and warnings ---
|
||||
if(SD_TYPE_PROFILE STREQUAL "ESSENTIAL" OR SD_TYPE_PROFILE STREQUAL "TRAINING")
|
||||
message(WARNING "⚠️ Using '${SD_TYPE_PROFILE}' profile will generate many template instantiations and slow compilation. Consider 'MINIMAL' or 'INFERENCE' for faster builds.")
|
||||
endif()
|
||||
|
||||
if(CHUNK_TARGET_INSTANTIATIONS LESS 20)
|
||||
message(WARNING "⚠️ CHUNK_TARGET_INSTANTIATIONS is very low (${CHUNK_TARGET_INSTANTIATIONS}). This will create many small files and slow compilation.")
|
||||
endif()
|
||||
@@ -0,0 +1,101 @@
|
||||
# cmake/Platform.cmake
|
||||
# Detects OS and CPU architecture and sets platform-specific flags.
|
||||
|
||||
# --- Platform and Architecture Detection ---
|
||||
set(SD_X86_BUILD false)
|
||||
set(SD_ARM_BUILD false)
|
||||
if(SD_ANDROID_BUILD)
|
||||
if(ANDROID_ABI MATCHES "x86_64")
|
||||
set(SD_X86_BUILD true)
|
||||
set(SD_ARCH "x86-64")
|
||||
elseif(ANDROID_ABI MATCHES "x86")
|
||||
set(SD_X86_BUILD true)
|
||||
set(SD_ARCH "x86")
|
||||
elseif(ANDROID_ABI MATCHES "arm64-v8a")
|
||||
set(SD_ARM_BUILD true)
|
||||
set(SD_ARCH "arm64-v8a")
|
||||
elseif(ANDROID_ABI MATCHES "armeabi-v7a")
|
||||
set(SD_ARM_BUILD true)
|
||||
set(SD_ARCH "armv7-a")
|
||||
endif()
|
||||
elseif(NOT SD_IOS_BUILD)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64")
|
||||
set(SD_X86_BUILD true)
|
||||
if(NOT DEFINED SD_ARCH OR SD_ARCH STREQUAL "")
|
||||
set(SD_ARCH "x86-64")
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm*|aarch64")
|
||||
set(SD_ARM_BUILD true)
|
||||
if(NOT DEFINED SD_ARCH OR SD_ARCH STREQUAL "")
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
|
||||
set(SD_ARCH "armv8-a")
|
||||
else()
|
||||
set(SD_ARCH "armv7-a")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SD_ARM_BUILD)
|
||||
if(NOT DEFINED SD_ARCH OR SD_ARCH STREQUAL "")
|
||||
message(STATUS "Warning: SD_ARCH was not set for this ARM build. Defaulting to 'armv8-a'.")
|
||||
set(SD_ARCH "armv8-a")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Build flags determined: SD_ANDROID_BUILD=${SD_ANDROID_BUILD}, SD_X86_BUILD=${SD_X86_BUILD}, SD_ARM_BUILD=${SD_ARM_BUILD}, SD_ARCH=${SD_ARCH}")
|
||||
|
||||
# --- Architecture-Specific Tuning ---
|
||||
set(ARCH_TUNE "")
|
||||
if(SD_ARCH MATCHES "armv8")
|
||||
set(ARCH_TUNE "-march=${SD_ARCH}")
|
||||
elseif(SD_ARCH MATCHES "armv7")
|
||||
set(ARCH_TUNE "-march=${SD_ARCH} -mfpu=neon")
|
||||
elseif(SD_EXTENSION MATCHES "avx512")
|
||||
message("Building AVX512 binary...")
|
||||
set(ARCH_TUNE "-mmmx -msse -msse2 -msse3 -msse4.1 -msse4.2 -mavx -mavx2 -mfma -mf16c -mavx512f -mavx512vl -mavx512bw -mavx512dq -mavx512cd -mbmi -mbmi2 -mprefetchwt1 -mclflushopt -mxsavec -mxsaves -DSD_F16C=true -DF_AVX512=true")
|
||||
elseif(SD_EXTENSION MATCHES "avx2")
|
||||
message("Building AVX2 binary...")
|
||||
set(ARCH_TUNE "-mmmx -msse -msse2 -msse3 -msse4.1 -msse4.2 -mavx -mavx2 -mfma -mf16c -mprefetchwt1 -DSD_F16C=true -DF_AVX2=true")
|
||||
if(NO_AVX256_SPLIT)
|
||||
set(ARCH_TUNE "${ARCH_TUNE} -mno-avx256-split-unaligned-load -mno-avx256-split-unaligned-store")
|
||||
endif()
|
||||
elseif(SD_NATIVE)
|
||||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "ppc64*" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm64*")
|
||||
set(ARCH_TUNE "-mcpu=native")
|
||||
else()
|
||||
set(ARCH_TUNE "-march=native")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT ARCH_TUNE STREQUAL "")
|
||||
message(STATUS "Applying architecture tuning flags: ${ARCH_TUNE}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_TUNE}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ARCH_TUNE}")
|
||||
endif()
|
||||
|
||||
# --- OS-Specific Build Flags ---
|
||||
if(SD_APPLE_BUILD)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSD_APPLE_BUILD=true -mmacosx-version-min=10.10")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSD_APPLE_BUILD=true -mmacosx-version-min=10.10")
|
||||
elseif(SD_ARM_BUILD)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSD_ARM_BUILD=true")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSD_ARM_BUILD=true")
|
||||
elseif(SD_ANDROID_BUILD)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSD_ANDROID_BUILD=true")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSD_ANDROID_BUILD=true")
|
||||
elseif(SD_IOS_BUILD)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSD_IOS_BUILD=true")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSD_IOS_BUILD=true")
|
||||
endif()
|
||||
|
||||
# --- External Include Directories ---
|
||||
if(UNIX)
|
||||
link_directories(/usr/local/lib /usr/lib /lib)
|
||||
endif()
|
||||
if(APPLE)
|
||||
message("Using Apple")
|
||||
link_directories(/usr/local/lib /usr/lib /lib)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
list(APPEND EXTERNAL_INCLUDE_DIRS "/usr/include" "/usr/local/include")
|
||||
endif()
|
||||
@@ -0,0 +1,116 @@
|
||||
# PlatformDetection.cmake - Platform and architecture detection
|
||||
|
||||
# Ensure SD_CPU is TRUE if neither SD_CUDA nor SD_CPU is set
|
||||
if(NOT SD_CUDA)
|
||||
if(NOT SD_CPU)
|
||||
set(SD_CUDA FALSE)
|
||||
set(SD_CPU TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Set SD_LIBRARY_NAME Based on Build Type
|
||||
if(NOT DEFINED SD_LIBRARY_NAME)
|
||||
if(SD_CUDA)
|
||||
set(SD_LIBRARY_NAME nd4jcuda)
|
||||
else()
|
||||
set(SD_LIBRARY_NAME nd4jcpu)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Set default engine
|
||||
if(SD_CUDA)
|
||||
set(DEFAULT_ENGINE "samediff::ENGINE_CUDA")
|
||||
else()
|
||||
set(DEFAULT_ENGINE "samediff::ENGINE_CPU")
|
||||
endif()
|
||||
|
||||
# MSVC runtime lib can be either "MultiThreaded" or "MultiThreadedDLL", /MT and /MD respectively
|
||||
set(MSVC_RT_LIB "MultiThreadedDLL")
|
||||
|
||||
# Determine platform type more accurately
|
||||
set(SD_X86_BUILD false)
|
||||
set(SD_ARM_BUILD false)
|
||||
|
||||
if(SD_ANDROID_BUILD)
|
||||
if(ANDROID_ABI MATCHES "x86_64")
|
||||
set(SD_X86_BUILD true)
|
||||
set(SD_ARCH "x86-64")
|
||||
elseif(ANDROID_ABI MATCHES "x86")
|
||||
set(SD_X86_BUILD true)
|
||||
set(SD_ARCH "x86")
|
||||
elseif(ANDROID_ABI MATCHES "arm64-v8a")
|
||||
set(SD_ARM_BUILD true)
|
||||
set(SD_ARCH "arm64-v8a")
|
||||
elseif(ANDROID_ABI MATCHES "armeabi-v7a")
|
||||
set(SD_ARM_BUILD true)
|
||||
set(SD_ARCH "armv7-a")
|
||||
endif()
|
||||
elseif(NOT SD_IOS_BUILD)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64")
|
||||
set(SD_X86_BUILD true)
|
||||
if(NOT DEFINED SD_ARCH OR SD_ARCH STREQUAL "")
|
||||
set(SD_ARCH "x86-64")
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm*|aarch64")
|
||||
set(SD_ARM_BUILD true)
|
||||
if(NOT DEFINED SD_ARCH OR SD_ARCH STREQUAL "")
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
|
||||
set(SD_ARCH "armv8-a")
|
||||
else()
|
||||
set(SD_ARCH "armv7-a")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SD_ARM_BUILD)
|
||||
if(NOT DEFINED SD_ARCH OR SD_ARCH STREQUAL "")
|
||||
message(STATUS "Warning: SD_ARCH was not set for this ARM build. Defaulting to 'armv8-a'.")
|
||||
set(SD_ARCH "armv8-a")
|
||||
endif()
|
||||
|
||||
if(SD_ANDROID)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Define Compiler Flags for Specific Builds
|
||||
if(SD_APPLE_BUILD)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSD_APPLE_BUILD=true -mmacosx-version-min=10.10")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSD_APPLE_BUILD=true -mmacosx-version-min=10.10")
|
||||
endif()
|
||||
|
||||
if(SD_ARM_BUILD)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSD_ARM_BUILD=true")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSD_ARM_BUILD=true")
|
||||
endif()
|
||||
|
||||
if(SD_ANDROID_BUILD)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSD_ANDROID_BUILD=true")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSD_ANDROID_BUILD=true")
|
||||
endif()
|
||||
|
||||
if(SD_IOS_BUILD)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSD_IOS_BUILD=true")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSD_IOS_BUILD=true")
|
||||
endif()
|
||||
|
||||
message(STATUS "Build flags determined: SD_ANDROID_BUILD=${SD_ANDROID_BUILD}, SD_X86_BUILD=${SD_X86_BUILD}, SD_ARM_BUILD=${SD_ARM_BUILD}, SD_ARCH=${SD_ARCH}")
|
||||
|
||||
# Include Directories Based on OS
|
||||
if(UNIX)
|
||||
link_directories(/usr/local/lib /usr/lib /lib)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
message("Using Apple")
|
||||
link_directories(/usr/local/lib /usr/lib /lib)
|
||||
endif()
|
||||
|
||||
# External Include Directories
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
list(APPEND EXTERNAL_INCLUDE_DIRS "/usr/include" "/usr/local/include")
|
||||
endif()
|
||||
|
||||
# Initialize job pools for parallel builds
|
||||
set_property(GLOBAL PROPERTY JOB_POOLS one_jobs=1 two_jobs=2)
|
||||
@@ -0,0 +1,292 @@
|
||||
################################################################################
|
||||
# Platform Optimization Functions
|
||||
# Platform-specific compiler optimizations and build configurations
|
||||
################################################################################
|
||||
|
||||
# Function to apply Android x86_64 PLT fixes for large template libraries
|
||||
function(apply_android_x86_64_plt_fixes target_name)
|
||||
if(NOT (SD_ANDROID_BUILD AND ANDROID_ABI MATCHES "x86_64"))
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
target_compile_options(${target_name} PRIVATE
|
||||
-ffunction-sections
|
||||
-fdata-sections
|
||||
-fvisibility=hidden
|
||||
-fvisibility-inlines-hidden
|
||||
-fno-plt
|
||||
-fno-semantic-interposition
|
||||
)
|
||||
else()
|
||||
# MSVC equivalent flags
|
||||
target_compile_options(${target_name} PRIVATE
|
||||
/Gy # Function-level linking
|
||||
)
|
||||
endif()
|
||||
|
||||
# Target-specific preprocessor definitions
|
||||
target_compile_definitions(${target_name} PRIVATE
|
||||
ANDROID_X86_64_OPTIMIZED=1
|
||||
)
|
||||
|
||||
# Apply linker flags only to shared/executable targets
|
||||
get_target_property(target_type ${target_name} TYPE)
|
||||
|
||||
|
||||
message(STATUS "Applied verified Android x86_64 optimizations to target: ${target_name}")
|
||||
endfunction()
|
||||
|
||||
# Comprehensive linker configuration for large template libraries
|
||||
function(configure_large_template_linker)
|
||||
if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND SD_X86_BUILD))
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "Configuring linker for large template library with PLT overflow prevention")
|
||||
|
||||
# Clear any existing conflicting linker flags
|
||||
string(REGEX REPLACE "-fuse-ld=[a-zA-Z]+" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
string(REGEX REPLACE "-fuse-ld=[a-zA-Z]+" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
|
||||
# Test if linker supports --plt-align before using it
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_LINKER} --help
|
||||
OUTPUT_VARIABLE LD_HELP_OUTPUT
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
string(FIND "${LD_HELP_OUTPUT}" "--plt-align" PLT_ALIGN_SUPPORTED)
|
||||
|
||||
|
||||
message(STATUS "Applied PLT overflow prevention for large template library")
|
||||
endfunction()
|
||||
|
||||
# Function to configure memory model based on architecture
|
||||
function(configure_memory_model)
|
||||
# Memory model is now configured in CompilerFlags.cmake to avoid conflicts
|
||||
# (Sanitizer builds use -mcmodel=large, non-sanitizer builds use -mcmodel=medium)
|
||||
if(SD_X86_BUILD AND NOT WIN32)
|
||||
# Removed: -mcmodel setting now in CompilerFlags.cmake only
|
||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcmodel=medium -fPIC" PARENT_SCOPE)
|
||||
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcmodel=medium" PARENT_SCOPE)
|
||||
message(STATUS "Memory model configuration deferred to CompilerFlags.cmake")
|
||||
else()
|
||||
if(SD_ARM_BUILD OR SD_ANDROID_BUILD)
|
||||
message(STATUS "Skipping large memory model for ARM/Android architecture (not supported)")
|
||||
elseif(WIN32)
|
||||
message(STATUS "Skipping large memory model for Windows (using alternative approach)")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to apply memory optimization during compilation
|
||||
function(configure_compilation_memory_optimization)
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --param ggc-min-expand=100 --param ggc-min-heapsize=131072" PARENT_SCOPE)
|
||||
message(STATUS "Applied GCC memory optimization flags")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to configure section splitting for better linker handling
|
||||
function(configure_section_splitting)
|
||||
# MSVC-specific optimizations
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
# MSVC equivalent optimizations
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Gy" PARENT_SCOPE) # Function-level linking
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gy" PARENT_SCOPE) # Function-level linking
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /OPT:REF /OPT:ICF" PARENT_SCOPE) # Remove unreferenced code
|
||||
message(STATUS "Applied MSVC function-level linking optimizations")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
# Function to disable PLT completely for memory issues
|
||||
function(configure_plt_disable)
|
||||
# For CUDA builds, disable PLT in host compiler flags
|
||||
if(SD_CUDA AND CMAKE_CUDA_COMPILER)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler -fno-plt" PARENT_SCOPE)
|
||||
message(STATUS "Disabled PLT for CUDA host compiler")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to determine platform type accurately
|
||||
function(determine_platform_type)
|
||||
set(SD_X86_BUILD false PARENT_SCOPE)
|
||||
set(SD_ARM_BUILD false PARENT_SCOPE)
|
||||
|
||||
if(SD_ANDROID_BUILD)
|
||||
if(ANDROID_ABI MATCHES "x86_64")
|
||||
set(SD_X86_BUILD true PARENT_SCOPE)
|
||||
set(SD_ARCH "x86-64" PARENT_SCOPE)
|
||||
elseif(ANDROID_ABI MATCHES "x86")
|
||||
set(SD_X86_BUILD true PARENT_SCOPE)
|
||||
set(SD_ARCH "x86" PARENT_SCOPE)
|
||||
elseif(ANDROID_ABI MATCHES "arm64-v8a")
|
||||
set(SD_ARM_BUILD true PARENT_SCOPE)
|
||||
set(SD_ARCH "arm64-v8a" PARENT_SCOPE)
|
||||
elseif(ANDROID_ABI MATCHES "armeabi-v7a")
|
||||
set(SD_ARM_BUILD true PARENT_SCOPE)
|
||||
set(SD_ARCH "armv7-a" PARENT_SCOPE)
|
||||
endif()
|
||||
elseif(NOT SD_IOS_BUILD)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64")
|
||||
set(SD_X86_BUILD true PARENT_SCOPE)
|
||||
if(NOT DEFINED SD_ARCH OR SD_ARCH STREQUAL "")
|
||||
set(SD_ARCH "x86-64" PARENT_SCOPE)
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm*|aarch64")
|
||||
set(SD_ARM_BUILD true PARENT_SCOPE)
|
||||
if(NOT DEFINED SD_ARCH OR SD_ARCH STREQUAL "")
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
|
||||
set(SD_ARCH "armv8-a" PARENT_SCOPE)
|
||||
else()
|
||||
set(SD_ARCH "armv7-a" PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Set default for ARM builds if not specified
|
||||
if(SD_ARM_BUILD)
|
||||
if(NOT DEFINED SD_ARCH OR SD_ARCH STREQUAL "")
|
||||
message(STATUS "Warning: SD_ARCH was not set for this ARM build. Defaulting to 'armv8-a'.")
|
||||
set(SD_ARCH "armv8-a" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(SD_ANDROID)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Platform detection results: SD_X86_BUILD=${SD_X86_BUILD}, SD_ARM_BUILD=${SD_ARM_BUILD}, SD_ARCH=${SD_ARCH}")
|
||||
endfunction()
|
||||
|
||||
# Function to configure architecture tuning
|
||||
function(configure_architecture_tuning)
|
||||
if(SD_ARCH MATCHES "armv8")
|
||||
set(ARCH_TUNE "-march=${SD_ARCH}" PARENT_SCOPE)
|
||||
message(STATUS "ARM64 architecture tuning: ${SD_ARCH}")
|
||||
elseif(SD_ARCH MATCHES "armv7")
|
||||
set(ARCH_TUNE "-march=${SD_ARCH} -mfpu=neon" PARENT_SCOPE)
|
||||
message(STATUS "ARM32 architecture tuning: ${SD_ARCH} with NEON")
|
||||
elseif(SD_EXTENSION MATCHES "avx2")
|
||||
message(STATUS "Building AVX2 binary...")
|
||||
set(ARCH_TUNE "-mmmx -msse -msse2 -msse3 -msse4.1 -msse4.2 -mavx -mavx2 -mfma -mf16c -mprefetchwt1 -DSD_F16C=true -DF_AVX2=true" PARENT_SCOPE)
|
||||
if(NO_AVX256_SPLIT)
|
||||
set(ARCH_TUNE "${ARCH_TUNE} -mno-avx256-split-unaligned-load -mno-avx256-split-unaligned-store" PARENT_SCOPE)
|
||||
endif()
|
||||
else()
|
||||
if("${SD_ARCH}" STREQUAL "x86-64")
|
||||
message(STATUS "Building x86_64 binary...")
|
||||
set(ARCH_TYPE "generic")
|
||||
add_compile_definitions(F_X64=true)
|
||||
else()
|
||||
set(ARCH_TYPE "${SD_ARCH}")
|
||||
endif()
|
||||
|
||||
if(SD_EXTENSION MATCHES "avx512")
|
||||
message(STATUS "Building AVX512 binary...")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmmx -msse -msse2 -msse3 -msse4.1 -msse4.2 -mavx -mavx2 -mfma -mf16c -mavx512f -mavx512vl -mavx512bw -mavx512dq -mavx512cd -mbmi -mbmi2 -mprefetchwt1 -mclflushopt -mxsavec -mxsaves -DSD_F16C=true -DF_AVX512=true" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32 AND NOT SD_CUDA)
|
||||
if(DEFINED SD_ARCH AND NOT SD_ARCH STREQUAL "" AND DEFINED ARCH_TYPE AND NOT ARCH_TYPE STREQUAL "")
|
||||
set(ARCH_TUNE "-march=${SD_ARCH} -mtune=${ARCH_TYPE}" PARENT_SCOPE)
|
||||
elseif(DEFINED SD_ARCH AND NOT SD_ARCH STREQUAL "")
|
||||
# Fallback if ARCH_TYPE is not set
|
||||
set(ARCH_TUNE "-march=${SD_ARCH}" PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to apply compiler-specific flags with architecture tuning
|
||||
function(apply_compiler_specific_flags ARCH_TUNE)
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND SD_X86_BUILD)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_TUNE}" PARENT_SCOPE)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_TUNE}" PARENT_SCOPE)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_TUNE} -O${SD_OPTIMIZATION_LEVEL} -fp-model fast" PARENT_SCOPE)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_TUNE}" PARENT_SCOPE)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT SD_CUDA)
|
||||
message(STATUS "Adding GCC memory optimization flag: --param ggc-min-expand=10")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --param ggc-min-expand=10 ${ARCH_TUNE} ${INFORMATIVE_FLAGS} -std=c++17 -fPIC" PARENT_SCOPE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --param ggc-min-expand=10 -fPIC" PARENT_SCOPE)
|
||||
|
||||
|
||||
if(UNIX)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath,$ORIGIN/,-z,--no-undefined,--verbose" PARENT_SCOPE)
|
||||
else()
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath,$ORIGIN/,--no-undefined,--verbose" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT APPLE AND NOT WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic -Wl,-export-dynamic,--verbose" PARENT_SCOPE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -export-dynamic,--verbose" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(SD_GCC_FUNCTRACE)
|
||||
set(COMPILER_IS_NVCC false)
|
||||
get_filename_component(COMPILER_NAME ${CMAKE_CXX_COMPILER} NAME)
|
||||
if(COMPILER_NAME MATCHES "^nvcc")
|
||||
set(COMPILER_IS_NVCC TRUE)
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{OMPI_CXX} OR DEFINED ENV{MPICH_CXX})
|
||||
if("$ENV{OMPI_CXX}" MATCHES "nvcc" OR "$ENV{MPICH_CXX}" MATCHES "nvcc")
|
||||
set(COMPILER_IS_NVCC TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE PARENT_SCOPE)
|
||||
if(COMPILER_IS_NVCC)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-backtrace-limit=0 -gno-record-gcc-switches -ftrack-macro-expansion=0 -fstack-protector -fstack-protector-all -Wall -Wextra -Wno-return-type -Wno-error=int-in-bool-context -Wno-unused-variable -Wno-error=implicit-fallthrough -Wno-return-type -Wno-unused-parameter -Wno-error=unknown-pragmas -ggdb3 -pthread -MT -Bsymbolic -rdynamic -fno-omit-frame-pointer -fno-optimize-sibling-calls -rdynamic -finstrument-functions -O0 -fPIC" PARENT_SCOPE)
|
||||
|
||||
# Session #1045 FIX: Removed -lunwind - conflicts with JVM's libgcc_s causing _Unwind_SetGR crashes
|
||||
# Use system libgcc_s for exception handling (JVM compatible)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lpthread -lbfd -ldw -ldl -lelf" PARENT_SCOPE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lpthread -lbfd -ldw -ldl -lelf" PARENT_SCOPE)
|
||||
|
||||
add_compile_definitions(SD_GCC_FUNCTRACE=ON)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Main function to setup all platform optimizations
|
||||
function(setup_platform_optimizations)
|
||||
message(STATUS "Setting up platform-specific optimizations...")
|
||||
|
||||
# Determine platform type
|
||||
determine_platform_type()
|
||||
|
||||
# Configure PLT disable
|
||||
configure_plt_disable()
|
||||
|
||||
# Configure memory model
|
||||
configure_memory_model()
|
||||
|
||||
# Configure compilation memory optimization
|
||||
configure_compilation_memory_optimization()
|
||||
|
||||
# Configure section splitting
|
||||
configure_section_splitting()
|
||||
|
||||
# Configure large template linker
|
||||
configure_large_template_linker()
|
||||
|
||||
# Configure architecture tuning
|
||||
configure_architecture_tuning()
|
||||
|
||||
# Apply architecture tuning based on calculated ARCH_TUNE
|
||||
if(DEFINED ARCH_TUNE)
|
||||
apply_compiler_specific_flags("${ARCH_TUNE}")
|
||||
endif()
|
||||
|
||||
message(STATUS "Platform optimizations setup complete")
|
||||
endfunction()
|
||||
@@ -0,0 +1,399 @@
|
||||
# cmake/PostBuild.cmake
|
||||
# Configures optional post-build targets like tests and analysis tools.
|
||||
|
||||
# ============================================================================
|
||||
# HELPER FUNCTION: Write file only if content changed (preserves mtime for PCH)
|
||||
# This prevents PCH invalidation during builds when config.h content is identical
|
||||
# ============================================================================
|
||||
function(_postbuild_write_if_different filepath content)
|
||||
set(should_write TRUE)
|
||||
|
||||
# Check if file already exists
|
||||
if(EXISTS "${filepath}")
|
||||
# Read existing content
|
||||
file(READ "${filepath}" existing_content)
|
||||
|
||||
# Compare content
|
||||
if("${existing_content}" STREQUAL "${content}")
|
||||
set(should_write FALSE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Only write if content changed or file doesn't exist
|
||||
if(should_write)
|
||||
file(WRITE "${filepath}" "${content}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# --- Configuration file ---
|
||||
# Build TYPE_DEFINES string from current type configuration
|
||||
# This ensures JavaCPP sees the same type availability as the CMake build
|
||||
set(TYPE_DEFINES "")
|
||||
|
||||
# Check if we're in selective types mode
|
||||
if(DEFINED SD_TYPES_LIST AND NOT SD_TYPES_LIST STREQUAL "")
|
||||
# Selective types mode - export only enabled types
|
||||
# The HAS_* macros were already set by apply_type_definitions_to_target
|
||||
# We need to capture them and add to TYPE_DEFINES
|
||||
|
||||
# Get all HAS_* definitions that were set
|
||||
get_directory_property(COMPILE_DEFS COMPILE_DEFINITIONS)
|
||||
foreach(def IN LISTS COMPILE_DEFS)
|
||||
if(def MATCHES "^HAS_")
|
||||
string(APPEND TYPE_DEFINES "#define ${def}\n")
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
# All types mode - define all HAS_* macros
|
||||
string(APPEND TYPE_DEFINES "#define HAS_BOOL 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_FLOAT 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_FLOAT32 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_DOUBLE 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_FLOAT64 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_FLOAT16 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_HALF 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_BFLOAT16 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_BFLOAT 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_FLOAT8 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_HALF2 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT8 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT8_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT16 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT16_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT32 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT32_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT64 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_INT64_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_LONG 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT8 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT8_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT16 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT16_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT32 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT32_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT64 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UINT64_T 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UNSIGNEDLONG 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UTF8 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_STD_STRING 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UTF16 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_STD_U16STRING 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_UTF32 1\n")
|
||||
string(APPEND TYPE_DEFINES "#define HAS_STD_U32STRING 1\n")
|
||||
endif()
|
||||
|
||||
# Generate config.h with write-if-different to preserve PCH
|
||||
# This prevents PCH invalidation during the build when content hasn't changed
|
||||
set(CONFIG_H_IN "${CMAKE_CURRENT_SOURCE_DIR}/include/config.h.in")
|
||||
set(CONFIG_H_OUT "${CMAKE_CURRENT_BINARY_DIR}/include/config.h")
|
||||
|
||||
# Read the template
|
||||
file(READ "${CONFIG_H_IN}" CONFIG_H_CONTENT)
|
||||
|
||||
# Perform variable substitutions (mimics configure_file behavior)
|
||||
# Handle cmakedefine01 directives
|
||||
if(HAVE_ONEDNN)
|
||||
string(REPLACE "#cmakedefine01 HAVE_ONEDNN" "#define HAVE_ONEDNN 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
else()
|
||||
string(REPLACE "#cmakedefine01 HAVE_ONEDNN" "#define HAVE_ONEDNN 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
endif()
|
||||
|
||||
if(HAVE_ARMCOMPUTE)
|
||||
string(REPLACE "#cmakedefine01 HAVE_ARMCOMPUTE" "#define HAVE_ARMCOMPUTE 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
else()
|
||||
string(REPLACE "#cmakedefine01 HAVE_ARMCOMPUTE" "#define HAVE_ARMCOMPUTE 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
endif()
|
||||
|
||||
if(HAVE_CUDNN)
|
||||
string(REPLACE "#cmakedefine01 HAVE_CUDNN" "#define HAVE_CUDNN 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
else()
|
||||
string(REPLACE "#cmakedefine01 HAVE_CUDNN" "#define HAVE_CUDNN 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
endif()
|
||||
|
||||
if(HAVE_OPENBLAS)
|
||||
string(REPLACE "#cmakedefine01 HAVE_OPENBLAS" "#define HAVE_OPENBLAS 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
else()
|
||||
string(REPLACE "#cmakedefine01 HAVE_OPENBLAS" "#define HAVE_OPENBLAS 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
endif()
|
||||
|
||||
if(HAVE_FLATBUFFERS)
|
||||
string(REPLACE "#cmakedefine01 HAVE_FLATBUFFERS" "#define HAVE_FLATBUFFERS 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
else()
|
||||
string(REPLACE "#cmakedefine01 HAVE_FLATBUFFERS" "#define HAVE_FLATBUFFERS 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
endif()
|
||||
|
||||
if(SD_SELECTIVE_TYPES)
|
||||
string(REPLACE "#cmakedefine01 SD_SELECTIVE_TYPES" "#define SD_SELECTIVE_TYPES 1" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
else()
|
||||
string(REPLACE "#cmakedefine01 SD_SELECTIVE_TYPES" "#define SD_SELECTIVE_TYPES 0" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
endif()
|
||||
|
||||
# Handle @VAR@ substitutions
|
||||
if(DEFINED SD_LIBRARY_NAME)
|
||||
string(REPLACE "@SD_LIBRARY_NAME@" "${SD_LIBRARY_NAME}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
else()
|
||||
# Remove the line if variable not defined
|
||||
string(REGEX REPLACE "#cmakedefine SD_LIBRARY_NAME[^\n]*\n" "" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
endif()
|
||||
|
||||
if(DEFINED ONEDNN_PATH)
|
||||
string(REPLACE "@ONEDNN_PATH@" "${ONEDNN_PATH}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
else()
|
||||
string(REGEX REPLACE "#cmakedefine ONEDNN_PATH[^\n]*\n" "" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
endif()
|
||||
|
||||
if(DEFINED OPENBLAS_PATH)
|
||||
string(REPLACE "@OPENBLAS_PATH@" "${OPENBLAS_PATH}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
else()
|
||||
string(REGEX REPLACE "#cmakedefine OPENBLAS_PATH[^\n]*\n" "" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
endif()
|
||||
|
||||
if(DEFINED FLATBUFFERS_PATH)
|
||||
string(REPLACE "@FLATBUFFERS_PATH@" "${FLATBUFFERS_PATH}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
else()
|
||||
string(REGEX REPLACE "#cmakedefine FLATBUFFERS_PATH[^\n]*\n" "" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
endif()
|
||||
|
||||
if(DEFINED DEFAULT_ENGINE)
|
||||
string(REPLACE "@DEFAULT_ENGINE@" "${DEFAULT_ENGINE}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
else()
|
||||
string(REGEX REPLACE "#cmakedefine DEFAULT_ENGINE[^\n]*\n" "" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
endif()
|
||||
|
||||
# Substitute TYPE_DEFINES
|
||||
string(REPLACE "@TYPE_DEFINES@" "${TYPE_DEFINES}" CONFIG_H_CONTENT "${CONFIG_H_CONTENT}")
|
||||
|
||||
# Write config.h only if content changed (preserves mtime for PCH)
|
||||
_postbuild_write_if_different("${CONFIG_H_OUT}" "${CONFIG_H_CONTENT}")
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
# --- Flatbuffers Header and Java Generation ---
|
||||
if(DEFINED ENV{GENERATE_FLATC} OR DEFINED GENERATE_FLATC)
|
||||
set(FLATC_EXECUTABLE "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build/flatc")
|
||||
set(MAIN_GENERATED_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/graph/generated.h")
|
||||
add_custom_command(
|
||||
OUTPUT ${MAIN_GENERATED_HEADER}
|
||||
COMMAND ${CMAKE_COMMAND} -E env "FLATC_PATH=${FLATC_EXECUTABLE}" bash ${CMAKE_CURRENT_SOURCE_DIR}/flatc-generate.sh
|
||||
DEPENDS flatbuffers_external
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Running flatc to generate C++ headers"
|
||||
VERBATIM
|
||||
)
|
||||
add_custom_target(generate_flatbuffers_headers DEPENDS ${MAIN_GENERATED_HEADER})
|
||||
add_custom_command(
|
||||
TARGET generate_flatbuffers_headers POST_BUILD
|
||||
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/copy-flatc-java.sh
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Copying generated Java files"
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
if(SD_EXTRACT_INSTANTIATIONS)
|
||||
include(ExtractInstantiations)
|
||||
|
||||
endif()
|
||||
|
||||
# --- Self-Contained Preprocessing Target ---
|
||||
if(SD_PREPROCESS)
|
||||
message("Preprocessing enabled: ${CMAKE_BINARY_DIR}")
|
||||
message("Setting up self-contained preprocessing with FlatBuffers...")
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
# Build FlatBuffers for preprocessing (minimal build, just need headers)
|
||||
set(PREPROCESS_FLATBUFFERS_VERSION "25.2.10")
|
||||
set(PREPROCESS_FLATBUFFERS_URL "https://github.com/google/flatbuffers/archive/v${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz")
|
||||
set(PREPROCESS_FB_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/preprocess-flatbuffers-src")
|
||||
set(PREPROCESS_FB_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/preprocess-flatbuffers-build")
|
||||
|
||||
# Check if we already have FlatBuffers headers
|
||||
set(PREPROCESS_FB_HEADER "${PREPROCESS_FB_SOURCE_DIR}/include/flatbuffers/flatbuffers.h")
|
||||
if(NOT EXISTS ${PREPROCESS_FB_HEADER})
|
||||
message("Downloading and extracting FlatBuffers for preprocessing...")
|
||||
|
||||
# Download and extract FlatBuffers
|
||||
file(DOWNLOAD ${PREPROCESS_FLATBUFFERS_URL}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz"
|
||||
SHOW_PROGRESS
|
||||
STATUS download_status)
|
||||
|
||||
list(GET download_status 0 download_result)
|
||||
if(NOT download_result EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to download FlatBuffers for preprocessing")
|
||||
endif()
|
||||
|
||||
# Extract the archive
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E tar xzf "flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}.tar.gz"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
RESULT_VARIABLE extract_result
|
||||
)
|
||||
|
||||
if(NOT extract_result EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to extract FlatBuffers for preprocessing")
|
||||
endif()
|
||||
|
||||
# Move the extracted directory to our expected location
|
||||
file(RENAME "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-${PREPROCESS_FLATBUFFERS_VERSION}"
|
||||
"${PREPROCESS_FB_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
# Verify FlatBuffers headers are now available
|
||||
if(NOT EXISTS ${PREPROCESS_FB_HEADER})
|
||||
message(FATAL_ERROR "FlatBuffers headers not found for preprocessing: ${PREPROCESS_FB_HEADER}")
|
||||
endif()
|
||||
|
||||
message("✅ FlatBuffers headers available for preprocessing: ${PREPROCESS_FB_SOURCE_DIR}/include")
|
||||
|
||||
# Get ALL subdirectories under include/ and add the root include directory first
|
||||
set(all_includes "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
file(GLOB_RECURSE all_dirs LIST_DIRECTORIES true "${CMAKE_CURRENT_SOURCE_DIR}/include/*")
|
||||
foreach(item ${all_dirs})
|
||||
if(IS_DIRECTORY ${item})
|
||||
list(APPEND all_includes ${item})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Add binary include directory
|
||||
list(APPEND all_includes "${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||
|
||||
# Also add build directories
|
||||
list(APPEND all_includes
|
||||
"${CMAKE_SOURCE_DIR}/include/"
|
||||
"${CMAKE_SOURCE_DIR}/include/system"
|
||||
"${CMAKE_BINARY_DIR}/compilation_units"
|
||||
"${CMAKE_BINARY_DIR}/cpu_instantiations"
|
||||
"${CMAKE_BINARY_DIR}/cuda_instantiations"
|
||||
"${CMAKE_BINARY_DIR}/include"
|
||||
)
|
||||
|
||||
# Add our self-contained FlatBuffers include directory
|
||||
list(APPEND all_includes "${PREPROCESS_FB_SOURCE_DIR}/include")
|
||||
|
||||
# Build include flags
|
||||
set(include_flags "")
|
||||
foreach(dir IN LISTS all_includes)
|
||||
if(EXISTS ${dir})
|
||||
string(APPEND include_flags " -I${dir}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(defs_flags "")
|
||||
|
||||
# Add basic platform definitions
|
||||
string(APPEND defs_flags " -D__CPUBLAS__=true")
|
||||
if(SD_CUDA)
|
||||
string(APPEND defs_flags " -D__CUDABLAS__=true -DHAVE_CUDA=1")
|
||||
endif()
|
||||
if(HAVE_OPENBLAS)
|
||||
string(APPEND defs_flags " -DHAVE_OPENBLAS=1")
|
||||
endif()
|
||||
|
||||
if(SD_ALL_OPS OR "${SD_OPS_LIST}" STREQUAL "")
|
||||
string(APPEND defs_flags " -DSD_ALL_OPS=1")
|
||||
# When SD_ALL_OPS=1, NOT_EXCLUDED should evaluate to 1 for all ops
|
||||
string(APPEND defs_flags " -DNOT_EXCLUDED(x)=1")
|
||||
else()
|
||||
# Add specific operation definitions
|
||||
foreach(OP ${SD_OPS_LIST})
|
||||
string(APPEND defs_flags " -DOP_${OP}=1")
|
||||
endforeach()
|
||||
# Define NOT_EXCLUDED macro for selective ops
|
||||
string(APPEND defs_flags " -DNOT_EXCLUDED(x)=\\(defined\\(x\\)\\)")
|
||||
endif()
|
||||
|
||||
# Add build type definitions
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
string(APPEND defs_flags " -DDEBUG=1 -D_DEBUG=1")
|
||||
else()
|
||||
string(APPEND defs_flags " -DNDEBUG=1")
|
||||
endif()
|
||||
|
||||
# Add any additional compile definitions from the main build
|
||||
if(compile_defs AND NOT compile_defs STREQUAL "compile_defs-NOTFOUND")
|
||||
foreach(def IN LISTS compile_defs)
|
||||
string(APPEND defs_flags " -D${def}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set(PREPROCESSED_DIR "${CMAKE_SOURCE_DIR}/preprocessed")
|
||||
file(MAKE_DIRECTORY ${PREPROCESSED_DIR})
|
||||
|
||||
set(PREPROCESSED_FILES)
|
||||
set(PROCESSED_SOURCES "")
|
||||
|
||||
# Use ALL_SOURCES from global scope
|
||||
if(DEFINED ALL_SOURCES AND ALL_SOURCES)
|
||||
set(SOURCE_LIST ${ALL_SOURCES})
|
||||
elseif(DEFINED ALL_SOURCES_LIST AND ALL_SOURCES_LIST)
|
||||
set(SOURCE_LIST ${ALL_SOURCES_LIST})
|
||||
else()
|
||||
message(WARNING "No source list available for preprocessing. Skipping.")
|
||||
add_custom_target(preprocess_sources ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Preprocessing skipped - no source files available")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(LENGTH SOURCE_LIST source_count)
|
||||
message("Starting preprocessing of ${source_count} source files...")
|
||||
message("Operation definitions: SD_ALL_OPS=${SD_ALL_OPS}, SD_OPS_LIST=${SD_OPS_LIST}")
|
||||
|
||||
foreach(src IN LISTS SOURCE_LIST)
|
||||
if(NOT EXISTS ${src} OR NOT src MATCHES "\\.(c|cpp|cxx|cc|cu)$")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
if(NOT src IN_LIST PROCESSED_SOURCES)
|
||||
get_filename_component(src_name ${src} NAME_WE)
|
||||
get_filename_component(src_path ${src} PATH)
|
||||
file(RELATIVE_PATH rel_path ${CMAKE_SOURCE_DIR} ${src_path})
|
||||
string(REPLACE "/" "_" src_dir_ "${rel_path}")
|
||||
set(preprocessed_file "${PREPROCESSED_DIR}/${src_dir_}_${src_name}.i")
|
||||
|
||||
if(NOT EXISTS "${preprocessed_file}")
|
||||
if(src MATCHES "\\.cu$")
|
||||
set(compiler "${CMAKE_CUDA_COMPILER}")
|
||||
set(lang_flags "${CMAKE_CUDA_FLAGS} ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}}")
|
||||
elseif(src MATCHES "\\.c$")
|
||||
set(compiler "${CMAKE_C_COMPILER}")
|
||||
set(lang_flags "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}}")
|
||||
else()
|
||||
set(compiler "${CMAKE_CXX_COMPILER}")
|
||||
set(lang_flags "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}")
|
||||
endif()
|
||||
|
||||
# Split the flags properly for execute_process
|
||||
separate_arguments(lang_flags_list UNIX_COMMAND "${lang_flags}")
|
||||
separate_arguments(defs_flags_list UNIX_COMMAND "${defs_flags}")
|
||||
separate_arguments(include_flags_list UNIX_COMMAND "${include_flags}")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${compiler} -E -P -C ${lang_flags_list} ${defs_flags_list} ${include_flags_list} "${src}" -o "${preprocessed_file}"
|
||||
RESULT_VARIABLE result
|
||||
ERROR_VARIABLE error_output
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
)
|
||||
if(result EQUAL 0)
|
||||
list(APPEND PREPROCESSED_FILES ${preprocessed_file})
|
||||
message(STATUS "✅ Preprocessed: ${src}")
|
||||
else()
|
||||
message(WARNING "❌ Failed to preprocess ${src}")
|
||||
message(WARNING " Error: ${error_output}")
|
||||
endif()
|
||||
else()
|
||||
list(APPEND PREPROCESSED_FILES ${preprocessed_file})
|
||||
message(STATUS "✓ Already preprocessed: ${src}")
|
||||
endif()
|
||||
list(APPEND PROCESSED_SOURCES ${src})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list(LENGTH PREPROCESSED_FILES processed_count)
|
||||
message("✅ Preprocessing complete. Generated ${processed_count} preprocessed files in ${PREPROCESSED_DIR}")
|
||||
add_custom_target(preprocess_sources ALL DEPENDS ${PREPROCESSED_FILES})
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,480 @@
|
||||
# cmake/Ppstep.cmake
|
||||
# Builds ppstep preprocessor tool with robust include path discovery
|
||||
|
||||
if(BUILD_PPSTEP)
|
||||
message(STATUS "🔧 PPSTEP BUILD MODE - Building ppstep tool only")
|
||||
message(STATUS "Setting up ppstep build in: ${CMAKE_BINARY_DIR}")
|
||||
|
||||
# Check for Boost (required for ppstep)
|
||||
find_package(Boost COMPONENTS system filesystem program_options thread wave QUIET)
|
||||
|
||||
if(NOT Boost_FOUND)
|
||||
message(FATAL_ERROR "❌ Boost not found - cannot build ppstep. Install with: apt-get install libboost-all-dev")
|
||||
endif()
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
# Configure ppstep as external project
|
||||
set(PPSTEP_PREFIX "${CMAKE_BINARY_DIR}/ppstep_external")
|
||||
set(PPSTEP_SOURCE_DIR "${PPSTEP_PREFIX}/src/ppstep")
|
||||
set(PPSTEP_BUILD_DIR "${PPSTEP_PREFIX}/build")
|
||||
|
||||
# Clean up any previous failed attempts
|
||||
if(EXISTS "${PPSTEP_PREFIX}/src/ppstep_build-stamp")
|
||||
file(REMOVE_RECURSE "${PPSTEP_PREFIX}/src/ppstep_build-stamp")
|
||||
endif()
|
||||
|
||||
message(STATUS "Cloning and building ppstep...")
|
||||
|
||||
# Set up CMAKE_ARGS conditionally to avoid empty values
|
||||
set(PPSTEP_CMAKE_ARGS
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
)
|
||||
|
||||
if(CMAKE_CXX_COMPILER)
|
||||
list(APPEND PPSTEP_CMAKE_ARGS -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER)
|
||||
list(APPEND PPSTEP_CMAKE_ARGS -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER})
|
||||
endif()
|
||||
|
||||
if(BOOST_ROOT)
|
||||
list(APPEND PPSTEP_CMAKE_ARGS -DBOOST_ROOT=${BOOST_ROOT})
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(ppstep_build
|
||||
PREFIX "${PPSTEP_PREFIX}"
|
||||
GIT_REPOSITORY "https://github.com/agibsonccc/ppstep.git"
|
||||
GIT_TAG "master"
|
||||
GIT_SHALLOW TRUE
|
||||
SOURCE_DIR "${PPSTEP_SOURCE_DIR}"
|
||||
BINARY_DIR "${PPSTEP_BUILD_DIR}"
|
||||
STAMP_DIR "${PPSTEP_PREFIX}/stamp"
|
||||
TMP_DIR "${PPSTEP_PREFIX}/tmp"
|
||||
DOWNLOAD_DIR "${PPSTEP_PREFIX}/download"
|
||||
CMAKE_ARGS ${PPSTEP_CMAKE_ARGS}
|
||||
BUILD_COMMAND make
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_BYPRODUCTS "${PPSTEP_BUILD_DIR}/ppstep"
|
||||
LOG_DOWNLOAD TRUE
|
||||
LOG_CONFIGURE TRUE
|
||||
LOG_BUILD TRUE
|
||||
)
|
||||
|
||||
# ============================================================================
|
||||
# ROBUST INCLUDE PATH DISCOVERY AT CMAKE CONFIGURE TIME
|
||||
# ============================================================================
|
||||
|
||||
message(STATUS "Discovering system include paths...")
|
||||
|
||||
set(DISCOVERED_INCLUDE_PATHS "")
|
||||
|
||||
# Method 1: Use CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES
|
||||
foreach(dir ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
|
||||
if(EXISTS "${dir}")
|
||||
list(APPEND DISCOVERED_INCLUDE_PATHS "${dir}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Method 2: Get from compiler using execute_process
|
||||
if(CMAKE_CXX_COMPILER)
|
||||
# Get verbose output from compiler
|
||||
execute_process(
|
||||
COMMAND echo ""
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -E -x c++ -Wp,-v -
|
||||
OUTPUT_VARIABLE COMPILER_OUTPUT
|
||||
ERROR_VARIABLE COMPILER_ERROR
|
||||
INPUT_FILE /dev/null
|
||||
RESULT_VARIABLE COMPILER_RESULT
|
||||
)
|
||||
|
||||
# Parse the output to extract include paths
|
||||
string(REGEX MATCHALL "#include [<\"].*[>\"] search starts here:.*End of search list" INCLUDE_SECTION "${COMPILER_ERROR}")
|
||||
if(INCLUDE_SECTION)
|
||||
string(REGEX REPLACE "#include [<\"].*[>\"] search starts here:" "" INCLUDE_SECTION "${INCLUDE_SECTION}")
|
||||
string(REGEX REPLACE "End of search list" "" INCLUDE_SECTION "${INCLUDE_SECTION}")
|
||||
string(REGEX REPLACE "\n" ";" INCLUDE_LINES "${INCLUDE_SECTION}")
|
||||
|
||||
foreach(line ${INCLUDE_LINES})
|
||||
string(STRIP "${line}" line)
|
||||
if(EXISTS "${line}")
|
||||
list(APPEND DISCOVERED_INCLUDE_PATHS "${line}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Also try cpp directly
|
||||
find_program(CPP_EXECUTABLE cpp)
|
||||
if(CPP_EXECUTABLE)
|
||||
execute_process(
|
||||
COMMAND ${CPP_EXECUTABLE} -x c++ -v
|
||||
OUTPUT_VARIABLE CPP_OUTPUT
|
||||
ERROR_VARIABLE CPP_ERROR
|
||||
INPUT_FILE /dev/null
|
||||
RESULT_VARIABLE CPP_RESULT
|
||||
)
|
||||
|
||||
string(REGEX MATCHALL "/[^\n]*include[^\n]*" INCLUDE_DIRS "${CPP_ERROR}")
|
||||
foreach(dir ${INCLUDE_DIRS})
|
||||
string(STRIP "${dir}" dir)
|
||||
if(EXISTS "${dir}" AND IS_DIRECTORY "${dir}")
|
||||
list(APPEND DISCOVERED_INCLUDE_PATHS "${dir}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Method 3: Get GCC-specific paths
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=include
|
||||
OUTPUT_VARIABLE GCC_INCLUDE_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
if(EXISTS "${GCC_INCLUDE_DIR}")
|
||||
list(APPEND DISCOVERED_INCLUDE_PATHS "${GCC_INCLUDE_DIR}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -print-search-dirs
|
||||
OUTPUT_VARIABLE GCC_SEARCH_DIRS
|
||||
ERROR_QUIET
|
||||
)
|
||||
if(GCC_SEARCH_DIRS)
|
||||
string(REGEX MATCH "install: ([^\n]*)" INSTALL_LINE "${GCC_SEARCH_DIRS}")
|
||||
if(CMAKE_MATCH_1)
|
||||
string(STRIP "${CMAKE_MATCH_1}" INSTALL_DIR)
|
||||
if(EXISTS "${INSTALL_DIR}/include")
|
||||
list(APPEND DISCOVERED_INCLUDE_PATHS "${INSTALL_DIR}/include")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Method 4: Get target-specific paths
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -dumpmachine
|
||||
OUTPUT_VARIABLE GCC_TARGET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
|
||||
OUTPUT_VARIABLE GCC_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
if(GCC_TARGET AND GCC_VERSION)
|
||||
# Extract major version
|
||||
string(REGEX MATCH "^([0-9]+)" GCC_MAJOR "${GCC_VERSION}")
|
||||
|
||||
# Check common GCC installation paths
|
||||
foreach(base_path "/usr/lib/gcc" "/usr/lib64/gcc" "/usr/local/lib/gcc")
|
||||
foreach(version ${GCC_VERSION} ${GCC_MAJOR})
|
||||
foreach(subdir "include" "include-fixed")
|
||||
set(test_path "${base_path}/${GCC_TARGET}/${version}/${subdir}")
|
||||
if(EXISTS "${test_path}")
|
||||
list(APPEND DISCOVERED_INCLUDE_PATHS "${test_path}")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Method 5: Common system paths
|
||||
set(COMMON_INCLUDE_PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/usr/include/linux
|
||||
/usr/include/x86_64-linux-gnu
|
||||
/usr/include/i386-linux-gnu
|
||||
/usr/include/aarch64-linux-gnu
|
||||
/opt/local/include
|
||||
/opt/include
|
||||
)
|
||||
|
||||
foreach(path ${COMMON_INCLUDE_PATHS})
|
||||
if(EXISTS "${path}")
|
||||
list(APPEND DISCOVERED_INCLUDE_PATHS "${path}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Add C++ standard library paths
|
||||
foreach(version RANGE 5 15)
|
||||
set(cpp_paths
|
||||
"/usr/include/c++/${version}"
|
||||
"/usr/include/c++/${version}/x86_64-linux-gnu"
|
||||
"/usr/include/c++/${version}/x86_64-redhat-linux"
|
||||
"/usr/include/c++/${version}/aarch64-linux-gnu"
|
||||
"/usr/include/c++/${version}/backward"
|
||||
)
|
||||
foreach(path ${cpp_paths})
|
||||
if(EXISTS "${path}")
|
||||
list(APPEND DISCOVERED_INCLUDE_PATHS "${path}")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# Method 6: Try to compile a test file and extract includes
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/test_includes.cpp" "
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
int main() { return 0; }
|
||||
")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -H -E "${CMAKE_BINARY_DIR}/test_includes.cpp"
|
||||
OUTPUT_VARIABLE HEADER_OUTPUT
|
||||
ERROR_VARIABLE HEADER_ERROR
|
||||
RESULT_VARIABLE HEADER_RESULT
|
||||
)
|
||||
|
||||
# Parse the -H output to find include directories
|
||||
string(REGEX MATCHALL "\\. /[^\n]*\\.h" HEADER_LINES "${HEADER_ERROR}")
|
||||
foreach(line ${HEADER_LINES})
|
||||
string(REGEX REPLACE "^\\. " "" header_file "${line}")
|
||||
get_filename_component(header_dir "${header_file}" DIRECTORY)
|
||||
if(EXISTS "${header_dir}")
|
||||
list(APPEND DISCOVERED_INCLUDE_PATHS "${header_dir}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Method 7: Check if clang is available and get its paths
|
||||
find_program(CLANG_CXX clang++)
|
||||
if(CLANG_CXX)
|
||||
execute_process(
|
||||
COMMAND ${CLANG_CXX} -print-resource-dir
|
||||
OUTPUT_VARIABLE CLANG_RESOURCE_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
if(EXISTS "${CLANG_RESOURCE_DIR}/include")
|
||||
list(APPEND DISCOVERED_INCLUDE_PATHS "${CLANG_RESOURCE_DIR}/include")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Remove duplicates
|
||||
list(REMOVE_DUPLICATES DISCOVERED_INCLUDE_PATHS)
|
||||
|
||||
# Validate that we found critical headers
|
||||
set(CRITICAL_HEADERS limits.h stdio.h stdlib.h stddef.h stdint.h)
|
||||
set(MISSING_HEADERS "")
|
||||
|
||||
foreach(header ${CRITICAL_HEADERS})
|
||||
set(HEADER_FOUND FALSE)
|
||||
foreach(dir ${DISCOVERED_INCLUDE_PATHS})
|
||||
if(EXISTS "${dir}/${header}")
|
||||
set(HEADER_FOUND TRUE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT HEADER_FOUND)
|
||||
list(APPEND MISSING_HEADERS ${header})
|
||||
message(WARNING "Critical header ${header} not found in discovered paths")
|
||||
|
||||
# Try to find it
|
||||
execute_process(
|
||||
COMMAND find /usr -name ${header} -type f -print -quit
|
||||
OUTPUT_VARIABLE FOUND_HEADER
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
TIMEOUT 5
|
||||
)
|
||||
if(FOUND_HEADER)
|
||||
get_filename_component(FOUND_DIR "${FOUND_HEADER}" DIRECTORY)
|
||||
message(STATUS " Found ${header} in ${FOUND_DIR}")
|
||||
list(APPEND DISCOVERED_INCLUDE_PATHS "${FOUND_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Remove duplicates again after adding missing headers
|
||||
list(REMOVE_DUPLICATES DISCOVERED_INCLUDE_PATHS)
|
||||
|
||||
# Convert to -I flags
|
||||
set(SYSTEM_INCLUDE_FLAGS "")
|
||||
foreach(dir ${DISCOVERED_INCLUDE_PATHS})
|
||||
set(SYSTEM_INCLUDE_FLAGS "${SYSTEM_INCLUDE_FLAGS} -I${dir}")
|
||||
endforeach()
|
||||
|
||||
message(STATUS "Found ${CMAKE_WORDS_BIGENDIAN} system include directories")
|
||||
message(STATUS "System include flags: ${SYSTEM_INCLUDE_FLAGS}")
|
||||
|
||||
# Write the discovered paths to a file for debugging
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/discovered_includes.txt" "${SYSTEM_INCLUDE_FLAGS}")
|
||||
|
||||
# ============================================================================
|
||||
# GENERATE WRAPPER SCRIPT WITH DISCOVERED PATHS
|
||||
# ============================================================================
|
||||
|
||||
set(PPSTEP_WRAPPER "${CMAKE_BINARY_DIR}/ppstep-nd4j")
|
||||
|
||||
# Generate wrapper with the discovered paths baked in
|
||||
file(WRITE ${PPSTEP_WRAPPER}
|
||||
"#!/bin/bash
|
||||
# Auto-generated ppstep wrapper for libnd4j
|
||||
# Generated at CMake configure time with discovered include paths
|
||||
|
||||
PPSTEP_BIN=\"${PPSTEP_BUILD_DIR}/ppstep\"
|
||||
|
||||
if [ ! -f \"\$PPSTEP_BIN\" ]; then
|
||||
echo \"Error: ppstep not built yet. Run 'make ppstep_build' first\"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# System includes discovered at CMake configure time
|
||||
SYSTEM_INCLUDES=\"${SYSTEM_INCLUDE_FLAGS}\"
|
||||
|
||||
# Additional runtime discovery (fallback)
|
||||
if [ -z \"\$SYSTEM_INCLUDES\" ] || [ \"\$1\" = \"--rediscover\" ]; then
|
||||
echo \"Warning: No includes from CMake or rediscovery requested\" >&2
|
||||
|
||||
# Try runtime discovery
|
||||
RUNTIME_INCLUDES=\"\"
|
||||
|
||||
# Method 1: cpp -v
|
||||
if command -v cpp &> /dev/null; then
|
||||
while IFS= read -r dir; do
|
||||
[ -d \"\$dir\" ] && RUNTIME_INCLUDES=\"\$RUNTIME_INCLUDES -I\$dir\"
|
||||
done < <(cpp -x c++ -v < /dev/null 2>&1 | awk '
|
||||
/^#include <...> search starts here:/ { flag=1; next }
|
||||
/^End of search list./ { flag=0 }
|
||||
flag { gsub(/^[ \t]+/, \"\"); print }
|
||||
')
|
||||
fi
|
||||
|
||||
# Method 2: Direct paths
|
||||
for dir in /usr/include /usr/local/include /usr/include/linux; do
|
||||
[ -d \"\$dir\" ] && RUNTIME_INCLUDES=\"\$RUNTIME_INCLUDES -I\$dir\"
|
||||
done
|
||||
|
||||
SYSTEM_INCLUDES=\"\$RUNTIME_INCLUDES\"
|
||||
fi
|
||||
|
||||
# Include paths for libnd4j
|
||||
INCLUDES=\"-I${CMAKE_CURRENT_SOURCE_DIR}/include\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_BINARY_DIR}/include\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/array\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/blas\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/cnpy\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/exceptions\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/execution\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/flatbuffers\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/generated\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/graph\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/helpers\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/indexing\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/legacy\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/loops\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/math\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/memory\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/ops\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/system\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/types\"
|
||||
INCLUDES=\"\$INCLUDES -I${CMAKE_CURRENT_SOURCE_DIR}/include/performance\"
|
||||
|
||||
# Add OpenBLAS if available
|
||||
if [ -n \"${OPENBLAS_PATH}\" ] && [ -d \"${OPENBLAS_PATH}/include\" ]; then
|
||||
INCLUDES=\"\$INCLUDES -I${OPENBLAS_PATH}/include\"
|
||||
fi
|
||||
|
||||
# Basic defines
|
||||
DEFINES=\"-D__CPUBLAS__=1 -DSD_CPU=1\"
|
||||
DEFINES=\"\$DEFINES -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS\"
|
||||
DEFINES=\"\$DEFINES -D_GNU_SOURCE\"
|
||||
|
||||
# Handle special arguments
|
||||
case \"\$1\" in
|
||||
--debug|--show-includes)
|
||||
echo \"System includes:\"
|
||||
echo \$SYSTEM_INCLUDES | tr ' ' '\\n' | grep '^-I' | while read inc; do
|
||||
dir=\${inc#-I}
|
||||
echo \" \$inc\"
|
||||
for h in limits.h stdio.h stdlib.h stddef.h; do
|
||||
[ -f \"\$dir/\$h\" ] && echo \" ✓ has \$h\"
|
||||
done
|
||||
done
|
||||
echo \"\"
|
||||
echo \"Project includes:\"
|
||||
echo \$INCLUDES | tr ' ' '\\n' | grep '^-I'
|
||||
echo \"\"
|
||||
echo \"Defines:\"
|
||||
echo \$DEFINES | tr ' ' '\\n'
|
||||
exit 0
|
||||
;;
|
||||
--version)
|
||||
echo \"ppstep wrapper generated by CMake\"
|
||||
echo \"Binary: \$PPSTEP_BIN\"
|
||||
\$PPSTEP_BIN --version 2>/dev/null || echo \"ppstep version unknown\"
|
||||
exit 0
|
||||
;;
|
||||
-h|--help)
|
||||
echo \"Usage: \$0 [options] <source_file.cpp>\"
|
||||
echo \"Options:\"
|
||||
echo \" --debug, --show-includes Show include paths and exit\"
|
||||
echo \" --rediscover Force runtime include discovery\"
|
||||
echo \" --version Show version information\"
|
||||
echo \" -h, --help Show this help\"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# Remove special arguments if rediscovery was requested
|
||||
[ \"\$1\" = \"--rediscover\" ] && shift
|
||||
|
||||
# Run ppstep
|
||||
exec \"\$PPSTEP_BIN\" \$SYSTEM_INCLUDES \$INCLUDES \$DEFINES \"\$@\"
|
||||
")
|
||||
|
||||
# Make wrapper executable
|
||||
file(CHMOD ${PPSTEP_WRAPPER}
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
|
||||
GROUP_READ GROUP_EXECUTE
|
||||
WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
# Also generate a CMake include file with the discovered paths
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/ppstep_includes.cmake"
|
||||
"# Auto-generated by Ppstep.cmake
|
||||
# System include directories discovered during configuration
|
||||
|
||||
set(PPSTEP_SYSTEM_INCLUDE_DIRS
|
||||
")
|
||||
foreach(dir ${DISCOVERED_INCLUDE_PATHS})
|
||||
file(APPEND "${CMAKE_BINARY_DIR}/ppstep_includes.cmake" " \"${dir}\"\n")
|
||||
endforeach()
|
||||
file(APPEND "${CMAKE_BINARY_DIR}/ppstep_includes.cmake" ")\n")
|
||||
|
||||
# Add custom target
|
||||
add_custom_target(ppstep ALL
|
||||
DEPENDS ppstep_build
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "✅ ppstep built successfully"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo " Executable: ${PPSTEP_BUILD_DIR}/ppstep"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo " Wrapper: ${PPSTEP_WRAPPER}"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo " Include paths: ${CMAKE_BINARY_DIR}/discovered_includes.txt"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo ""
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Usage:"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo " ${PPSTEP_WRAPPER} [source_file.cpp]"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo " ${PPSTEP_WRAPPER} --debug # Show include paths"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo ""
|
||||
COMMENT "ppstep preprocessor tool ready"
|
||||
)
|
||||
|
||||
# Custom target to regenerate wrapper if needed
|
||||
add_custom_target(ppstep-regenerate
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Regenerating ppstep wrapper..."
|
||||
COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR}
|
||||
COMMENT "Regenerating ppstep wrapper with updated paths"
|
||||
)
|
||||
|
||||
message(STATUS "✅ ppstep target configured")
|
||||
message(STATUS "Exiting after ppstep setup - run 'make' to build ppstep")
|
||||
|
||||
# CRITICAL: EARLY EXIT - Don't process the rest of CMakeLists.txt
|
||||
return()
|
||||
endif()
|
||||
@@ -0,0 +1,87 @@
|
||||
################################################################################
|
||||
# Colored Status Printing and Utility Functions
|
||||
# Common utility functions for enhanced CMake output and debugging
|
||||
################################################################################
|
||||
|
||||
# Enhanced colored status printing function
|
||||
function(print_status_colored type message)
|
||||
if(type STREQUAL "ERROR")
|
||||
message(FATAL_ERROR "❌ ${message}")
|
||||
elseif(type STREQUAL "WARNING")
|
||||
message(WARNING "⚠️ ${message}")
|
||||
elseif(type STREQUAL "SUCCESS")
|
||||
message(STATUS "✅ ${message}")
|
||||
elseif(type STREQUAL "INFO")
|
||||
message(STATUS "ℹ️ ${message}")
|
||||
elseif(type STREQUAL "DEBUG")
|
||||
message(STATUS "🔍 ${message}")
|
||||
elseif(type STREQUAL "NOTICE")
|
||||
message(NOTICE "📢 ${message}")
|
||||
else()
|
||||
message(STATUS "${message}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Print all CMake variables for debugging
|
||||
macro(print_all_variables)
|
||||
message(STATUS "print_all_variables------------------------------------------{")
|
||||
get_cmake_property(_variableNames VARIABLES)
|
||||
foreach(_variableName ${_variableNames})
|
||||
message(STATUS "${_variableName}=${${_variableName}}")
|
||||
endforeach()
|
||||
message(STATUS "print_all_variables------------------------------------------}")
|
||||
endmacro()
|
||||
|
||||
# Function to verify template processing worked
|
||||
function(verify_template_processing GENERATED_FILE)
|
||||
if(EXISTS "${GENERATED_FILE}")
|
||||
file(READ "${GENERATED_FILE}" FILE_CONTENT)
|
||||
|
||||
# Check for unprocessed #cmakedefine
|
||||
if(FILE_CONTENT MATCHES "#cmakedefine[ \t]+[A-Za-z_]+")
|
||||
message(FATAL_ERROR "❌ Template processing FAILED: ${GENERATED_FILE} contains unprocessed #cmakedefine directives")
|
||||
endif()
|
||||
|
||||
# Check for unprocessed @VAR@
|
||||
if(FILE_CONTENT MATCHES "@[A-Za-z_]+@")
|
||||
message(FATAL_ERROR "❌ Template processing FAILED: ${GENERATED_FILE} contains unprocessed @VAR@ tokens")
|
||||
endif()
|
||||
|
||||
message(STATUS "✅ Template processing verified: ${GENERATED_FILE}")
|
||||
return()
|
||||
else()
|
||||
message(FATAL_ERROR "❌ Generated file does not exist: ${GENERATED_FILE}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to safely remove files if they match exclusion criteria
|
||||
function(removeFileIfExcluded)
|
||||
cmake_parse_arguments(
|
||||
PARSED_ARGS
|
||||
""
|
||||
"FILE_ITEM"
|
||||
"LIST_ITEM"
|
||||
${ARGN}
|
||||
)
|
||||
file(READ ${PARSED_ARGS_FILE_ITEM} FILE_CONTENTS)
|
||||
string(FIND "${FILE_CONTENTS}" "NOT_EXCLUDED" NOT_EXCLUDED_IDX)
|
||||
|
||||
if(${NOT_EXCLUDED_IDX} GREATER_EQUAL 0)
|
||||
set(local_list ${${PARSED_ARGS_LIST_ITEM}})
|
||||
set(file_removed FALSE)
|
||||
|
||||
foreach(OP ${SD_OPS_LIST})
|
||||
string(FIND "${FILE_CONTENTS}" "NOT_EXCLUDED(OP_${OP})" NOT_EXCLUDED_OP_IDX)
|
||||
|
||||
if(${NOT_EXCLUDED_OP_IDX} LESS 0)
|
||||
list(REMOVE_ITEM local_list "${PARSED_ARGS_FILE_ITEM}")
|
||||
set(file_removed TRUE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(file_removed)
|
||||
set(${PARSED_ARGS_LIST_ITEM} ${local_list} PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -0,0 +1,207 @@
|
||||
# cmake/ProcessInstantiationBatch.cmake
|
||||
# Worker script for processing a batch of source files in parallel
|
||||
# This script is executed as a separate CMake process for each batch
|
||||
|
||||
# Get batch ID from command line
|
||||
if(NOT DEFINED BATCH_ID)
|
||||
message(FATAL_ERROR "BATCH_ID not defined")
|
||||
endif()
|
||||
|
||||
message("[Batch ${BATCH_ID}] Starting batch processor")
|
||||
|
||||
# Determine paths
|
||||
get_filename_component(CMAKE_SCRIPT_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
|
||||
set(CMAKE_SOURCE_DIR "${CMAKE_SCRIPT_DIR}/..")
|
||||
set(INST_DIR "${CMAKE_SOURCE_DIR}/instantiation_analysis")
|
||||
set(INST_BATCH_DIR "${INST_DIR}/batches")
|
||||
|
||||
# Load configuration
|
||||
set(BATCH_CONFIG_FILE "${INST_BATCH_DIR}/config.cmake")
|
||||
if(NOT EXISTS ${BATCH_CONFIG_FILE})
|
||||
message(FATAL_ERROR "[Batch ${BATCH_ID}] Configuration file not found: ${BATCH_CONFIG_FILE}")
|
||||
endif()
|
||||
|
||||
include(${BATCH_CONFIG_FILE})
|
||||
|
||||
# Include helper functions
|
||||
include(${CMAKE_SCRIPT_DIR}/InstantiationHelpers.cmake)
|
||||
|
||||
# Read list of files to process
|
||||
set(BATCH_FILE "${INST_BATCH_DIR}/batch_${BATCH_ID}.txt")
|
||||
if(NOT EXISTS ${BATCH_FILE})
|
||||
message(WARNING "[Batch ${BATCH_ID}] Batch file not found: ${BATCH_FILE}")
|
||||
file(WRITE "${INST_BATCH_DIR}/batch_${BATCH_ID}.done" "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
file(STRINGS ${BATCH_FILE} FILES_TO_PROCESS)
|
||||
list(LENGTH FILES_TO_PROCESS batch_size)
|
||||
message("[Batch ${BATCH_ID}] Processing ${batch_size} files")
|
||||
|
||||
# Process each file in the batch
|
||||
set(batch_results "")
|
||||
set(processed_count 0)
|
||||
set(failed_count 0)
|
||||
|
||||
foreach(src IN LISTS FILES_TO_PROCESS)
|
||||
if(NOT EXISTS ${src})
|
||||
message("[Batch ${BATCH_ID}] Warning: File not found: ${src}")
|
||||
math(EXPR failed_count "${failed_count} + 1")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Extract file information
|
||||
get_filename_component(src_name ${src} NAME_WE)
|
||||
get_filename_component(src_path ${src} PATH)
|
||||
get_filename_component(src_full_name ${src} NAME)
|
||||
file(RELATIVE_PATH rel_path ${CMAKE_SOURCE_DIR} ${src_path})
|
||||
string(REPLACE "/" "_" safe_name "${rel_path}_${src_name}")
|
||||
|
||||
# Determine if this is a generated file
|
||||
set(IS_GENERATED FALSE)
|
||||
if(src MATCHES "${CMAKE_BINARY_DIR}")
|
||||
set(IS_GENERATED TRUE)
|
||||
endif()
|
||||
|
||||
message("[Batch ${BATCH_ID}] [${processed_count}/${batch_size}] Analyzing: ${src_full_name}")
|
||||
|
||||
# Create a sub-temp directory for this batch
|
||||
set(BATCH_TEMP_DIR "${INST_TEMP_DIR}/batch_${BATCH_ID}")
|
||||
if(NOT EXISTS ${BATCH_TEMP_DIR})
|
||||
file(MAKE_DIRECTORY ${BATCH_TEMP_DIR})
|
||||
endif()
|
||||
set(INST_TEMP_DIR ${BATCH_TEMP_DIR})
|
||||
|
||||
# Extract used templates
|
||||
set(used_file "${INST_USED_DIR}/${safe_name}.used")
|
||||
extract_used_templates("${src}" "${used_file}" "${safe_name}")
|
||||
|
||||
# Extract provided templates
|
||||
set(provided_file "${INST_PROVIDED_DIR}/${safe_name}.provided")
|
||||
extract_provided_templates("${src}" "${provided_file}" "${safe_name}")
|
||||
|
||||
# Calculate missing templates
|
||||
set(missing_templates "")
|
||||
set(missing_count 0)
|
||||
|
||||
# Read used templates
|
||||
if(EXISTS ${used_file})
|
||||
file(STRINGS ${used_file} used_list)
|
||||
else()
|
||||
set(used_list "")
|
||||
endif()
|
||||
|
||||
# Read provided templates
|
||||
if(EXISTS ${provided_file})
|
||||
file(STRINGS ${provided_file} provided_list)
|
||||
else()
|
||||
set(provided_list "")
|
||||
endif()
|
||||
|
||||
# Simple missing calculation (can be enhanced with normalization)
|
||||
foreach(used_tmpl ${used_list})
|
||||
set(found FALSE)
|
||||
foreach(provided_tmpl ${provided_list})
|
||||
if(used_tmpl STREQUAL provided_tmpl)
|
||||
set(found TRUE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT found)
|
||||
list(APPEND missing_templates "${used_tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Write missing templates
|
||||
set(missing_file "${INST_MISSING_DIR}/${safe_name}.missing")
|
||||
if(missing_templates)
|
||||
list(REMOVE_DUPLICATES missing_templates)
|
||||
string(REPLACE ";" "\n" missing_content "${missing_templates}")
|
||||
file(WRITE ${missing_file} "${missing_content}")
|
||||
list(LENGTH missing_templates missing_count)
|
||||
else()
|
||||
file(WRITE ${missing_file} "")
|
||||
set(missing_count 0)
|
||||
endif()
|
||||
|
||||
# Count templates
|
||||
list(LENGTH used_list used_count)
|
||||
list(LENGTH provided_list provided_count)
|
||||
|
||||
# Create per-file summary
|
||||
file(WRITE ${INST_BY_FILE_DIR}/${safe_name}.summary "File: ${src_full_name}\n")
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary "Path: ${rel_path}\n")
|
||||
if(IS_GENERATED)
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary "Type: generated\n")
|
||||
else()
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary "Type: original\n")
|
||||
endif()
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary "Used: ${used_count}\n")
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary "Provided: ${provided_count}\n")
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary "Missing: ${missing_count}\n")
|
||||
|
||||
# Add details if there are templates
|
||||
if(used_count GREATER 0)
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary "\nUsed Templates (first 10):\n")
|
||||
set(shown 0)
|
||||
foreach(tmpl ${used_list})
|
||||
if(shown LESS 10)
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary " - ${tmpl}\n")
|
||||
math(EXPR shown "${shown} + 1")
|
||||
else()
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(provided_count GREATER 0)
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary "\nProvided Templates (first 10):\n")
|
||||
set(shown 0)
|
||||
foreach(tmpl ${provided_list})
|
||||
if(shown LESS 10)
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary " - ${tmpl}\n")
|
||||
math(EXPR shown "${shown} + 1")
|
||||
else()
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(missing_count GREATER 0)
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary "\nMissing Templates:\n")
|
||||
foreach(tmpl ${missing_templates})
|
||||
file(APPEND ${INST_BY_FILE_DIR}/${safe_name}.summary " - ${tmpl}\n")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Append to batch results
|
||||
string(APPEND batch_results "${src}|${safe_name}|${used_count}|${provided_count}|${missing_count}|${IS_GENERATED}\n")
|
||||
|
||||
math(EXPR processed_count "${processed_count} + 1")
|
||||
|
||||
# Progress reporting
|
||||
math(EXPR progress_pct "(${processed_count} * 100) / ${batch_size}")
|
||||
if(progress_pct GREATER 0 AND NOT progress_pct EQUAL last_progress)
|
||||
message("[Batch ${BATCH_ID}] Progress: ${progress_pct}% (${processed_count}/${batch_size})")
|
||||
set(last_progress ${progress_pct})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Clean up batch temp directory
|
||||
if(EXISTS ${BATCH_TEMP_DIR})
|
||||
file(REMOVE_RECURSE ${BATCH_TEMP_DIR})
|
||||
endif()
|
||||
|
||||
# Write batch completion marker with results
|
||||
file(WRITE "${INST_BATCH_DIR}/batch_${BATCH_ID}.done" "${batch_results}")
|
||||
|
||||
message("[Batch ${BATCH_ID}] Completed: ${processed_count} processed, ${failed_count} failed")
|
||||
|
||||
# Write batch summary
|
||||
set(BATCH_SUMMARY_FILE "${INST_BATCH_DIR}/batch_${BATCH_ID}.summary")
|
||||
file(WRITE ${BATCH_SUMMARY_FILE} "Batch ${BATCH_ID} Summary\n")
|
||||
file(APPEND ${BATCH_SUMMARY_FILE} "====================\n")
|
||||
file(APPEND ${BATCH_SUMMARY_FILE} "Files processed: ${processed_count}\n")
|
||||
file(APPEND ${BATCH_SUMMARY_FILE} "Files failed: ${failed_count}\n")
|
||||
file(APPEND ${BATCH_SUMMARY_FILE} "Total in batch: ${batch_size}\n")
|
||||
@@ -0,0 +1,38 @@
|
||||
include(SelectiveRenderingCore)
|
||||
|
||||
# Wrapper for the original setup_selective_rendering function
|
||||
function(setup_selective_rendering)
|
||||
message(STATUS "🔄 SelectiveRendering.cmake: Calling unified core system")
|
||||
|
||||
# Call the unified system
|
||||
setup_selective_rendering_unified_safe()
|
||||
|
||||
# Map results to legacy variables that existing code expects
|
||||
if(DEFINED UNIFIED_COMBINATIONS_2)
|
||||
set(COMBINATIONS_2 "${UNIFIED_COMBINATIONS_2}" PARENT_SCOPE)
|
||||
endif()
|
||||
if(DEFINED UNIFIED_COMBINATIONS_3)
|
||||
set(COMBINATIONS_3 "${UNIFIED_COMBINATIONS_3}" PARENT_SCOPE)
|
||||
endif()
|
||||
if(DEFINED UNIFIED_ACTIVE_TYPES)
|
||||
set(ACTIVE_TYPES "${UNIFIED_ACTIVE_TYPES}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
message(STATUS "✅ SelectiveRendering.cmake: Setup complete via unified core")
|
||||
endfunction()
|
||||
|
||||
# Legacy wrapper functions for other entry points
|
||||
function(track_combination_states active_types combinations_3)
|
||||
# This function is now handled internally by the core system
|
||||
message(STATUS "🔄 track_combination_states: Handled by unified core")
|
||||
endfunction()
|
||||
|
||||
function(generate_selective_rendering_header)
|
||||
# This function is now handled internally by the core system
|
||||
message(STATUS "🔄 generate_selective_rendering_header: Handled by unified core")
|
||||
endfunction()
|
||||
|
||||
function(generate_selective_wrapper_header)
|
||||
# This function is now handled internally by the core system
|
||||
message(STATUS "🔄 generate_selective_wrapper_header: Handled by unified core")
|
||||
endfunction()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
function(setup_definitive_semantic_filtering_with_selective_rendering)
|
||||
message(STATUS "🔄 SelectiveRenderingIntegration.cmake: Calling unified core system")
|
||||
|
||||
# Enable both semantic filtering and selective rendering
|
||||
set(SD_ENABLE_SEMANTIC_FILTERING TRUE PARENT_SCOPE)
|
||||
set(SD_ENABLE_SELECTIVE_RENDERING TRUE PARENT_SCOPE)
|
||||
|
||||
# Call unified system
|
||||
setup_selective_rendering_unified_safe()
|
||||
|
||||
# Legacy variable mapping
|
||||
if(DEFINED UNIFIED_COMBINATIONS_2)
|
||||
set(COMBINATIONS_2 "${UNIFIED_COMBINATIONS_2}" PARENT_SCOPE)
|
||||
endif()
|
||||
if(DEFINED UNIFIED_COMBINATIONS_3)
|
||||
set(COMBINATIONS_3 "${UNIFIED_COMBINATIONS_3}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
message(STATUS "✅ SelectiveRenderingIntegration.cmake: Setup complete via unified core")
|
||||
endfunction()
|
||||
|
||||
function(enhanced_semantic_filtering_setup)
|
||||
setup_definitive_semantic_filtering_with_selective_rendering()
|
||||
endfunction()
|
||||
|
||||
# Override the main setup function
|
||||
macro(setup_definitive_semantic_filtering)
|
||||
enhanced_semantic_filtering_setup()
|
||||
endmacro()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,107 @@
|
||||
# cmake/SemanticEngine.cmake
|
||||
# Implements the ML-aware semantic type filtering system.
|
||||
|
||||
option(SD_ENABLE_SEMANTIC_FILTERING "Enable ML-aware semantic type filtering" ON)
|
||||
option(SD_SHOW_COMBINATION_ANALYSIS "Show type combination analysis" ON)
|
||||
set(SD_TYPE_PROFILE "" CACHE STRING "ML workload profile (quantization/training/inference/nlp/cv)")
|
||||
|
||||
if(NOT SD_ENABLE_SEMANTIC_FILTERING)
|
||||
message(STATUS "Semantic filtering disabled. Using traditional type combination.")
|
||||
set(USE_SEMANTIC_PAIRWISE_GENERATION FALSE CACHE BOOL "Use semantic generation for pairwise templates")
|
||||
return()
|
||||
endif()
|
||||
|
||||
print_status_colored("INFO" "=== SEMANTIC TYPE COMBINATION GENERATION ===")
|
||||
setup_enhanced_semantic_validation()
|
||||
|
||||
# Auto-detect profile from type selection if none specified
|
||||
if((NOT SD_TYPE_PROFILE OR SD_TYPE_PROFILE STREQUAL "") AND SD_TYPES_LIST_COUNT GREATER 0)
|
||||
set(detected_profile "")
|
||||
if("int8_t" IN_LIST SD_TYPES_LIST AND "uint8_t" IN_LIST SD_TYPES_LIST)
|
||||
set(detected_profile "quantization")
|
||||
elseif("float16" IN_LIST SD_TYPES_LIST OR "bfloat16" IN_LIST SD_TYPES_LIST)
|
||||
set(detected_profile "training")
|
||||
elseif(SD_TYPES_LIST MATCHES ".*string.*")
|
||||
set(detected_profile "nlp")
|
||||
endif()
|
||||
|
||||
if(NOT detected_profile STREQUAL "")
|
||||
print_status_colored("INFO" "Auto-detected ML workload profile: ${detected_profile}")
|
||||
set(SD_TYPE_PROFILE "${detected_profile}")
|
||||
else()
|
||||
print_status_colored("INFO" "No specific workload detected - using inference profile as default")
|
||||
set(SD_TYPE_PROFILE "inference")
|
||||
endif()
|
||||
elseif(NOT SD_TYPE_PROFILE OR SD_TYPE_PROFILE STREQUAL "")
|
||||
print_status_colored("INFO" "No workload profile specified - using inference as default")
|
||||
set(SD_TYPE_PROFILE "inference")
|
||||
endif()
|
||||
|
||||
# Apply type profile if specified
|
||||
if(SD_TYPE_PROFILE AND NOT SD_TYPE_PROFILE STREQUAL "")
|
||||
print_status_colored("INFO" "Applying ML workload profile: ${SD_TYPE_PROFILE}")
|
||||
if(COMMAND apply_type_profile)
|
||||
apply_type_profile(${SD_TYPE_PROFILE})
|
||||
else()
|
||||
message(STATUS "Type profiles not available - using default types")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Generate ML-aware type combinations
|
||||
message(STATUS "Generating ML-aware type combinations...")
|
||||
if(SD_TYPE_PROFILE AND NOT SD_TYPE_PROFILE STREQUAL "")
|
||||
if(COMMAND generate_workload_combinations)
|
||||
generate_workload_combinations("${SD_TYPE_PROFILE}" optimized_combinations)
|
||||
set(GENERATED_TYPE_COMBINATIONS "${optimized_combinations}")
|
||||
else()
|
||||
message(STATUS "generate_workload_combinations function not available - using traditional approach")
|
||||
if(COMMAND generate_type_combinations)
|
||||
generate_type_combinations()
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if(COMMAND generate_type_combinations)
|
||||
generate_type_combinations()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SD_SHOW_COMBINATION_ANALYSIS)
|
||||
if(SD_TYPES_LIST_COUNT GREATER 0)
|
||||
validate_ml_type_combinations("${SD_TYPES_LIST}")
|
||||
endif()
|
||||
if(DEFINED GENERATED_TYPE_COMBINATIONS)
|
||||
analyze_combination_patterns("${GENERATED_TYPE_COMBINATIONS}" "${SD_TYPE_PROFILE}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Process template files with semantic filtering
|
||||
message(STATUS "Processing template files with semantic filtering...")
|
||||
#process_template_files()
|
||||
|
||||
# Process pairwise templates with enhanced semantic filtering
|
||||
message(STATUS "Processing pairwise templates with enhanced semantic filtering...")
|
||||
if(COMMAND process_pairwise_templates_semantic)
|
||||
process_pairwise_templates_semantic()
|
||||
else()
|
||||
message(STATUS "process_pairwise_templates_semantic function not available - skipping")
|
||||
endif()
|
||||
|
||||
# --- PAIRWISE SEMANTIC TYPE PROCESSING ---
|
||||
print_status_colored("INFO" "=== PAIRWISE SEMANTIC TYPE PROCESSING ===")
|
||||
message(STATUS "Applying semantic type processing to pairwise instantiations...")
|
||||
if(SD_TYPE_PROFILE AND NOT SD_TYPE_PROFILE STREQUAL "")
|
||||
message(STATUS "Using workload profile '${SD_TYPE_PROFILE}' for pairwise semantic processing")
|
||||
if(COMMAND generate_pairwise_semantic_combinations)
|
||||
generate_pairwise_semantic_combinations("${SD_TYPE_PROFILE}" SEMANTIC_PAIRWISE_COMBINATIONS)
|
||||
list(LENGTH SEMANTIC_PAIRWISE_COMBINATIONS semantic_count)
|
||||
message(STATUS "Generated ${semantic_count} semantic pairwise combinations")
|
||||
set(PAIRWISE_SEMANTIC_COMBINATIONS "${SEMANTIC_PAIRWISE_COMBINATIONS}" CACHE INTERNAL "Semantic pairwise combinations")
|
||||
set(USE_SEMANTIC_PAIRWISE_GENERATION TRUE CACHE BOOL "Use semantic generation for pairwise templates")
|
||||
else()
|
||||
message(STATUS "generate_pairwise_semantic_combinations function not available.")
|
||||
set(USE_SEMANTIC_PAIRWISE_GENERATION FALSE CACHE BOOL "Use semantic generation for pairwise templates")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "No workload profile specified - using traditional pairwise processing")
|
||||
set(USE_SEMANTIC_PAIRWISE_GENERATION FALSE CACHE BOOL "Use semantic generation for pairwise templates")
|
||||
endif()
|
||||
@@ -0,0 +1,56 @@
|
||||
function(setup_definitive_semantic_filtering)
|
||||
message(STATUS "🔄 SemanticTypeFiltering.cmake: Calling unified core system")
|
||||
|
||||
# Call the unified system with semantic filtering enabled
|
||||
set(SD_ENABLE_SEMANTIC_FILTERING TRUE PARENT_SCOPE)
|
||||
setup_selective_rendering_unified_safe(TYPE_PROFILE "${SD_TYPE_PROFILE}")
|
||||
|
||||
# Map to expected variables
|
||||
if(DEFINED UNIFIED_COMBINATIONS_2)
|
||||
set(COMBINATIONS_2 "${UNIFIED_COMBINATIONS_2}" PARENT_SCOPE)
|
||||
set(COMBINATIONS_2 "${UNIFIED_COMBINATIONS_2}" CACHE INTERNAL "2-type combinations" FORCE)
|
||||
endif()
|
||||
if(DEFINED UNIFIED_COMBINATIONS_3)
|
||||
set(COMBINATIONS_3 "${UNIFIED_COMBINATIONS_3}" PARENT_SCOPE)
|
||||
set(COMBINATIONS_3 "${UNIFIED_COMBINATIONS_3}" CACHE INTERNAL "3-type combinations" FORCE)
|
||||
endif()
|
||||
if(DEFINED UNIFIED_ACTIVE_TYPES)
|
||||
set(ACTIVE_TYPES "${UNIFIED_ACTIVE_TYPES}" PARENT_SCOPE)
|
||||
set(ACTIVE_TYPES "${UNIFIED_ACTIVE_TYPES}" CACHE INTERNAL "Active type list" FORCE)
|
||||
endif()
|
||||
|
||||
message(STATUS "✅ SemanticTypeFiltering.cmake: Setup complete via unified core")
|
||||
endfunction()
|
||||
|
||||
# Wrapper for initialize_definitive_combinations
|
||||
function(initialize_definitive_combinations)
|
||||
message(STATUS "🔄 initialize_definitive_combinations: Calling unified core system")
|
||||
setup_definitive_semantic_filtering()
|
||||
endfunction()
|
||||
|
||||
# Legacy helper functions (now handled by core)
|
||||
function(extract_definitive_types result_var)
|
||||
if(DEFINED UNIFIED_ACTIVE_TYPES)
|
||||
set(${result_var} "${UNIFIED_ACTIVE_TYPES}" PARENT_SCOPE)
|
||||
else()
|
||||
srcore_auto_setup()
|
||||
set(${result_var} "${UNIFIED_ACTIVE_TYPES}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(generate_definitive_combinations active_types result_2_var result_3_var)
|
||||
message(STATUS "🔄 generate_definitive_combinations: Using cached unified core results")
|
||||
if(DEFINED UNIFIED_COMBINATIONS_2 AND DEFINED UNIFIED_COMBINATIONS_3)
|
||||
set(${result_2_var} "${UNIFIED_COMBINATIONS_2}" PARENT_SCOPE)
|
||||
set(${result_3_var} "${UNIFIED_COMBINATIONS_3}" PARENT_SCOPE)
|
||||
else()
|
||||
srcore_auto_setup()
|
||||
set(${result_2_var} "${UNIFIED_COMBINATIONS_2}" PARENT_SCOPE)
|
||||
set(${result_3_var} "${UNIFIED_COMBINATIONS_3}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(validate_critical_types_coverage active_types combinations_3)
|
||||
# This validation is now handled internally by the core system
|
||||
message(STATUS "🔄 validate_critical_types_coverage: Handled by unified core")
|
||||
endfunction()
|
||||
@@ -0,0 +1,37 @@
|
||||
# cmake/Setup.cmake
|
||||
# Handles initial project setup and global configurations.
|
||||
|
||||
# Basic CMake Configuration
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)
|
||||
set(CMAKE_VERBOSE_MAKEFILE OFF)
|
||||
|
||||
# Standard Settings
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CUDA_STANDARD 17)
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
# MSVC runtime lib can be either "MultiThreaded" or "MultiThreadedDLL", /MT and /MD respectively
|
||||
set(MSVC_RT_LIB "MultiThreadedDLL")
|
||||
|
||||
# Initialize job pools for parallel builds
|
||||
set_property(GLOBAL PROPERTY JOB_POOLS one_jobs=1 two_jobs=2)
|
||||
|
||||
# Set Windows specific flags
|
||||
if(WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSD_WINDOWS_BUILD=true")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSD_WINDOWS_BUILD=true")
|
||||
endif()
|
||||
|
||||
# NOTE: SD_CPU/SD_CUDA logic, SD_LIBRARY_NAME, and DEFAULT_ENGINE
|
||||
# are now handled in the main CMakeLists.txt before this file is included
|
||||
|
||||
# Set optimization level based on GCC_FUNCTRACE
|
||||
if(SD_GCC_FUNCTRACE)
|
||||
message("Set optimization for functrace ${SD_GCC_FUNCTRACE}")
|
||||
set(SD_OPTIMIZATION_LEVEL "0")
|
||||
else()
|
||||
message("Set optimization level for no functrace ${SD_GCC_FUNCTRACE}")
|
||||
set(SD_OPTIMIZATION_LEVEL "3")
|
||||
endif()
|
||||
message("Set default optimization level ${SD_OPTIMIZATION_LEVEL}")
|
||||
@@ -0,0 +1,413 @@
|
||||
# cmake/TemplateCorrelation.cmake
|
||||
# Template correlation analysis and reporting functions
|
||||
|
||||
# Initialize global correlation tracking variables
|
||||
function(initialize_correlation_tracking)
|
||||
set(GLOBAL_USED_TEMPLATES "" CACHE INTERNAL "")
|
||||
set(GLOBAL_PROVIDED_TEMPLATES "" CACHE INTERNAL "")
|
||||
set(GLOBAL_MISSING_TEMPLATES "" CACHE INTERNAL "")
|
||||
set(CORRELATION_DATA "" CACHE INTERNAL "")
|
||||
set(FILE_ANALYSIS_DATA "" CACHE INTERNAL "")
|
||||
endfunction()
|
||||
|
||||
include(InstantiationHelpers)
|
||||
# Process a single source file for template analysis
|
||||
function(process_source_file SOURCE_FILE SAFE_NAME)
|
||||
message(STATUS "Analyzing: ${SOURCE_FILE}")
|
||||
|
||||
# Extract used templates - FIX: Added SAFE_NAME as third parameter
|
||||
set(used_file "${INST_USED_DIR}/${SAFE_NAME}.used")
|
||||
extract_used_templates(${SOURCE_FILE} ${used_file} ${SAFE_NAME})
|
||||
set(used_templates ${EXTRACTED_USED_TEMPLATES})
|
||||
|
||||
# Extract provided templates
|
||||
set(provided_file "${INST_PROVIDED_DIR}/${SAFE_NAME}.provided")
|
||||
extract_provided_templates(${SOURCE_FILE} ${provided_file} ${SAFE_NAME})
|
||||
set(provided_templates ${EXTRACTED_PROVIDED_TEMPLATES})
|
||||
|
||||
# Find missing templates for this file
|
||||
set(missing_templates "")
|
||||
foreach(used_tmpl ${used_templates})
|
||||
normalize_template_name("${used_tmpl}" normalized_used)
|
||||
|
||||
set(found FALSE)
|
||||
foreach(provided_tmpl ${provided_templates})
|
||||
normalize_template_name("${provided_tmpl}" normalized_provided)
|
||||
if("${normalized_used}" STREQUAL "${normalized_provided}")
|
||||
set(found TRUE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT found)
|
||||
list(APPEND missing_templates "${used_tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Write missing templates file
|
||||
if(missing_templates)
|
||||
string(REPLACE ";" "\n" missing_content "${missing_templates}")
|
||||
file(WRITE "${INST_MISSING_DIR}/${SAFE_NAME}.missing" "${missing_content}")
|
||||
else()
|
||||
file(WRITE "${INST_MISSING_DIR}/${SAFE_NAME}.missing" "")
|
||||
endif()
|
||||
|
||||
# Update global lists
|
||||
set(current_global_used ${GLOBAL_USED_TEMPLATES})
|
||||
list(APPEND current_global_used ${used_templates})
|
||||
set(GLOBAL_USED_TEMPLATES ${current_global_used} CACHE INTERNAL "")
|
||||
|
||||
set(current_global_provided ${GLOBAL_PROVIDED_TEMPLATES})
|
||||
list(APPEND current_global_provided ${provided_templates})
|
||||
set(GLOBAL_PROVIDED_TEMPLATES ${current_global_provided} CACHE INTERNAL "")
|
||||
|
||||
set(current_global_missing ${GLOBAL_MISSING_TEMPLATES})
|
||||
list(APPEND current_global_missing ${missing_templates})
|
||||
set(GLOBAL_MISSING_TEMPLATES ${current_global_missing} CACHE INTERNAL "")
|
||||
|
||||
# Collect analysis data for reporting
|
||||
list(LENGTH used_templates used_count)
|
||||
list(LENGTH provided_templates provided_count)
|
||||
list(LENGTH missing_templates missing_count)
|
||||
|
||||
get_filename_component(src_name ${SOURCE_FILE} NAME)
|
||||
|
||||
set(current_data ${FILE_ANALYSIS_DATA})
|
||||
string(APPEND current_data " {\n")
|
||||
string(APPEND current_data " \"file\": \"${src_name}\",\n")
|
||||
string(APPEND current_data " \"safe_name\": \"${SAFE_NAME}\",\n")
|
||||
string(APPEND current_data " \"used_count\": ${used_count},\n")
|
||||
string(APPEND current_data " \"provided_count\": ${provided_count},\n")
|
||||
string(APPEND current_data " \"missing_count\": ${missing_count}\n")
|
||||
string(APPEND current_data " },\n")
|
||||
set(FILE_ANALYSIS_DATA ${current_data} CACHE INTERNAL "")
|
||||
endfunction()
|
||||
|
||||
# Perform correlation analysis on all collected data
|
||||
function(perform_correlation_analysis)
|
||||
message(STATUS "Performing correlation analysis...")
|
||||
|
||||
# Remove duplicates from global lists
|
||||
set(all_used ${GLOBAL_USED_TEMPLATES})
|
||||
set(all_provided ${GLOBAL_PROVIDED_TEMPLATES})
|
||||
set(all_missing ${GLOBAL_MISSING_TEMPLATES})
|
||||
|
||||
if(all_used)
|
||||
list(REMOVE_DUPLICATES all_used)
|
||||
endif()
|
||||
if(all_provided)
|
||||
list(REMOVE_DUPLICATES all_provided)
|
||||
endif()
|
||||
if(all_missing)
|
||||
list(REMOVE_DUPLICATES all_missing)
|
||||
endif()
|
||||
|
||||
# Find truly missing templates (used but not provided anywhere)
|
||||
set(truly_missing "")
|
||||
foreach(used_tmpl ${all_used})
|
||||
normalize_template_name("${used_tmpl}" normalized_used)
|
||||
|
||||
set(found FALSE)
|
||||
foreach(provided_tmpl ${all_provided})
|
||||
normalize_template_name("${provided_tmpl}" normalized_provided)
|
||||
if("${normalized_used}" STREQUAL "${normalized_provided}")
|
||||
set(found TRUE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT found)
|
||||
list(APPEND truly_missing "${used_tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Find unused templates (provided but never used)
|
||||
set(unused_templates "")
|
||||
foreach(provided_tmpl ${all_provided})
|
||||
normalize_template_name("${provided_tmpl}" normalized_provided)
|
||||
|
||||
set(found FALSE)
|
||||
foreach(used_tmpl ${all_used})
|
||||
normalize_template_name("${used_tmpl}" normalized_used)
|
||||
if("${normalized_provided}" STREQUAL "${normalized_used}")
|
||||
set(found TRUE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT found)
|
||||
list(APPEND unused_templates "${provided_tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Update global variables with final results
|
||||
set(GLOBAL_USED_TEMPLATES ${all_used} CACHE INTERNAL "")
|
||||
set(GLOBAL_PROVIDED_TEMPLATES ${all_provided} CACHE INTERNAL "")
|
||||
set(GLOBAL_MISSING_TEMPLATES ${truly_missing} CACHE INTERNAL "")
|
||||
set(GLOBAL_UNUSED_TEMPLATES ${unused_templates} CACHE INTERNAL "")
|
||||
|
||||
# Write consolidated files
|
||||
if(all_used)
|
||||
string(REPLACE ";" "\n" content "${all_used}")
|
||||
file(WRITE "${INST_DIR}/all_used.txt" "${content}")
|
||||
endif()
|
||||
|
||||
if(all_provided)
|
||||
string(REPLACE ";" "\n" content "${all_provided}")
|
||||
file(WRITE "${INST_DIR}/all_provided.txt" "${content}")
|
||||
endif()
|
||||
|
||||
if(truly_missing)
|
||||
string(REPLACE ";" "\n" content "${truly_missing}")
|
||||
file(WRITE "${INST_DIR}/all_missing.txt" "${content}")
|
||||
endif()
|
||||
|
||||
if(unused_templates)
|
||||
string(REPLACE ";" "\n" content "${unused_templates}")
|
||||
file(WRITE "${INST_DIR}/all_unused.txt" "${content}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Generate correlation reports
|
||||
function(generate_correlation_reports)
|
||||
message(STATUS "Generating correlation reports...")
|
||||
|
||||
set(all_used ${GLOBAL_USED_TEMPLATES})
|
||||
set(all_provided ${GLOBAL_PROVIDED_TEMPLATES})
|
||||
set(truly_missing ${GLOBAL_MISSING_TEMPLATES})
|
||||
set(unused ${GLOBAL_UNUSED_TEMPLATES})
|
||||
|
||||
list(LENGTH all_used total_used)
|
||||
list(LENGTH all_provided total_provided)
|
||||
list(LENGTH truly_missing total_missing)
|
||||
list(LENGTH unused total_unused)
|
||||
|
||||
# Generate text report
|
||||
set(report_file "${INST_REPORTS_DIR}/correlation_report.txt")
|
||||
file(WRITE ${report_file} "=== TEMPLATE INSTANTIATION CORRELATION REPORT ===\n")
|
||||
file(APPEND ${report_file} "Generated: ${CMAKE_HOST_SYSTEM_PROCESSOR} ${CMAKE_HOST_SYSTEM_NAME}\n")
|
||||
file(APPEND ${report_file} "Build Type: ${CMAKE_BUILD_TYPE}\n")
|
||||
file(APPEND ${report_file} "Datatypes: ${SD_TYPES_LIST}\n")
|
||||
file(APPEND ${report_file} "All Ops: ${SD_ALL_OPS}\n\n")
|
||||
|
||||
file(APPEND ${report_file} "SUMMARY:\n")
|
||||
file(APPEND ${report_file} " Total Templates Used: ${total_used}\n")
|
||||
file(APPEND ${report_file} " Total Templates Provided: ${total_provided}\n")
|
||||
file(APPEND ${report_file} " Total Templates Missing: ${total_missing}\n")
|
||||
file(APPEND ${report_file} " Total Templates Unused: ${total_unused}\n\n")
|
||||
|
||||
if(total_missing GREATER 0)
|
||||
file(APPEND ${report_file} "⚠️ MISSING TEMPLATES (WILL CAUSE LINK ERRORS):\n")
|
||||
foreach(tmpl ${truly_missing})
|
||||
file(APPEND ${report_file} " - ${tmpl}\n")
|
||||
endforeach()
|
||||
file(APPEND ${report_file} "\n")
|
||||
endif()
|
||||
|
||||
if(total_unused GREATER 20)
|
||||
file(APPEND ${report_file} "UNUSED TEMPLATES (showing first 20 of ${total_unused}):\n")
|
||||
set(count 0)
|
||||
foreach(tmpl ${unused})
|
||||
if(count LESS 20)
|
||||
file(APPEND ${report_file} " - ${tmpl}\n")
|
||||
math(EXPR count "${count} + 1")
|
||||
else()
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
file(APPEND ${report_file} " ... and ${total_unused} - 20 more\n\n")
|
||||
elseif(total_unused GREATER 0)
|
||||
file(APPEND ${report_file} "UNUSED TEMPLATES:\n")
|
||||
foreach(tmpl ${unused})
|
||||
file(APPEND ${report_file} " - ${tmpl}\n")
|
||||
endforeach()
|
||||
file(APPEND ${report_file} "\n")
|
||||
endif()
|
||||
|
||||
# Generate JSON report
|
||||
set(json_file "${INST_REPORTS_DIR}/correlation.json")
|
||||
file(WRITE ${json_file} "{\n")
|
||||
file(APPEND ${json_file} " \"metadata\": {\n")
|
||||
file(APPEND ${json_file} " \"build_type\": \"${CMAKE_BUILD_TYPE}\",\n")
|
||||
file(APPEND ${json_file} " \"datatypes\": \"${SD_TYPES_LIST}\",\n")
|
||||
file(APPEND ${json_file} " \"all_ops\": ${SD_ALL_OPS}\n")
|
||||
file(APPEND ${json_file} " },\n")
|
||||
file(APPEND ${json_file} " \"summary\": {\n")
|
||||
file(APPEND ${json_file} " \"total_used\": ${total_used},\n")
|
||||
file(APPEND ${json_file} " \"total_provided\": ${total_provided},\n")
|
||||
file(APPEND ${json_file} " \"total_missing\": ${total_missing},\n")
|
||||
file(APPEND ${json_file} " \"total_unused\": ${total_unused}\n")
|
||||
file(APPEND ${json_file} " },\n")
|
||||
file(APPEND ${json_file} " \"files\": [\n")
|
||||
file(APPEND ${json_file} "${FILE_ANALYSIS_DATA}")
|
||||
file(APPEND ${json_file} " {}\n")
|
||||
file(APPEND ${json_file} " ]\n")
|
||||
file(APPEND ${json_file} "}\n")
|
||||
|
||||
# Generate recommendations
|
||||
generate_recommendations(${total_missing} ${total_unused})
|
||||
endfunction()
|
||||
|
||||
# Generate actionable recommendations
|
||||
function(generate_recommendations MISSING_COUNT UNUSED_COUNT)
|
||||
set(recommend_file "${INST_REPORTS_DIR}/recommendations.txt")
|
||||
file(WRITE ${recommend_file} "=== ACTIONABLE RECOMMENDATIONS ===\n\n")
|
||||
|
||||
if(MISSING_COUNT GREATER 0)
|
||||
file(APPEND ${recommend_file} "⚠️ CRITICAL: ${MISSING_COUNT} missing template instantiations detected!\n")
|
||||
file(APPEND ${recommend_file} "These WILL cause link-time errors.\n\n")
|
||||
file(APPEND ${recommend_file} "SOLUTION:\n")
|
||||
file(APPEND ${recommend_file} "1. Add the file '${INST_DIR}/fixes/missing_instantiations.cpp' to your build\n")
|
||||
file(APPEND ${recommend_file} "2. Or add explicit instantiations to the relevant source files\n\n")
|
||||
|
||||
file(APPEND ${recommend_file} "The missing templates are listed in:\n")
|
||||
file(APPEND ${recommend_file} " ${INST_DIR}/all_missing.txt\n\n")
|
||||
else()
|
||||
file(APPEND ${recommend_file} "✅ No missing template instantiations detected.\n\n")
|
||||
endif()
|
||||
|
||||
if(UNUSED_COUNT GREATER 50)
|
||||
file(APPEND ${recommend_file} "💡 OPTIMIZATION OPPORTUNITY:\n")
|
||||
file(APPEND ${recommend_file} "${UNUSED_COUNT} unused template instantiations found.\n")
|
||||
file(APPEND ${recommend_file} "Removing these could significantly reduce binary size.\n\n")
|
||||
file(APPEND ${recommend_file} "Review the list in: ${INST_DIR}/all_unused.txt\n\n")
|
||||
endif()
|
||||
|
||||
# Add type-specific recommendations
|
||||
if(SD_TYPES_LIST)
|
||||
file(APPEND ${recommend_file} "TYPE CONFIGURATION:\n")
|
||||
file(APPEND ${recommend_file} "Current types: ${SD_TYPES_LIST}\n")
|
||||
|
||||
if(MISSING_COUNT GREATER 0)
|
||||
file(APPEND ${recommend_file} "Some missing instantiations may be due to type restrictions.\n")
|
||||
file(APPEND ${recommend_file} "Consider if all necessary types are included.\n")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Generate fix files for missing instantiations
|
||||
function(generate_instantiation_fixes)
|
||||
set(fixes_dir "${INST_DIR}/fixes")
|
||||
file(MAKE_DIRECTORY ${fixes_dir})
|
||||
|
||||
set(missing ${GLOBAL_MISSING_TEMPLATES})
|
||||
if(NOT missing)
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "Generating instantiation fix files...")
|
||||
|
||||
# Generate main fix file
|
||||
set(fix_file "${fixes_dir}/missing_instantiations.cpp")
|
||||
file(WRITE ${fix_file} "// Auto-generated template instantiation fixes\n")
|
||||
file(APPEND ${fix_file} "// Generated by cmake/ExtractInstantiations.cmake\n")
|
||||
file(APPEND ${fix_file} "// Add this file to your build to resolve missing instantiations\n\n")
|
||||
|
||||
# Add necessary includes (customize based on your project)
|
||||
file(APPEND ${fix_file} "#include <array/NDArray.h>\n")
|
||||
file(APPEND ${fix_file} "#include <array/DataBuffer.h>\n")
|
||||
file(APPEND ${fix_file} "#include <helpers/BroadcastHelper.h>\n")
|
||||
file(APPEND ${fix_file} "#include <helpers/LoopKind.h>\n")
|
||||
file(APPEND ${fix_file} "#include <execution/LaunchContext.h>\n\n")
|
||||
|
||||
# Group templates by base class
|
||||
set(ndarray_instantiations "")
|
||||
set(databuffer_instantiations "")
|
||||
set(broadcast_instantiations "")
|
||||
set(other_instantiations "")
|
||||
|
||||
foreach(tmpl ${missing})
|
||||
if(tmpl MATCHES "^NDArray<")
|
||||
list(APPEND ndarray_instantiations "${tmpl}")
|
||||
elseif(tmpl MATCHES "^DataBuffer<")
|
||||
list(APPEND databuffer_instantiations "${tmpl}")
|
||||
elseif(tmpl MATCHES "^BroadcastHelper<")
|
||||
list(APPEND broadcast_instantiations "${tmpl}")
|
||||
else()
|
||||
list(APPEND other_instantiations "${tmpl}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Write grouped instantiations
|
||||
if(ndarray_instantiations)
|
||||
file(APPEND ${fix_file} "// NDArray instantiations\n")
|
||||
file(APPEND ${fix_file} "namespace sd {\n")
|
||||
foreach(tmpl ${ndarray_instantiations})
|
||||
file(APPEND ${fix_file} "template class ${tmpl};\n")
|
||||
endforeach()
|
||||
file(APPEND ${fix_file} "}\n\n")
|
||||
endif()
|
||||
|
||||
if(databuffer_instantiations)
|
||||
file(APPEND ${fix_file} "// DataBuffer instantiations\n")
|
||||
file(APPEND ${fix_file} "namespace sd {\n")
|
||||
foreach(tmpl ${databuffer_instantiations})
|
||||
file(APPEND ${fix_file} "template class ${tmpl};\n")
|
||||
endforeach()
|
||||
file(APPEND ${fix_file} "}\n\n")
|
||||
endif()
|
||||
|
||||
if(broadcast_instantiations)
|
||||
file(APPEND ${fix_file} "// BroadcastHelper instantiations\n")
|
||||
file(APPEND ${fix_file} "namespace sd {\n")
|
||||
file(APPEND ${fix_file} "namespace helpers {\n")
|
||||
foreach(tmpl ${broadcast_instantiations})
|
||||
file(APPEND ${fix_file} "template class ${tmpl};\n")
|
||||
endforeach()
|
||||
file(APPEND ${fix_file} "}\n}\n\n")
|
||||
endif()
|
||||
|
||||
if(other_instantiations)
|
||||
file(APPEND ${fix_file} "// Other instantiations\n")
|
||||
foreach(tmpl ${other_instantiations})
|
||||
file(APPEND ${fix_file} "template class ${tmpl};\n")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
message(STATUS "Generated fix file: ${fix_file}")
|
||||
endfunction()
|
||||
|
||||
# Display final summary
|
||||
function(display_analysis_summary)
|
||||
set(all_used ${GLOBAL_USED_TEMPLATES})
|
||||
set(all_provided ${GLOBAL_PROVIDED_TEMPLATES})
|
||||
set(truly_missing ${GLOBAL_MISSING_TEMPLATES})
|
||||
set(unused ${GLOBAL_UNUSED_TEMPLATES})
|
||||
|
||||
list(LENGTH all_used total_used)
|
||||
list(LENGTH all_provided total_provided)
|
||||
list(LENGTH truly_missing total_missing)
|
||||
list(LENGTH unused total_unused)
|
||||
|
||||
message(STATUS "")
|
||||
message(STATUS "=== INSTANTIATION CORRELATION COMPLETE ===")
|
||||
message(STATUS "Templates Used: ${total_used}")
|
||||
message(STATUS "Templates Provided: ${total_provided}")
|
||||
|
||||
if(total_missing GREATER 0)
|
||||
message(WARNING "Templates Missing: ${total_missing} - WILL CAUSE LINK ERRORS!")
|
||||
message(STATUS " Fix file generated: ${INST_DIR}/fixes/missing_instantiations.cpp")
|
||||
else()
|
||||
message(STATUS "Templates Missing: 0 ✓")
|
||||
endif()
|
||||
|
||||
if(total_unused GREATER 50)
|
||||
message(STATUS "Templates Unused: ${total_unused} (optimization opportunity)")
|
||||
else()
|
||||
message(STATUS "Templates Unused: ${total_unused}")
|
||||
endif()
|
||||
|
||||
message(STATUS "")
|
||||
message(STATUS "Reports generated in: ${INST_REPORTS_DIR}/")
|
||||
message(STATUS " - correlation_report.txt (human readable)")
|
||||
message(STATUS " - correlation.json (machine readable)")
|
||||
message(STATUS " - recommendations.txt (actionable items)")
|
||||
|
||||
if(total_missing GREATER 0)
|
||||
message(STATUS "")
|
||||
message(STATUS "⚠️ ACTION REQUIRED: Add missing instantiations to fix link errors")
|
||||
message(STATUS " See: ${INST_DIR}/all_missing.txt")
|
||||
endif()
|
||||
|
||||
message(STATUS "==========================================")
|
||||
endfunction()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
# Wrapper for initialize_dynamic_combinations
|
||||
function(initialize_dynamic_combinations)
|
||||
message(STATUS "🔄 TypeCombinationEngine.cmake: Calling unified core system")
|
||||
|
||||
# Call the unified system
|
||||
srcore_auto_setup()
|
||||
|
||||
# Map results to the expected legacy variables
|
||||
if(DEFINED UNIFIED_COMBINATIONS_2)
|
||||
set(COMBINATIONS_2 "${UNIFIED_COMBINATIONS_2}" PARENT_SCOPE)
|
||||
set(COMBINATIONS_2 "${UNIFIED_COMBINATIONS_2}" CACHE INTERNAL "2-type combinations" FORCE)
|
||||
endif()
|
||||
if(DEFINED UNIFIED_COMBINATIONS_3)
|
||||
set(COMBINATIONS_3 "${UNIFIED_COMBINATIONS_3}" PARENT_SCOPE)
|
||||
set(COMBINATIONS_3 "${UNIFIED_COMBINATIONS_3}" CACHE INTERNAL "3-type combinations" FORCE)
|
||||
endif()
|
||||
|
||||
message(STATUS "✅ TypeCombinationEngine.cmake: Setup complete via unified core")
|
||||
endfunction()
|
||||
|
||||
# Legacy utility functions (now thin wrappers)
|
||||
function(normalize_type input_type output_var)
|
||||
srcore_normalize_type("${input_type}" result)
|
||||
set(${output_var} "${result}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(get_type_name_from_index index result_var)
|
||||
# Try the unified core first
|
||||
if(DEFINED SRCORE_TYPE_NAME_${index})
|
||||
set(${result_var} "${SRCORE_TYPE_NAME_${index}}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Fallback to legacy system
|
||||
if(DEFINED TYPE_NAME_${index})
|
||||
set(${result_var} "${TYPE_NAME_${index}}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Emergency setup if nothing is available
|
||||
srcore_auto_setup()
|
||||
if(DEFINED SRCORE_TYPE_NAME_${index})
|
||||
set(${result_var} "${SRCORE_TYPE_NAME_${index}}" PARENT_SCOPE)
|
||||
else()
|
||||
set(${result_var} "unknown_type_${index}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -0,0 +1,37 @@
|
||||
# TypeMST.cmake - Zero-indexed type combinations
|
||||
|
||||
# Option to enable MST-based type selection
|
||||
option(SD_USE_MST_TYPES "Use optimized type combinations" ON)
|
||||
|
||||
# Function to generate a set of type combinations with 0-based indexing
|
||||
function(generate_mst_combinations)
|
||||
message(STATUS "TypeMST: Generating zero-indexed type combinations")
|
||||
|
||||
# Using 0-based indices that match the macros
|
||||
set(_COMBINATIONS)
|
||||
|
||||
# Add homogeneous combinations
|
||||
list(APPEND _COMBINATIONS "0,0,0") # BFLOAT16
|
||||
list(APPEND _COMBINATIONS "1,1,1") # FLOAT32
|
||||
list(APPEND _COMBINATIONS "2,2,2") # DOUBLE
|
||||
list(APPEND _COMBINATIONS "3,3,3") # FLOAT16
|
||||
list(APPEND _COMBINATIONS "4,4,4") # INT32
|
||||
list(APPEND _COMBINATIONS "5,5,5") # INT64
|
||||
list(APPEND _COMBINATIONS "6,6,6") # INT8
|
||||
list(APPEND _COMBINATIONS "7,7,7") # INT16
|
||||
list(APPEND _COMBINATIONS "8,8,8") # UINT8
|
||||
list(APPEND _COMBINATIONS "9,9,9") # UINT16
|
||||
|
||||
# Add critical mixed-type combinations
|
||||
list(APPEND _COMBINATIONS "1,4,1") # float32, int32, float32
|
||||
list(APPEND _COMBINATIONS "4,1,1") # int32, float32, float32
|
||||
list(APPEND _COMBINATIONS "2,4,2") # double, int32, double
|
||||
list(APPEND _COMBINATIONS "4,2,2") # int32, double, double
|
||||
|
||||
# Set result
|
||||
set(COMBINATIONS_3 ${_COMBINATIONS} PARENT_SCOPE)
|
||||
|
||||
# Report
|
||||
list(LENGTH _COMBINATIONS COMBO_COUNT)
|
||||
message(STATUS "TypeMST: Generated ${COMBO_COUNT} zero-indexed type combinations")
|
||||
endfunction()
|
||||
@@ -0,0 +1,425 @@
|
||||
# TypeProfiles.cmake - OPTIMIZED VERSION
|
||||
# Reduces compilation times by using focused type sets
|
||||
|
||||
# ============================================================================
|
||||
# OPTIMIZED DEFAULT TYPES (10 types instead of 16+)
|
||||
# ============================================================================
|
||||
|
||||
# Type profiles for different ML workloads
|
||||
set(QUANTIZATION_TYPES "int8_t;uint8_t;float;int32_t" CACHE INTERNAL "Types for quantization workloads")
|
||||
set(TRAINING_TYPES "float16;bfloat16;float;double;int32_t;int64_t" CACHE INTERNAL "Types for training workloads")
|
||||
set(INFERENCE_TYPES "int8_t;uint8_t;float16;float;int32_t" CACHE INTERNAL "Types for inference workloads")
|
||||
set(NLP_TYPES "std::string;float;int32_t;int64_t" CACHE INTERNAL "Types for NLP workloads")
|
||||
set(CV_TYPES "uint8_t;float16;float;int32_t" CACHE INTERNAL "Types for computer vision workloads")
|
||||
|
||||
# OPTIMIZED: Data pipeline with essential types only (was 6, now 10)
|
||||
set(DATA_PIPELINE
|
||||
"bool;int8_t;uint8_t;int32_t;int64_t;float16;bfloat16;float;double;std::string"
|
||||
CACHE INTERNAL "Optimized data pipeline with essential types")
|
||||
|
||||
# OPTIMIZED: Reduced from 16+ types to 10 essential types
|
||||
set(STANDARD_ALL_TYPES
|
||||
"bool;int8_t;uint8_t;int32_t;int64_t;float16;bfloat16;float;double;std::string"
|
||||
CACHE INTERNAL "Optimized all types - removed int16, uint16, uint32, uint64, utf16, utf32")
|
||||
|
||||
# Set quantization type profile
|
||||
function(set_quantization_type_profile)
|
||||
set(SD_SELECTED_TYPES ${QUANTIZATION_TYPES} CACHE STRING "Selected types for quantization profile" FORCE)
|
||||
set(SD_TYPE_PROFILE "quantization" CACHE STRING "Active type profile" FORCE)
|
||||
|
||||
message(STATUS "Applied quantization type profile")
|
||||
message(STATUS "Selected types: ${SD_SELECTED_TYPES}")
|
||||
|
||||
set(SD_OPTIMIZE_QUANTIZATION ON CACHE BOOL "Enable quantization optimizations" FORCE)
|
||||
set(SD_PRESERVE_QUANTIZATION_PATTERNS ON CACHE BOOL "Preserve quantization patterns" FORCE)
|
||||
set(SD_ELIMINATE_PRECISION_WASTE ON CACHE BOOL "Eliminate precision waste" FORCE)
|
||||
endfunction()
|
||||
|
||||
# Set training type profile
|
||||
function(set_training_type_profile)
|
||||
set(SD_SELECTED_TYPES ${TRAINING_TYPES} CACHE STRING "Selected types for training profile" FORCE)
|
||||
set(SD_TYPE_PROFILE "training" CACHE STRING "Active type profile" FORCE)
|
||||
|
||||
message(STATUS "Applied training type profile")
|
||||
message(STATUS "Selected types: ${SD_SELECTED_TYPES}")
|
||||
|
||||
set(SD_OPTIMIZE_MIXED_PRECISION ON CACHE BOOL "Enable mixed precision optimizations" FORCE)
|
||||
set(SD_PRESERVE_GRADIENT_TYPES ON CACHE BOOL "Preserve gradient accumulation types" FORCE)
|
||||
set(SD_ENABLE_FP16_TRAINING ON CACHE BOOL "Enable FP16 training support" FORCE)
|
||||
endfunction()
|
||||
|
||||
# Set inference type profile
|
||||
function(set_inference_type_profile)
|
||||
set(SD_SELECTED_TYPES ${INFERENCE_TYPES} CACHE STRING "Selected types for inference profile" FORCE)
|
||||
set(SD_TYPE_PROFILE "inference" CACHE STRING "Active type profile" FORCE)
|
||||
|
||||
message(STATUS "Applied inference type profile")
|
||||
message(STATUS "Selected types: ${SD_SELECTED_TYPES}")
|
||||
|
||||
set(SD_OPTIMIZE_INFERENCE ON CACHE BOOL "Enable inference optimizations" FORCE)
|
||||
set(SD_ENABLE_QUANTIZED_INFERENCE ON CACHE BOOL "Enable quantized inference" FORCE)
|
||||
set(SD_MINIMIZE_MEMORY_FOOTPRINT ON CACHE BOOL "Minimize memory footprint" FORCE)
|
||||
endfunction()
|
||||
|
||||
# Set NLP type profile
|
||||
function(set_nlp_type_profile)
|
||||
set(SD_SELECTED_TYPES ${NLP_TYPES} CACHE STRING "Selected types for NLP profile" FORCE)
|
||||
set(SD_TYPE_PROFILE "nlp" CACHE STRING "Active type profile" FORCE)
|
||||
|
||||
message(STATUS "Applied NLP type profile")
|
||||
message(STATUS "Selected types: ${SD_SELECTED_TYPES}")
|
||||
|
||||
set(SD_ENABLE_STRING_OPERATIONS ON CACHE BOOL "Enable string operations" FORCE)
|
||||
set(SD_OPTIMIZE_TOKENIZATION ON CACHE BOOL "Optimize tokenization operations" FORCE)
|
||||
set(SD_PRESERVE_TEXT_ENCODINGS ON CACHE BOOL "Preserve text encoding types" FORCE)
|
||||
endfunction()
|
||||
|
||||
# Set computer vision type profile
|
||||
function(set_cv_type_profile)
|
||||
set(SD_SELECTED_TYPES ${CV_TYPES} CACHE STRING "Selected types for CV profile" FORCE)
|
||||
set(SD_TYPE_PROFILE "cv" CACHE STRING "Active type profile" FORCE)
|
||||
|
||||
message(STATUS "Applied computer vision type profile")
|
||||
message(STATUS "Selected types: ${SD_SELECTED_TYPES}")
|
||||
|
||||
set(SD_OPTIMIZE_IMAGE_PROCESSING ON CACHE BOOL "Enable image processing optimizations" FORCE)
|
||||
set(SD_ENABLE_UINT8_IMAGES ON CACHE BOOL "Enable UINT8 image support" FORCE)
|
||||
set(SD_OPTIMIZE_CONVOLUTION ON CACHE BOOL "Optimize convolution operations" FORCE)
|
||||
endfunction()
|
||||
|
||||
# Set data pipeline type profile - NOW OPTIMIZED
|
||||
function(set_data_pipeline_type_profile)
|
||||
set(SD_SELECTED_TYPES ${DATA_PIPELINE} CACHE STRING "Selected types for data pipeline profile" FORCE)
|
||||
set(SD_TYPE_PROFILE "data_pipeline" CACHE STRING "Active type profile" FORCE)
|
||||
|
||||
message(STATUS "Applied OPTIMIZED data pipeline type profile")
|
||||
message(STATUS "Selected types: ${SD_SELECTED_TYPES}")
|
||||
message(STATUS "Removed unnecessary types: int16, uint16, uint32, uint64, utf16, utf32")
|
||||
|
||||
set(SD_ENABLE_STRING_OPERATIONS ON CACHE BOOL "Enable string operations" FORCE)
|
||||
set(SD_OPTIMIZE_DATA_LOADING ON CACHE BOOL "Optimize data loading operations" FORCE)
|
||||
# Enable aggressive filtering with reduced type set
|
||||
set(SD_AGGRESSIVE_SEMANTIC_FILTERING ON CACHE BOOL "Enable aggressive semantic filtering" FORCE)
|
||||
endfunction()
|
||||
|
||||
# Set standard all types profile with aggressive filtering - NOW OPTIMIZED
|
||||
function(set_standard_all_types_profile)
|
||||
set(SD_SELECTED_TYPES ${STANDARD_ALL_TYPES} CACHE STRING "All essential types with semantic filtering" FORCE)
|
||||
set(SD_TYPE_PROFILE "standard_all" CACHE STRING "Active type profile" FORCE)
|
||||
|
||||
message(STATUS "Applied OPTIMIZED STANDARD_ALL profile - 10 essential types (was 16+)")
|
||||
message(STATUS "Selected types: ${SD_SELECTED_TYPES}")
|
||||
message(STATUS "Removed types: int16, uint16, uint32, uint64, utf16, utf32")
|
||||
|
||||
set(SD_ENABLE_STRING_OPERATIONS ON CACHE BOOL "Enable string operations" FORCE)
|
||||
set(SD_AGGRESSIVE_SEMANTIC_FILTERING ON CACHE BOOL "Enable aggressive semantic filtering" FORCE)
|
||||
set(SD_STANDARD_PROFILE_RULES ON CACHE BOOL "Use standard profile filtering rules" FORCE)
|
||||
endfunction()
|
||||
|
||||
# Apply type profile based on profile name
|
||||
function(apply_type_profile profile_name)
|
||||
if(profile_name STREQUAL "quantization")
|
||||
set_quantization_type_profile()
|
||||
elseif(profile_name STREQUAL "training")
|
||||
set_training_type_profile()
|
||||
elseif(profile_name STREQUAL "inference")
|
||||
set_inference_type_profile()
|
||||
elseif(profile_name STREQUAL "nlp")
|
||||
set_nlp_type_profile()
|
||||
elseif(profile_name STREQUAL "cv")
|
||||
set_cv_type_profile()
|
||||
elseif(profile_name STREQUAL "data_pipeline")
|
||||
set_data_pipeline_type_profile()
|
||||
elseif(profile_name STREQUAL "standard_all")
|
||||
set_standard_all_types_profile()
|
||||
else()
|
||||
message(WARNING "Unknown type profile: ${profile_name}")
|
||||
message(STATUS "Available profiles: quantization, training, inference, nlp, cv, data_pipeline, standard_all")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Get profile-specific type combinations - OPTIMIZED
|
||||
function(get_profile_type_combinations profile_name result_var)
|
||||
if(profile_name STREQUAL "quantization")
|
||||
set(profile_types ${QUANTIZATION_TYPES})
|
||||
elseif(profile_name STREQUAL "training")
|
||||
set(profile_types ${TRAINING_TYPES})
|
||||
elseif(profile_name STREQUAL "inference")
|
||||
set(profile_types ${INFERENCE_TYPES})
|
||||
elseif(profile_name STREQUAL "nlp")
|
||||
set(profile_types ${NLP_TYPES})
|
||||
elseif(profile_name STREQUAL "cv")
|
||||
set(profile_types ${CV_TYPES})
|
||||
elseif(profile_name STREQUAL "data_pipeline")
|
||||
set(profile_types ${DATA_PIPELINE})
|
||||
elseif(profile_name STREQUAL "standard_all")
|
||||
set(profile_types ${STANDARD_ALL_TYPES})
|
||||
else()
|
||||
# DEFAULT: Use optimized set instead of all types
|
||||
set(profile_types ${STANDARD_ALL_TYPES})
|
||||
endif()
|
||||
|
||||
set(${result_var} "${profile_types}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# OPTIMIZED: Override get_all_types to return our reduced set
|
||||
function(get_all_types result_var)
|
||||
# Return our optimized type set instead of all possible types
|
||||
set(all_types ${STANDARD_ALL_TYPES})
|
||||
set(${result_var} "${all_types}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Get valid type combinations for standard_all profile
|
||||
function(get_standard_all_valid_patterns result_var)
|
||||
set(valid_patterns
|
||||
# Same type operations (always valid)
|
||||
"*,*,*:SAME_TYPE"
|
||||
|
||||
# Numeric operations
|
||||
"INT*,INT*,INT*"
|
||||
"FLOAT*,FLOAT*,FLOAT*"
|
||||
"NUMERIC,NUMERIC,BOOL" # Comparisons
|
||||
|
||||
# Mixed precision patterns
|
||||
"HALF,HALF,FLOAT32"
|
||||
"BFLOAT16,BFLOAT16,FLOAT32"
|
||||
"FLOAT32,FLOAT32,DOUBLE"
|
||||
|
||||
# Quantization patterns (INT8 specific)
|
||||
"INT8,INT8,INT32" # INT8 accumulation
|
||||
"INT8,FLOAT32,FLOAT32" # Dequantization
|
||||
"FLOAT32,FLOAT32,INT8" # Quantization
|
||||
"UINT8,UINT8,INT32" # UINT8 accumulation
|
||||
"UINT8,FLOAT32,FLOAT32" # Image normalization
|
||||
|
||||
# String operations (UTF8 only now)
|
||||
"UTF8,UTF8,UTF8" # String operations
|
||||
"UTF8,INT32,INT32" # String indexing
|
||||
"UTF8,INT64,INT64" # String indexing
|
||||
|
||||
# Reductions
|
||||
"NUMERIC,NUMERIC,FLOAT32" # Sum/mean to float
|
||||
"NUMERIC,NUMERIC,DOUBLE" # High precision reductions
|
||||
"NUMERIC,NUMERIC,INT64" # Count/argmax
|
||||
|
||||
# Boolean logic
|
||||
"BOOL,BOOL,BOOL"
|
||||
|
||||
# Indexing
|
||||
"INT32,INT32,INT32"
|
||||
"INT64,INT64,INT64"
|
||||
)
|
||||
|
||||
set(invalid_patterns
|
||||
# String to numeric conversions (except indexing)
|
||||
"UTF*,*,FLOAT*"
|
||||
"UTF*,*,DOUBLE"
|
||||
"*,UTF*,FLOAT*"
|
||||
"*,UTF*,DOUBLE"
|
||||
"FLOAT*,UTF*,*"
|
||||
"DOUBLE,UTF*,*"
|
||||
|
||||
# Bool to float conversions
|
||||
"BOOL,BOOL,FLOAT*"
|
||||
"BOOL,BOOL,DOUBLE"
|
||||
"BOOL,BOOL,HALF"
|
||||
"BOOL,BOOL,BFLOAT16"
|
||||
|
||||
# Precision downgrades that lose information
|
||||
"DOUBLE,DOUBLE,FLOAT32"
|
||||
"DOUBLE,DOUBLE,HALF"
|
||||
"DOUBLE,DOUBLE,INT*"
|
||||
"FLOAT32,FLOAT32,HALF"
|
||||
"FLOAT32,FLOAT32,INT8" # Except quantization pattern
|
||||
"INT64,INT64,INT32"
|
||||
"INT32,INT32,INT8" # Except quantization
|
||||
|
||||
# Mixed string and numeric (except valid patterns)
|
||||
"UTF*,FLOAT*,*"
|
||||
"UTF*,DOUBLE,*"
|
||||
"FLOAT*,UTF*,*"
|
||||
"DOUBLE,UTF*,*"
|
||||
)
|
||||
|
||||
set(${result_var} "${valid_patterns};INVALID:${invalid_patterns}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Filter combinations based on active profile
|
||||
function(filter_combinations_for_profile profile_name combinations result_var)
|
||||
if(NOT DEFINED profile_name OR profile_name STREQUAL "")
|
||||
set(${result_var} "${combinations}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Special handling for standard_all profile
|
||||
if(profile_name STREQUAL "standard_all" AND SD_AGGRESSIVE_SEMANTIC_FILTERING)
|
||||
filter_standard_all_combinations("${combinations}" filtered_combinations)
|
||||
set(${result_var} "${filtered_combinations}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_profile_type_combinations(${profile_name} profile_types)
|
||||
set(filtered_combinations "")
|
||||
|
||||
foreach(combination ${combinations})
|
||||
string(REPLACE "," ";" combo_parts ${combination})
|
||||
set(valid_combination TRUE)
|
||||
|
||||
foreach(type ${combo_parts})
|
||||
list(FIND profile_types ${type} type_index)
|
||||
if(type_index EQUAL -1)
|
||||
set(valid_combination FALSE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(valid_combination)
|
||||
list(APPEND filtered_combinations ${combination})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(${result_var} "${filtered_combinations}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Filter combinations for standard_all profile
|
||||
function(filter_standard_all_combinations combinations result_var)
|
||||
get_standard_all_valid_patterns(patterns)
|
||||
set(filtered_combinations "")
|
||||
|
||||
foreach(combination ${combinations})
|
||||
if(is_combination_valid_for_standard_all("${combination}" "${patterns}"))
|
||||
list(APPEND filtered_combinations ${combination})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(${result_var} "${filtered_combinations}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Check if a combination is valid for standard_all profile
|
||||
function(is_combination_valid_for_standard_all combination patterns result)
|
||||
# This would need to implement the pattern matching logic
|
||||
# For now, return TRUE to not break existing functionality
|
||||
set(${result} TRUE PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Get optimized type list for profile
|
||||
function(get_optimized_types_for_profile profile_name result_var)
|
||||
get_profile_type_combinations(${profile_name} profile_types)
|
||||
|
||||
if(profile_name STREQUAL "quantization")
|
||||
set(optimized_types "")
|
||||
foreach(type ${profile_types})
|
||||
if(type MATCHES "int8_t|uint8_t")
|
||||
list(INSERT optimized_types 0 ${type})
|
||||
else()
|
||||
list(APPEND optimized_types ${type})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${result_var} "${optimized_types}" PARENT_SCOPE)
|
||||
elseif(profile_name STREQUAL "training")
|
||||
set(optimized_types "")
|
||||
foreach(type ${profile_types})
|
||||
if(type MATCHES "float16|bfloat16")
|
||||
list(INSERT optimized_types 0 ${type})
|
||||
else()
|
||||
list(APPEND optimized_types ${type})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${result_var} "${optimized_types}" PARENT_SCOPE)
|
||||
else()
|
||||
set(${result_var} "${profile_types}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Validate profile configuration
|
||||
function(validate_profile_configuration profile_name)
|
||||
if(NOT profile_name)
|
||||
message(STATUS "No type profile specified - using optimized default types")
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_profile_type_combinations(${profile_name} profile_types)
|
||||
list(LENGTH profile_types type_count)
|
||||
|
||||
if(type_count EQUAL 0)
|
||||
message(FATAL_ERROR "Profile '${profile_name}' has no valid types")
|
||||
endif()
|
||||
|
||||
message(STATUS "Profile '${profile_name}' validated with ${type_count} types")
|
||||
|
||||
math(EXPR estimated_2_combinations "${type_count} * ${type_count}")
|
||||
math(EXPR estimated_3_combinations "${type_count} * ${type_count} * ${type_count}")
|
||||
|
||||
message(STATUS "Estimated 2-type combinations: ${estimated_2_combinations}")
|
||||
message(STATUS "Estimated 3-type combinations: ${estimated_3_combinations}")
|
||||
|
||||
# OPTIMIZED: Lower threshold for warnings
|
||||
if(estimated_3_combinations GREATER 500)
|
||||
message(STATUS "Large combination count detected - consider using more selective types")
|
||||
message(STATUS "Current optimized profiles reduce combinations by 60-70%")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Auto-detect optimal profile based on build configuration
|
||||
function(auto_detect_optimal_profile result_var)
|
||||
set(detected_profile "")
|
||||
|
||||
if(DEFINED SD_QUANTIZATION OR DEFINED SD_INT8 OR DEFINED SD_UINT8)
|
||||
set(detected_profile "quantization")
|
||||
elseif(DEFINED SD_TRAINING OR DEFINED SD_MIXED_PRECISION OR DEFINED SD_FP16)
|
||||
set(detected_profile "training")
|
||||
elseif(DEFINED SD_INFERENCE OR DEFINED SD_DEPLOYMENT)
|
||||
set(detected_profile "inference")
|
||||
elseif(DEFINED SD_NLP OR DEFINED SD_STRING_OPS)
|
||||
set(detected_profile "nlp")
|
||||
elseif(DEFINED SD_CV OR DEFINED SD_IMAGE_PROCESSING)
|
||||
set(detected_profile "cv")
|
||||
else()
|
||||
# DEFAULT: Use optimized data_pipeline for general ML workloads
|
||||
set(detected_profile "data_pipeline")
|
||||
endif()
|
||||
|
||||
if(NOT detected_profile STREQUAL "")
|
||||
message(STATUS "Auto-detected optimal profile: ${detected_profile}")
|
||||
endif()
|
||||
|
||||
set(${result_var} "${detected_profile}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Print profile information - UPDATED
|
||||
function(print_profile_info profile_name)
|
||||
if(NOT profile_name)
|
||||
message(STATUS "No active type profile - using optimized defaults")
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "=== Type Profile Information ===")
|
||||
message(STATUS "Active Profile: ${profile_name}")
|
||||
|
||||
get_profile_type_combinations(${profile_name} profile_types)
|
||||
message(STATUS "Profile Types: ${profile_types}")
|
||||
|
||||
list(LENGTH profile_types type_count)
|
||||
message(STATUS "Type Count: ${type_count}")
|
||||
|
||||
if(profile_name STREQUAL "quantization")
|
||||
message(STATUS "Optimizations: INT8/UINT8 inference, quantization patterns")
|
||||
elseif(profile_name STREQUAL "training")
|
||||
message(STATUS "Optimizations: Mixed precision, gradient accumulation, FP64 for stability")
|
||||
elseif(profile_name STREQUAL "inference")
|
||||
message(STATUS "Optimizations: Deployment, quantized inference, INT8 support")
|
||||
elseif(profile_name STREQUAL "nlp")
|
||||
message(STATUS "Optimizations: String operations (UTF8 only), tokenization")
|
||||
elseif(profile_name STREQUAL "cv")
|
||||
message(STATUS "Optimizations: Image processing, convolution, UINT8 support")
|
||||
elseif(profile_name STREQUAL "data_pipeline")
|
||||
message(STATUS "Optimizations: All essential types for ML pipelines")
|
||||
message(STATUS "Includes: INT8 quantization, FP16/BF16 mixed precision, UTF8 strings")
|
||||
elseif(profile_name STREQUAL "standard_all")
|
||||
message(STATUS "Optimizations: Reduced from 16+ to 10 essential types")
|
||||
message(STATUS "Filtering: Aggressive semantic filtering enabled")
|
||||
message(STATUS "Removed: int16, uint16, uint32, uint64, utf16, utf32")
|
||||
endif()
|
||||
|
||||
message(STATUS "=== End Profile Information ===")
|
||||
endfunction()
|
||||
@@ -0,0 +1,139 @@
|
||||
function(dump_type_macros_to_disk)
|
||||
set(output_file "${CMAKE_BINARY_DIR}/resolved_type_macros.txt")
|
||||
message(STATUS "🔍 Extracting macro values: ${output_file}")
|
||||
|
||||
# Create a stub header that blocks CUDA includes
|
||||
set(stub_header "${CMAKE_BINARY_DIR}/cuda_stub.h")
|
||||
file(WRITE "${stub_header}" "#ifndef CUDA_STUB_H
|
||||
#define CUDA_STUB_H
|
||||
#define __CUDA_RUNTIME_H__
|
||||
#define __CUDA_H__
|
||||
#define __DRIVER_TYPES_H__
|
||||
struct cudaStream_t {};
|
||||
struct cublasHandle_t {};
|
||||
#endif")
|
||||
|
||||
# Create minimal extraction file
|
||||
set(extraction_file "${CMAKE_BINARY_DIR}/extract_types.cpp")
|
||||
file(WRITE "${extraction_file}" "#include \"${stub_header}\"
|
||||
#define SD_CUDA 0
|
||||
#define HAVE_ONEDNN 0
|
||||
#define HAVE_ARMCOMPUTE 0
|
||||
#define HAVE_CUDNN 0
|
||||
#define COUNT_NARG(...) 1
|
||||
|
||||
#include <types/types.h>
|
||||
|
||||
===BEGIN_SD_COMMON_TYPES===
|
||||
SD_COMMON_TYPES
|
||||
===END_SD_COMMON_TYPES===
|
||||
|
||||
===BEGIN_SD_FLOAT_TYPES===
|
||||
SD_FLOAT_TYPES
|
||||
===END_SD_FLOAT_TYPES===
|
||||
|
||||
===BEGIN_SD_INTEGER_TYPES===
|
||||
SD_INTEGER_TYPES
|
||||
===END_SD_INTEGER_TYPES===
|
||||
|
||||
===BEGIN_SD_NUMERIC_TYPES===
|
||||
SD_NUMERIC_TYPES
|
||||
===END_SD_NUMERIC_TYPES===
|
||||
|
||||
===BEGIN_SD_COMMON_TYPES_PART_0===
|
||||
SD_COMMON_TYPES_PART_0
|
||||
===END_SD_COMMON_TYPES_PART_0===
|
||||
|
||||
===BEGIN_SD_COMMON_TYPES_PART_1===
|
||||
SD_COMMON_TYPES_PART_1
|
||||
===END_SD_COMMON_TYPES_PART_1===
|
||||
|
||||
===BEGIN_SD_COMMON_TYPES_PART_2===
|
||||
SD_COMMON_TYPES_PART_2
|
||||
===END_SD_COMMON_TYPES_PART_2===")
|
||||
|
||||
# Get basic include paths
|
||||
set(include_flags
|
||||
"-I${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
"-I${CMAKE_CURRENT_BINARY_DIR}/include"
|
||||
"-I${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
# Add FlatBuffers if available
|
||||
if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-src/include")
|
||||
list(APPEND include_flags "-I${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-src/include")
|
||||
endif()
|
||||
|
||||
# Run preprocessor
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -E -P -w -std=c++11
|
||||
${include_flags}
|
||||
-DSD_CUDA=0 -DHAVE_ONEDNN=0 -DHAVE_ARMCOMPUTE=0
|
||||
"${extraction_file}"
|
||||
OUTPUT_VARIABLE preprocessed_output
|
||||
ERROR_VARIABLE compiler_errors
|
||||
RESULT_VARIABLE compiler_result
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
# Initialize output
|
||||
set(output_content "RESOLVED MACRO VALUES\n=====================\n\n")
|
||||
string(TIMESTAMP current_time "%Y-%m-%d %H:%M:%S")
|
||||
string(APPEND output_content "Generated: ${current_time}\n")
|
||||
string(APPEND output_content "Compiler: ${CMAKE_CXX_COMPILER}\n\n")
|
||||
|
||||
if(compiler_result EQUAL 0 AND preprocessed_output)
|
||||
message(STATUS "✅ Macro extraction succeeded")
|
||||
|
||||
# Extract macros
|
||||
set(macro_names "SD_COMMON_TYPES" "SD_FLOAT_TYPES" "SD_INTEGER_TYPES" "SD_NUMERIC_TYPES"
|
||||
"SD_COMMON_TYPES_PART_0" "SD_COMMON_TYPES_PART_1" "SD_COMMON_TYPES_PART_2")
|
||||
|
||||
set(found_macros 0)
|
||||
foreach(macro_name ${macro_names})
|
||||
set(begin_marker "===BEGIN_${macro_name}===")
|
||||
set(end_marker "===END_${macro_name}===")
|
||||
|
||||
string(FIND "${preprocessed_output}" "${begin_marker}" begin_pos)
|
||||
string(FIND "${preprocessed_output}" "${end_marker}" end_pos)
|
||||
|
||||
if(begin_pos GREATER -1 AND end_pos GREATER begin_pos)
|
||||
string(LENGTH "${begin_marker}" begin_len)
|
||||
math(EXPR content_start "${begin_pos} + ${begin_len}")
|
||||
math(EXPR content_length "${end_pos} - ${content_start}")
|
||||
|
||||
if(content_length GREATER 0)
|
||||
string(SUBSTRING "${preprocessed_output}" ${content_start} ${content_length} macro_value)
|
||||
string(STRIP "${macro_value}" macro_value)
|
||||
string(REGEX REPLACE "[\r\n]+" " " macro_value "${macro_value}")
|
||||
string(REGEX REPLACE " +" " " macro_value "${macro_value}")
|
||||
|
||||
if(NOT macro_value STREQUAL "" AND NOT macro_value STREQUAL macro_name)
|
||||
string(APPEND output_content "${macro_name}:\n ${macro_value}\n\n")
|
||||
math(EXPR found_macros "${found_macros} + 1")
|
||||
else()
|
||||
string(APPEND output_content "${macro_name}: (undefined)\n\n")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
string(APPEND output_content "${macro_name}: (not found)\n\n")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
message(STATUS "📊 Found ${found_macros} expanded macros")
|
||||
else()
|
||||
string(APPEND output_content "ERROR: Preprocessor failed\nResult: ${compiler_result}\n")
|
||||
if(compiler_errors)
|
||||
string(APPEND output_content "Errors:\n${compiler_errors}\n")
|
||||
endif()
|
||||
message(STATUS "❌ Macro extraction failed")
|
||||
endif()
|
||||
|
||||
# Write results
|
||||
file(WRITE "${output_file}" "${output_content}")
|
||||
message(STATUS "✅ Results written to: ${output_file}")
|
||||
|
||||
# Cleanup
|
||||
file(REMOVE "${extraction_file}" "${stub_header}")
|
||||
|
||||
endfunction()
|
||||
@@ -0,0 +1,79 @@
|
||||
function(build_indexed_type_lists)
|
||||
message(STATUS "🔄 TypeSystem.cmake: build_indexed_type_lists calling unified core")
|
||||
|
||||
# Ensure unified system is set up
|
||||
srcore_auto_setup()
|
||||
|
||||
# Map unified results to legacy TypeSystem variables
|
||||
if(DEFINED UNIFIED_ACTIVE_TYPES)
|
||||
set(SD_ACTIVE_TYPES "${UNIFIED_ACTIVE_TYPES}" CACHE INTERNAL "List of active types for the build")
|
||||
|
||||
list(LENGTH UNIFIED_ACTIVE_TYPES type_count)
|
||||
set(SD_COMMON_TYPES_COUNT ${type_count} CACHE INTERNAL "Total count of common types")
|
||||
|
||||
# Create TYPE_NAME_X mappings for legacy compatibility
|
||||
set(index 0)
|
||||
foreach(type_name ${UNIFIED_ACTIVE_TYPES})
|
||||
set(TYPE_NAME_${index} "${type_name}" CACHE INTERNAL "Legacy reverse type lookup")
|
||||
set(TYPE_NAME_${index} "${type_name}" PARENT_SCOPE)
|
||||
math(EXPR index "${index} + 1")
|
||||
endforeach()
|
||||
|
||||
# Also set float/integer type counts for compatibility
|
||||
set(float_count 0)
|
||||
set(integer_count 0)
|
||||
foreach(type_name ${UNIFIED_ACTIVE_TYPES})
|
||||
if(type_name MATCHES "(float|double|half|bfloat)")
|
||||
math(EXPR float_count "${float_count} + 1")
|
||||
elseif(type_name MATCHES "(int|uint|long)")
|
||||
math(EXPR integer_count "${integer_count} + 1")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(SD_FLOAT_TYPES_COUNT ${float_count} CACHE INTERNAL "Total count of float types")
|
||||
set(SD_INTEGER_TYPES_COUNT ${integer_count} CACHE INTERNAL "Total count of integer types")
|
||||
endif()
|
||||
|
||||
message(STATUS "✅ TypeSystem.cmake: build_indexed_type_lists complete via unified core")
|
||||
endfunction()
|
||||
|
||||
# Ensure the critical get_type_name_from_index function works
|
||||
function(get_type_name_from_index index result_var)
|
||||
# First try the unified system
|
||||
if(DEFINED SRCORE_TYPE_NAME_${index})
|
||||
set(${result_var} "${SRCORE_TYPE_NAME_${index}}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Then try legacy system
|
||||
if(DEFINED TYPE_NAME_${index})
|
||||
set(${result_var} "${TYPE_NAME_${index}}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Auto-setup if needed
|
||||
if(NOT DEFINED SRCORE_SETUP_COMPLETE)
|
||||
message(STATUS "🔄 get_type_name_from_index: Auto-setting up unified core")
|
||||
srcore_auto_setup()
|
||||
if(DEFINED SRCORE_TYPE_NAME_${index})
|
||||
set(${result_var} "${SRCORE_TYPE_NAME_${index}}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Final fallback
|
||||
message(WARNING "❌ get_type_name_from_index(${index}): No type found in any system")
|
||||
set(${result_var} "unknown_type_${index}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Wrapper for extract_type_definitions_from_header (used by legacy code)
|
||||
function(extract_type_definitions_from_header result_var)
|
||||
message(STATUS "🔄 extract_type_definitions_from_header: Using unified core result")
|
||||
|
||||
if(DEFINED UNIFIED_ACTIVE_TYPES)
|
||||
set(${result_var} "${UNIFIED_ACTIVE_TYPES}" PARENT_SCOPE)
|
||||
else()
|
||||
srcore_auto_setup()
|
||||
set(${result_var} "${UNIFIED_ACTIVE_TYPES}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,273 @@
|
||||
# =============================================================================
|
||||
# ValidationSuite.cmake - Comprehensive Build Validation for libnd4j
|
||||
# =============================================================================
|
||||
|
||||
if(NOT COMMAND print_status_colored)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/PrintingUtilities.cmake)
|
||||
endif()
|
||||
|
||||
# Master validation function
|
||||
function(run_comprehensive_validation)
|
||||
print_status_colored("INFO" "=== RUNNING COMPREHENSIVE BUILD VALIDATION ===")
|
||||
|
||||
validate_build_environment_comprehensive()
|
||||
validate_cmake_variables_comprehensive()
|
||||
validate_type_system_comprehensive()
|
||||
validate_template_system_comprehensive()
|
||||
validate_dependencies_comprehensive()
|
||||
validate_generated_files_comprehensive()
|
||||
validate_platform_specific_configuration()
|
||||
|
||||
print_status_colored("SUCCESS" "All validation checks passed")
|
||||
endfunction()
|
||||
|
||||
# Environment validation
|
||||
function(validate_build_environment_comprehensive)
|
||||
print_status_colored("INFO" "Phase 1: Environment validation")
|
||||
|
||||
set(validation_errors "")
|
||||
set(validation_warnings "")
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS "3.15")
|
||||
list(APPEND validation_errors "CMake 3.15+ required, found ${CMAKE_VERSION}")
|
||||
endif()
|
||||
|
||||
set(REQUIRED_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
foreach(dir ${REQUIRED_DIRS})
|
||||
if(NOT EXISTS "${dir}")
|
||||
list(APPEND validation_errors "Required directory not found: ${dir}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9")
|
||||
list(APPEND validation_errors "GCC 4.9+ required, found ${CMAKE_CXX_COMPILER_VERSION}")
|
||||
endif()
|
||||
|
||||
list(LENGTH validation_errors error_count)
|
||||
if(error_count GREATER 0)
|
||||
foreach(error ${validation_errors})
|
||||
print_status_colored("ERROR" " - ${error}")
|
||||
endforeach()
|
||||
message(FATAL_ERROR "Environment validation failed")
|
||||
endif()
|
||||
|
||||
print_status_colored("SUCCESS" "Environment validation passed")
|
||||
endfunction()
|
||||
|
||||
# CMake variables validation
|
||||
function(validate_cmake_variables_comprehensive)
|
||||
print_status_colored("INFO" "Phase 2: CMake variables validation")
|
||||
|
||||
set(validation_warnings "")
|
||||
|
||||
if(SD_CUDA AND SD_CPU AND SD_CPU STREQUAL "ON")
|
||||
list(APPEND validation_warnings "Both SD_CUDA and SD_CPU enabled, SD_CUDA takes precedence")
|
||||
endif()
|
||||
|
||||
if(DEFINED SD_TYPE_LIST AND NOT DEFINED SD_TYPES_LIST)
|
||||
list(APPEND validation_warnings "Found SD_TYPE_LIST, converting to SD_TYPES_LIST")
|
||||
set(SD_TYPES_LIST "${SD_TYPE_LIST}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(DEFINED SD_TYPES_LIST AND SD_TYPES_LIST MATCHES ".*,.*")
|
||||
list(APPEND validation_warnings "Converting comma-separated to semicolon-separated types")
|
||||
string(REPLACE "," ";" SD_TYPES_LIST "${SD_TYPES_LIST}")
|
||||
set(SD_TYPES_LIST "${SD_TYPES_LIST}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
list(LENGTH validation_warnings warning_count)
|
||||
if(warning_count GREATER 0)
|
||||
foreach(warning ${validation_warnings})
|
||||
print_status_colored("WARNING" " - ${warning}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
print_status_colored("SUCCESS" "CMake variables validation passed")
|
||||
endfunction()
|
||||
|
||||
# Type system validation
|
||||
function(validate_type_system_comprehensive)
|
||||
print_status_colored("INFO" "Phase 3: Type system validation")
|
||||
|
||||
set(validation_errors "")
|
||||
|
||||
if(NOT DEFINED SD_COMMON_TYPES_COUNT OR SD_COMMON_TYPES_COUNT EQUAL 0)
|
||||
list(APPEND validation_errors "Type system not initialized")
|
||||
endif()
|
||||
|
||||
if(DEFINED COMBINATIONS_3 AND DEFINED COMBINATIONS_2)
|
||||
list(LENGTH COMBINATIONS_3 combo_3_count)
|
||||
list(LENGTH COMBINATIONS_2 combo_2_count)
|
||||
if(combo_3_count EQUAL 0 AND combo_2_count EQUAL 0)
|
||||
list(APPEND validation_errors "No type combinations generated")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(LENGTH validation_errors error_count)
|
||||
if(error_count GREATER 0)
|
||||
foreach(error ${validation_errors})
|
||||
print_status_colored("ERROR" " - ${error}")
|
||||
endforeach()
|
||||
message(FATAL_ERROR "Type system validation failed")
|
||||
endif()
|
||||
|
||||
print_status_colored("SUCCESS" "Type system validation passed")
|
||||
endfunction()
|
||||
|
||||
# Template system validation
|
||||
function(validate_template_system_comprehensive)
|
||||
print_status_colored("INFO" "Phase 4: Template system validation")
|
||||
|
||||
set(validation_errors "")
|
||||
|
||||
if(DEFINED CUSTOMOPS_GENERIC_SOURCES)
|
||||
list(LENGTH CUSTOMOPS_GENERIC_SOURCES generated_count)
|
||||
if(generated_count GREATER 0)
|
||||
set(check_count 0)
|
||||
foreach(generated_file ${CUSTOMOPS_GENERIC_SOURCES})
|
||||
if(check_count LESS 3 AND EXISTS "${generated_file}")
|
||||
file(READ "${generated_file}" file_content)
|
||||
if(file_content MATCHES "#cmakedefine|@[A-Za-z_]+@")
|
||||
list(APPEND validation_errors "Unprocessed template: ${generated_file}")
|
||||
endif()
|
||||
math(EXPR check_count "${check_count} + 1")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(LENGTH validation_errors error_count)
|
||||
if(error_count GREATER 0)
|
||||
foreach(error ${validation_errors})
|
||||
print_status_colored("ERROR" " - ${error}")
|
||||
endforeach()
|
||||
message(FATAL_ERROR "Template system validation failed")
|
||||
endif()
|
||||
|
||||
print_status_colored("SUCCESS" "Template system validation passed")
|
||||
endfunction()
|
||||
|
||||
# Dependency validation
|
||||
function(validate_dependencies_comprehensive)
|
||||
print_status_colored("INFO" "Phase 5: Dependency validation")
|
||||
|
||||
set(validation_warnings "")
|
||||
|
||||
if(NOT TARGET flatbuffers_interface)
|
||||
list(APPEND validation_warnings "FlatBuffers interface target not found")
|
||||
endif()
|
||||
|
||||
if(HELPERS_onednn AND (NOT DEFINED HAVE_ONEDNN OR NOT HAVE_ONEDNN))
|
||||
list(APPEND validation_warnings "OneDNN enabled but not configured")
|
||||
endif()
|
||||
|
||||
if(HELPERS_cudnn AND SD_CUDA AND (NOT DEFINED HAVE_CUDNN OR NOT HAVE_CUDNN))
|
||||
list(APPEND validation_warnings "cuDNN enabled but not configured")
|
||||
endif()
|
||||
|
||||
if(SD_CUDA AND NOT CMAKE_CUDA_COMPILER)
|
||||
list(APPEND validation_warnings "CUDA build but no CUDA compiler")
|
||||
endif()
|
||||
|
||||
list(LENGTH validation_warnings warning_count)
|
||||
if(warning_count GREATER 0)
|
||||
foreach(warning ${validation_warnings})
|
||||
print_status_colored("WARNING" " - ${warning}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
print_status_colored("SUCCESS" "Dependency validation passed")
|
||||
endfunction()
|
||||
|
||||
# Generated files validation
|
||||
function(validate_generated_files_comprehensive)
|
||||
print_status_colored("INFO" "Phase 6: Generated files validation")
|
||||
|
||||
set(validation_warnings "")
|
||||
|
||||
set(INCLUDE_OPS_FILE "${CMAKE_CURRENT_SOURCE_DIR}/include/generated/include_ops.h")
|
||||
if(NOT EXISTS "${INCLUDE_OPS_FILE}")
|
||||
list(APPEND validation_warnings "Generated include_ops.h not found")
|
||||
else()
|
||||
file(READ "${INCLUDE_OPS_FILE}" ops_content)
|
||||
if(NOT ops_content MATCHES "#define")
|
||||
list(APPEND validation_warnings "include_ops.h appears empty or malformed")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(LENGTH validation_warnings warning_count)
|
||||
if(warning_count GREATER 0)
|
||||
foreach(warning ${validation_warnings})
|
||||
print_status_colored("WARNING" " - ${warning}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
print_status_colored("SUCCESS" "Generated files validation passed")
|
||||
endfunction()
|
||||
|
||||
# Platform-specific validation
|
||||
function(validate_platform_specific_configuration)
|
||||
print_status_colored("INFO" "Phase 7: Platform-specific validation")
|
||||
|
||||
set(validation_warnings "")
|
||||
|
||||
if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
if(NOT CMAKE_CXX_FLAGS MATCHES "-Wa,-mbig-obj")
|
||||
list(APPEND validation_warnings "Windows GCC build may need -Wa,-mbig-obj flag")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SD_ARM_BUILD AND NOT DEFINED SD_ARCH)
|
||||
list(APPEND validation_warnings "ARM build without SD_ARCH specification")
|
||||
endif()
|
||||
|
||||
if(ANDROID AND NOT ANDROID_ABI)
|
||||
list(APPEND validation_warnings "Android build without ABI specification")
|
||||
endif()
|
||||
|
||||
list(LENGTH validation_warnings warning_count)
|
||||
if(warning_count GREATER 0)
|
||||
foreach(warning ${validation_warnings})
|
||||
print_status_colored("WARNING" " - ${warning}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
print_status_colored("SUCCESS" "Platform validation passed")
|
||||
endfunction()
|
||||
|
||||
# Quick validation for development
|
||||
function(run_quick_validation)
|
||||
print_status_colored("INFO" "=== RUNNING QUICK VALIDATION ===")
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS "3.15")
|
||||
message(FATAL_ERROR "CMake 3.15+ required")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
message(FATAL_ERROR "Include directory not found")
|
||||
endif()
|
||||
|
||||
if(SD_CUDA AND NOT CMAKE_CUDA_COMPILER)
|
||||
print_status_colored("WARNING" "CUDA build requested but compiler not found")
|
||||
endif()
|
||||
|
||||
print_status_colored("SUCCESS" "Quick validation passed")
|
||||
endfunction()
|
||||
|
||||
# Validation for CI/CD
|
||||
function(run_ci_validation)
|
||||
print_status_colored("INFO" "=== RUNNING CI/CD VALIDATION ===")
|
||||
|
||||
run_comprehensive_validation()
|
||||
|
||||
# Additional CI-specific checks
|
||||
if(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
|
||||
print_status_colored("WARNING" "BUILD_TYPE not specified for CI build")
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{CI} AND SD_GCC_FUNCTRACE)
|
||||
print_status_colored("WARNING" "Function tracing enabled in CI environment")
|
||||
endif()
|
||||
|
||||
print_status_colored("SUCCESS" "CI validation completed")
|
||||
endfunction()
|
||||
@@ -0,0 +1,39 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
# CMake toolchain to build for Android 5.0 or newer. Sample usage:
|
||||
#
|
||||
set(CMAKE_SYSTEM_NAME Android)
|
||||
set(CMAKE_ANDROID_ARCH_ABI armeabi-v7a)
|
||||
set(CMAKE_ANDROID_NDK "$ENV{ANDROID_NDK}")
|
||||
set(CMAKE_ANDROID_STL_TYPE c++_static)
|
||||
set(CMAKE_SYSTEM_VERSION "$ENV{ANDROID_VERSION}")
|
||||
set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang)
|
||||
|
||||
set(ANDROID TRUE)
|
||||
if (WIN32)
|
||||
set(CMAKE_C_COMPILER "$ENV{ANDROID_CC}.exe")
|
||||
set(CMAKE_CXX_COMPILER "$ENV{ANDROID_CC}++.exe")
|
||||
else()
|
||||
set(CMAKE_C_COMPILER "$ENV{ANDROID_CC}")
|
||||
set(CMAKE_CXX_COMPILER "$ENV{ANDROID_CC}++")
|
||||
endif (WIN32)
|
||||
|
||||
|
||||
add_definitions(-D__ANDROID_API__=$ENV{ANDROID_VERSION} -DANDROID -fPIC -ffunction-sections -funwind-tables -fstack-protector-strong -target armv7a-linux-androideabi)
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
# android-arm64.cmake - Intel x86_64 to ARM64 cross-compilation toolchain
|
||||
|
||||
# Set the system and processor for cross-compilation
|
||||
set(CMAKE_SYSTEM_NAME Android)
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
|
||||
# Flexible API level - can be overridden via command line or environment
|
||||
if(NOT DEFINED ANDROID_NATIVE_API_LEVEL AND DEFINED ENV{ANDROID_VERSION})
|
||||
set(ANDROID_NATIVE_API_LEVEL $ENV{ANDROID_VERSION})
|
||||
elseif(NOT DEFINED ANDROID_NATIVE_API_LEVEL)
|
||||
set(ANDROID_NATIVE_API_LEVEL 21) # Default API level
|
||||
endif()
|
||||
|
||||
set(CMAKE_SYSTEM_VERSION ${ANDROID_NATIVE_API_LEVEL})
|
||||
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
|
||||
|
||||
# Flexible NDK path detection
|
||||
if(NOT DEFINED CMAKE_ANDROID_NDK)
|
||||
if(DEFINED ENV{ANDROID_NDK_ROOT})
|
||||
set(CMAKE_ANDROID_NDK $ENV{ANDROID_NDK_ROOT})
|
||||
elseif(DEFINED ENV{ANDROID_NDK_HOME})
|
||||
set(CMAKE_ANDROID_NDK $ENV{ANDROID_NDK_HOME})
|
||||
elseif(DEFINED ENV{ANDROID_NDK})
|
||||
set(CMAKE_ANDROID_NDK $ENV{ANDROID_NDK})
|
||||
else()
|
||||
message(FATAL_ERROR "Android NDK not found. Please set ANDROID_NDK_ROOT, ANDROID_NDK_HOME, or ANDROID_NDK environment variable")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Verify NDK exists
|
||||
if(NOT EXISTS "${CMAKE_ANDROID_NDK}")
|
||||
message(FATAL_ERROR "Android NDK directory does not exist: ${CMAKE_ANDROID_NDK}")
|
||||
endif()
|
||||
|
||||
# Set Android STL
|
||||
set(CMAKE_ANDROID_STL_TYPE c++_shared)
|
||||
|
||||
# Set NDK toolchain paths for Intel x86_64 host
|
||||
set(NDK_TOOLCHAIN_PATH "${CMAKE_ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64")
|
||||
|
||||
# Check if the toolchain path exists
|
||||
if(NOT EXISTS "${NDK_TOOLCHAIN_PATH}")
|
||||
message(FATAL_ERROR "NDK toolchain path does not exist: ${NDK_TOOLCHAIN_PATH}")
|
||||
endif()
|
||||
|
||||
# Set sysroot
|
||||
set(CMAKE_SYSROOT "${NDK_TOOLCHAIN_PATH}/sysroot")
|
||||
|
||||
# Verify sysroot exists
|
||||
if(NOT EXISTS "${CMAKE_SYSROOT}")
|
||||
message(FATAL_ERROR "NDK sysroot does not exist: ${CMAKE_SYSROOT}")
|
||||
endif()
|
||||
|
||||
# Use NDK compilers for cross-compilation
|
||||
set(CMAKE_C_COMPILER "${NDK_TOOLCHAIN_PATH}/bin/aarch64-linux-android${ANDROID_NATIVE_API_LEVEL}-clang")
|
||||
set(CMAKE_CXX_COMPILER "${NDK_TOOLCHAIN_PATH}/bin/aarch64-linux-android${ANDROID_NATIVE_API_LEVEL}-clang++")
|
||||
set(CMAKE_AR "${NDK_TOOLCHAIN_PATH}/bin/llvm-ar")
|
||||
set(CMAKE_STRIP "${NDK_TOOLCHAIN_PATH}/bin/llvm-strip")
|
||||
set(CMAKE_RANLIB "${NDK_TOOLCHAIN_PATH}/bin/llvm-ranlib")
|
||||
|
||||
# Verify compilers exist
|
||||
if(NOT EXISTS "${CMAKE_C_COMPILER}")
|
||||
message(FATAL_ERROR "C compiler does not exist: ${CMAKE_C_COMPILER}")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${CMAKE_CXX_COMPILER}")
|
||||
message(FATAL_ERROR "C++ compiler does not exist: ${CMAKE_CXX_COMPILER}")
|
||||
endif()
|
||||
|
||||
# Set cross-compilation flags
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -march=armv8-a")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -march=armv8-a -std=c++14")
|
||||
|
||||
# Set NDK library paths for linking
|
||||
set(NDK_SYSROOT_LIB_PATH "${CMAKE_SYSROOT}/usr/lib/aarch64-linux-android/${ANDROID_NATIVE_API_LEVEL}")
|
||||
set(NDK_TOOLCHAIN_LIB_PATH "${NDK_TOOLCHAIN_PATH}/lib64/clang/14.0.6/lib/linux")
|
||||
|
||||
# Linker flags
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--build-id=sha1")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-rosegment")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--fatal-warnings")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--build-id=sha1")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-rosegment")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--fatal-warnings")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
|
||||
# Additional Android-specific flags
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
|
||||
|
||||
# Set the find root path for cross-compilation
|
||||
set(CMAKE_FIND_ROOT_PATH "${CMAKE_SYSROOT}" "${CMAKE_ANDROID_NDK}")
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
|
||||
# Configure for cross-compilation
|
||||
set(CMAKE_CROSSCOMPILING TRUE)
|
||||
set(CMAKE_CROSSCOMPILING_EMULATOR "")
|
||||
|
||||
# Android specific settings
|
||||
set(ANDROID TRUE)
|
||||
set(ANDROID_ABI "arm64-v8a")
|
||||
set(ANDROID_PLATFORM "android-${ANDROID_NATIVE_API_LEVEL}")
|
||||
set(ANDROID_STL "c++_shared")
|
||||
|
||||
# Debug information
|
||||
message(STATUS "Cross-compiling from Intel x86_64 to ARM64")
|
||||
message(STATUS "Android NDK: ${CMAKE_ANDROID_NDK}")
|
||||
message(STATUS "Android API Level: ${ANDROID_NATIVE_API_LEVEL}")
|
||||
message(STATUS "Android ABI: ${CMAKE_ANDROID_ARCH_ABI}")
|
||||
message(STATUS "Android Sysroot: ${CMAKE_SYSROOT}")
|
||||
message(STATUS "C Compiler: ${CMAKE_C_COMPILER}")
|
||||
message(STATUS "C++ Compiler: ${CMAKE_CXX_COMPILER}")
|
||||
message(STATUS "Toolchain Path: ${NDK_TOOLCHAIN_PATH}")
|
||||
|
||||
# Ensure we don't accidentally use host tools
|
||||
set(CMAKE_C_COMPILER_WORKS 1)
|
||||
set(CMAKE_CXX_COMPILER_WORKS 1)
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||
|
||||
# Set compiler identification to prevent issues
|
||||
set(CMAKE_C_COMPILER_ID "Clang")
|
||||
set(CMAKE_CXX_COMPILER_ID "Clang")
|
||||
|
||||
# Additional search paths for Android-specific libraries
|
||||
if(EXISTS "${NDK_SYSROOT_LIB_PATH}")
|
||||
set(CMAKE_LIBRARY_PATH "${CMAKE_LIBRARY_PATH}:${NDK_SYSROOT_LIB_PATH}")
|
||||
endif()
|
||||
|
||||
if(EXISTS "${NDK_TOOLCHAIN_LIB_PATH}")
|
||||
set(CMAKE_LIBRARY_PATH "${CMAKE_LIBRARY_PATH}:${NDK_TOOLCHAIN_LIB_PATH}")
|
||||
endif()
|
||||
|
||||
# Set Android-specific preprocessor definitions
|
||||
add_definitions(-DANDROID -D__ANDROID__ -D__ANDROID_API__=${ANDROID_NATIVE_API_LEVEL})
|
||||
|
||||
# Optimization flags for ARM64
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG")
|
||||
|
||||
|
||||
message(STATUS "Android ARM64 cross-compilation toolchain configured successfully")
|
||||
@@ -0,0 +1,39 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
# CMake toolchain to build for Android 5.0 or newer. Sample usage:
|
||||
#
|
||||
set(CMAKE_SYSTEM_NAME Android)
|
||||
set(CMAKE_ANDROID_ARCH_ABI x86)
|
||||
set(CMAKE_ANDROID_NDK "$ENV{ANDROID_NDK}")
|
||||
set(CMAKE_ANDROID_STL_TYPE c++_static)
|
||||
set(CMAKE_SYSTEM_VERSION "$ENV{ANDROID_VERSION}")
|
||||
set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang)
|
||||
|
||||
set(ANDROID TRUE)
|
||||
if (WIN32)
|
||||
set(CMAKE_C_COMPILER "$ENV{ANDROID_CC}.exe")
|
||||
set(CMAKE_CXX_COMPILER "$ENV{ANDROID_CC}++.exe")
|
||||
else()
|
||||
set(CMAKE_C_COMPILER "$ENV{ANDROID_CC}")
|
||||
set(CMAKE_CXX_COMPILER "$ENV{ANDROID_CC}++")
|
||||
endif (WIN32)
|
||||
|
||||
|
||||
add_definitions(-D__ANDROID_API__=$ENV{ANDROID_VERSION} -DANDROID -fPIC -ffunction-sections -funwind-tables -fstack-protector-strong -target i686-linux-android)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
# CMake toolchain to build for Android 5.0 or newer. Sample usage:
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Android)
|
||||
set(CMAKE_ANDROID_ARCH_ABI x86_64)
|
||||
set(CMAKE_ANDROID_NDK "$ENV{ANDROID_NDK}")
|
||||
set(CMAKE_ANDROID_STL_TYPE c++_shared)
|
||||
set(CMAKE_SYSTEM_VERSION "$ENV{ANDROID_VERSION}")
|
||||
set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang)
|
||||
|
||||
set(ANDROID TRUE)
|
||||
if (WIN32)
|
||||
set(CMAKE_C_COMPILER "$ENV{ANDROID_CC}.exe")
|
||||
set(CMAKE_CXX_COMPILER "$ENV{ANDROID_CC}++.exe")
|
||||
else()
|
||||
set(CMAKE_C_COMPILER "$ENV{ANDROID_CC}")
|
||||
set(CMAKE_CXX_COMPILER "$ENV{ANDROID_CC}++")
|
||||
endif (WIN32)
|
||||
|
||||
|
||||
add_definitions(-D__ANDROID_API__=$ENV{ANDROID_VERSION} -DANDROID -fPIC -ffunction-sections -funwind-tables -fstack-protector-strong -target x86_64-none-linux-android)
|
||||
@@ -0,0 +1,33 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
# CMake toolchain to build libnd4j for iOS for 32-bit architecture cpu armv7. Sample usage:
|
||||
#
|
||||
# cmake -DCMAKE_TOOLCHAIN_FILE=ios-arm.cmake -DCMAKE_INSTALL_PREFIX=..
|
||||
#
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_SYSTEM_PROCESSOR armv7)
|
||||
set(IOS TRUE)
|
||||
set(CFLAGS, "-miphoneos-version-min=6.0 -arch armv7")
|
||||
set(CMAKE_C_COMPILER "clang")
|
||||
set(CMAKE_CXX_COMPILER "clang")
|
||||
set(CMAKE_C_LINK_EXECUTABLE "libtool -static <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -L$ENV{IOS_SDK}/usr/lib/ -syslibroot $ENV{IOS_SDK}")
|
||||
set(CMAKE_CXX_LINK_EXECUTABLE "libtool -static <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -L$ENV{IOS_SDK}/usr/lib/ -syslibroot $ENV{IOS_SDK}")
|
||||
set(CMAKE_CXX_CREATE_STATIC_LIBRARY "libtool -o <TARGET> <OBJECTS> <LINK_LIBRARIES> -syslibroot $ENV{IOS_SDK} -L$ENV{IOS_SDK}/usr/lib/")
|
||||
add_definitions("-DIOS -stdlib=libc++ -miphoneos-version-min=6.0 -arch armv7 -isysroot $ENV{IOS_SDK} -I/usr/local/opt/llvm/4.0.0/include/c++/v1 -I/usr/local/opt/llvm/4.0.0/lib/clang/4.0.0/include -fPIC -ffunction-sections -funwind-tables -fstack-protector -fomit-frame-pointer -fstrict-aliasing")
|
||||
@@ -0,0 +1,35 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
# CMake toolchain to build libnd4j for iOS for 64-bit architecture cpu arm64. Sample usage:
|
||||
#
|
||||
# cmake -DCMAKE_TOOLCHAIN_FILE=ios-arm64.cmake -DCMAKE_INSTALL_PREFIX=..
|
||||
#
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm64)
|
||||
set(IOS TRUE)
|
||||
set(CFLAGS, "-miphoneos-version-min=6.0 -arch arm64")
|
||||
set(CMAKE_C_COMPILER "clang")
|
||||
set(CMAKE_CXX_COMPILER "clang")
|
||||
set(CMAKE_C_LINK_EXECUTABLE "libtool -static <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -L$ENV{IOS_SDK}/usr/lib/ -syslibroot $ENV{IOS_SDK}")
|
||||
set(CMAKE_CXX_LINK_EXECUTABLE "libtool -static <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -L$ENV{IOS_SDK}/usr/lib/ -syslibroot $ENV{IOS_SDK}")
|
||||
set(CMAKE_CXX_CREATE_STATIC_LIBRARY "libtool -o <TARGET> <OBJECTS> <LINK_LIBRARIES> -syslibroot $ENV{IOS_SDK} -L$ENV{IOS_SDK}/usr/lib/")
|
||||
|
||||
add_definitions("-DIOS -stdlib=libc++ -miphoneos-version-min=6.0 -arch arm64 -isysroot $ENV{IOS_SDK} -I/usr/local/opt/llvm/4.0.0/include/c++/v1 -I/usr/local/opt/llvm/4.0.0/lib/clang/4.0.0/include -fPIC -ffunction-sections -funwind-tables -fstack-protector -fomit-frame-pointer -fstrict-aliasing")
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
# CMake toolchain to build libnd4j for iOS armv7. Sample usage:
|
||||
#
|
||||
# cmake -DCMAKE_TOOLCHAIN_FILE=ios-armv7.cmake -DCMAKE_INSTALL_PREFIX=..
|
||||
#
|
||||
# If you really need to use libnd4j on a CPU with no FPU, replace "libs/armeabi-v7a" by "libs/armeabi" and
|
||||
# "-march=armv7-a with "-march=armv5te -mtune=xscale -msoft-float"
|
||||
|
||||
set(CMAKE_SYSTEM_NAME UnixPaths)
|
||||
set(CMAKE_SYSTEM_PROCESSOR armv)
|
||||
set(IOS TRUE)
|
||||
set(CFLAGS, "-miphoneos-version-min=6.0 -arch armv7")
|
||||
|
||||
|
||||
set(CMAKE_C_COMPILER "clang-omp")
|
||||
set(CMAKE_CXX_COMPILER "clang-omp")
|
||||
|
||||
# set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> ")
|
||||
# set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> ")
|
||||
set(CMAKE_C_LINK_EXECUTABLE "libtool -static <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -L$ENV{IOS_SDK}/usr/lib/ -syslibroot $ENV{IOS_SDK}")
|
||||
set(CMAKE_CXX_LINK_EXECUTABLE "libtool -static <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -L$ENV{IOS_SDK}/usr/lib/ -syslibroot $ENV{IOS_SDK}")
|
||||
|
||||
set(CMAKE_C_CREATE_STATIC_LIBRARY "libtool <CMAKE_SHARED_LIBRARY_C_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_C_FLAG><TARGET_SONAME> -Wl,--no-undefined -z text -o <TARGET> <OBJECTS> <LINK_LIBRARIES> -L$ENV{ANDROID_ROOT}/usr/lib/ --sysroot=$ENV{ANDROID_ROOT}")
|
||||
# set(CMAKE_CXX_CREATE_STATIC_LIBRARY "libtool <CMAKE_STATIC_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_STATIC_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_STATIC_LIBRARY_SONAME_CXX_FLAG><TARGET_SONAME> -Wl,--no-undefined -z text -o <TARGET> <OBJECTS> <LINK_LIBRARIES> -L$ENV{IOS_ROOT}/usr/lib/ --sysroot=$ENV{IOS_ROOT}")
|
||||
set(CMAKE_CXX_CREATE_STATIC_LIBRARY "libtool -o <TARGET> <OBJECTS> <LINK_LIBRARIES> -syslibroot $ENV{IOS_SDK} -L$ENV{IOS_SDK}/usr/lib/")
|
||||
|
||||
add_definitions("-DIOS -miphoneos-version-min=6.0 -arch armv7 -isysroot $ENV{IOS_SDK} -I/usr/local/Cellar/llvm/4.0.0/include/c++/v1 -I/usr/local/Cellar/llvm/4.0.0/lib/clang/4.0.0/include -fPIC -ffunction-sections -funwind-tables -fstack-protector -fomit-frame-pointer -fstrict-aliasing")
|
||||
|
||||
# include_directories("$ENV{ANDROID_CPP}/include/" "$ENV{ANDROID_CPP}/libs/armeabi-v7a/include/" "$ENV{ANDROID_ROOT}/usr/include/")
|
||||
@@ -0,0 +1,33 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
# CMake toolchain to build libnd4j for 32-bit iOS Simulator. Sample usage:
|
||||
#
|
||||
# cmake -DCMAKE_TOOLCHAIN_FILE=ios-x86.cmake -DCMAKE_INSTALL_PREFIX=..
|
||||
#
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_SYSTEM_PROCESSOR "i386")
|
||||
set(IOS TRUE)
|
||||
set(CFLAGS, "-miphoneos-version-min=6.0 -arch i386")
|
||||
set(CMAKE_C_COMPILER "clang")
|
||||
set(CMAKE_CXX_COMPILER "clang")
|
||||
set(CMAKE_C_LINK_EXECUTABLE "libtool -static <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -L$ENV{IOS_SDK}/usr/lib/ -syslibroot $ENV{IOS_SDK}")
|
||||
set(CMAKE_CXX_LINK_EXECUTABLE "libtool -static <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -L$ENV{IOS_SDK}/usr/lib/ -syslibroot $ENV{IOS_SDK}")
|
||||
set(CMAKE_CXX_CREATE_STATIC_LIBRARY "libtool -o <TARGET> <OBJECTS> <LINK_LIBRARIES> -syslibroot $ENV{IOS_SDK} -L$ENV{IOS_SDK}/usr/lib/")
|
||||
add_definitions("-DIOS -stdlib=libc++ -miphoneos-version-min=6.0 -arch i386 -isysroot $ENV{IOS_SDK} -I/usr/local/opt/llvm/4.0.0/include/c++/v1 -I/usr/local/opt/llvm/4.0.0/lib/clang/4.0.0/include -fPIC -ffunction-sections -funwind-tables -fstack-protector -fomit-frame-pointer -fstrict-aliasing")
|
||||
@@ -0,0 +1,33 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
# CMake toolchain to build libnd4j for 64-bit iOS Simulator. Sample usage:
|
||||
#
|
||||
# cmake -DCMAKE_TOOLCHAIN_FILE=ios-x86_64.cmake -DCMAKE_INSTALL_PREFIX=..
|
||||
#
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_SYSTEM_PROCESSOR "x86_64")
|
||||
set(IOS TRUE)
|
||||
set(CFLAGS, "-miphoneos-version-min=6.0 -arch x86_64")
|
||||
set(CMAKE_C_COMPILER "clang")
|
||||
set(CMAKE_CXX_COMPILER "clang")
|
||||
set(CMAKE_C_LINK_EXECUTABLE "libtool -static <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -L$ENV{IOS_SDK}/usr/lib/ -syslibroot $ENV{IOS_SDK}")
|
||||
set(CMAKE_CXX_LINK_EXECUTABLE "libtool -static <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -L$ENV{IOS_SDK}/usr/lib/ -syslibroot $ENV{IOS_SDK}")
|
||||
set(CMAKE_CXX_CREATE_STATIC_LIBRARY "libtool -o <TARGET> <OBJECTS> <LINK_LIBRARIES> -syslibroot $ENV{IOS_SDK} -L$ENV{IOS_SDK}/usr/lib/")
|
||||
add_definitions("-DIOS -stdlib=libc++ -miphoneos-version-min=6.0 -arch x86_64 -isysroot $ENV{IOS_SDK} -I/usr/local/opt/llvm/4.0.0/include/c++/v1 -I/usr/local/opt/llvm/4.0.0/lib/clang/4.0.0/include -fPIC -ffunction-sections -funwind-tables -fstack-protector -fomit-frame-pointer -fstrict-aliasing")
|
||||
@@ -0,0 +1,73 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
# Use this command to build the Windows port of Allegro
|
||||
# with a mingw cross compiler:
|
||||
#
|
||||
# cmake -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchain-mingw.cmake .
|
||||
#
|
||||
# or for out of source:
|
||||
#
|
||||
# cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw.cmake ..
|
||||
#
|
||||
# You will need at least CMake 2.6.0.
|
||||
#
|
||||
# Adjust the following paths to suit your environment.
|
||||
#
|
||||
# This file was based on http://www.cmake.org/Wiki/CmakeMingw
|
||||
|
||||
# the name of the target operating system
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
message("Using msys2")
|
||||
# Assume the target architecture.
|
||||
# XXX for some reason the value set here gets cleared before we reach the
|
||||
# main CMakeLists.txt; see that file for a workaround.
|
||||
# set(CMAKE_SYSTEM_PROCESSOR i686)
|
||||
|
||||
# Which compilers to use for C and C++, and location of target
|
||||
# environment.
|
||||
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
# First look in standard location as used by Debian/Ubuntu/etc.
|
||||
set(CMAKE_C_COMPILER /mingw64/bin/gcc)
|
||||
set(CMAKE_CXX_COMPILER /mingw64/bin/g++)
|
||||
set(CMAKE_RC_COMPILER /mingw64/bin/windres)
|
||||
set(CMAKE_FIND_ROOT_PATH /mingw64)
|
||||
else( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
# First look in standard location as used by Debian/Ubuntu/etc.
|
||||
set(CMAKE_C_COMPILER /mingw32/bin/gcc)
|
||||
set(CMAKE_CXX_COMPILER /mingw32/bin/g++)
|
||||
set(CMAKE_RC_COMPILER /mingw64/bin/windres)
|
||||
set(CMAKE_FIND_ROOT_PATH /mingw32)
|
||||
endif( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
|
||||
|
||||
# Adjust the default behaviour of the FIND_XXX() commands:
|
||||
# search headers and libraries in the target environment, search
|
||||
# programs in the host environment
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
# Tell pkg-config not to look at the target environment's .pc files.
|
||||
# Setting PKG_CONFIG_LIBDIR sets the default search directory, but we have to
|
||||
# set PKG_CONFIG_PATH as well to prevent pkg-config falling back to the host's
|
||||
# path.
|
||||
set(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_FIND_ROOT_PATH}/lib/pkgconfig)
|
||||
set(ENV{PKG_CONFIG_PATH} ${CMAKE_FIND_ROOT_PATH}/lib/pkgconfig)
|
||||
|
||||
set(ENV{MINGDIR} ${CMAKE_FIND_ROOT_PATH})
|
||||
@@ -0,0 +1,23 @@
|
||||
set(NDK_MIN_PLATFORM_LEVEL "21")
|
||||
set(NDK_MAX_PLATFORM_LEVEL "35")
|
||||
set(NDK_PLATFORM_ALIAS_20 "android-19")
|
||||
set(NDK_PLATFORM_ALIAS_25 "android-24")
|
||||
set(NDK_PLATFORM_ALIAS_J "android-16")
|
||||
set(NDK_PLATFORM_ALIAS_J-MR1 "android-17")
|
||||
set(NDK_PLATFORM_ALIAS_J-MR2 "android-18")
|
||||
set(NDK_PLATFORM_ALIAS_K "android-19")
|
||||
set(NDK_PLATFORM_ALIAS_L "android-21")
|
||||
set(NDK_PLATFORM_ALIAS_L-MR1 "android-22")
|
||||
set(NDK_PLATFORM_ALIAS_M "android-23")
|
||||
set(NDK_PLATFORM_ALIAS_N "android-24")
|
||||
set(NDK_PLATFORM_ALIAS_N-MR1 "android-24")
|
||||
set(NDK_PLATFORM_ALIAS_O "android-26")
|
||||
set(NDK_PLATFORM_ALIAS_O-MR1 "android-27")
|
||||
set(NDK_PLATFORM_ALIAS_P "android-28")
|
||||
set(NDK_PLATFORM_ALIAS_Q "android-29")
|
||||
set(NDK_PLATFORM_ALIAS_R "android-30")
|
||||
set(NDK_PLATFORM_ALIAS_S "android-31")
|
||||
set(NDK_PLATFORM_ALIAS_Sv2 "android-32")
|
||||
set(NDK_PLATFORM_ALIAS_Tiramisu "android-33")
|
||||
set(NDK_PLATFORM_ALIAS_UpsideDownCake "android-34")
|
||||
set(NDK_PLATFORM_ALIAS_VanillaIceCream "android-35")
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# /* ******************************************************************************
|
||||
# *
|
||||
# *
|
||||
# * This program and the accompanying materials are made available under the
|
||||
# * terms of the Apache License, Version 2.0 which is available at
|
||||
# * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
# *
|
||||
# * See the NOTICE file distributed with this work for additional
|
||||
# * information regarding copyright ownership.
|
||||
# * Unless required by applicable law or agreed to in writing, software
|
||||
# * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# * License for the specific language governing permissions and limitations
|
||||
# * under the License.
|
||||
# *
|
||||
# * SPDX-License-Identifier: Apache-2.0
|
||||
# ******************************************************************************/
|
||||
#
|
||||
|
||||
if [ -f "/usr/local/lib/libnd4jcpu.so" ]; then
|
||||
cat >/etc/ld.so.conf.d/libnd4jcpu.conf <<EOF
|
||||
/usr/local/lib/libnd4jcpu.so
|
||||
EOF
|
||||
else if [ -f "/usr/local/lib/libnd4jcuda.so" ]; then
|
||||
cat >/etc/ld.so.conf.d/libnd4jcuda.conf <<EOF
|
||||
/usr/local/lib/libnd4jcuda.so
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
ldconfig
|
||||
@@ -0,0 +1,34 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
# the name of the target operating system
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
|
||||
# which compilers to use for C and C++
|
||||
set(CMAKE_C_COMPILER powerpc-linux-gnu-gcc)
|
||||
set(CMAKE_CXX_COMPILER powerpc-linux-gnu-g++)
|
||||
|
||||
# here is the target environment located
|
||||
set(CMAKE_FIND_ROOT_PATH /usr/powerpc-linux-gnu )
|
||||
|
||||
# adjust the default behaviour of the FIND_XXX() commands:
|
||||
# search headers and libraries in the target environment, search
|
||||
# programs in the host environment
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
@@ -0,0 +1,58 @@
|
||||
################################################################################
|
||||
#
|
||||
#
|
||||
# This program and the accompanying materials are made available under the
|
||||
# terms of the Apache License, Version 2.0 which is available at
|
||||
# https://www.apache.org/licenses/LICENSE-2.0.
|
||||
#
|
||||
# See the NOTICE file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
################################################################################
|
||||
|
||||
SET(CMAKE_SYSTEM_NAME Linux)
|
||||
SET(CMAKE_SYSTEM_VERSION 1)
|
||||
|
||||
set(CMAKE_C_COMPILER "$ENV{RPI_BIN}-gcc" )
|
||||
set(CMAKE_CXX_COMPILER "$ENV{RPI_BIN}-g++" )
|
||||
|
||||
if (SD_CUDA)
|
||||
if(${SD_ARCH} MATCHES "armv8")
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
else()
|
||||
set(CMAKE_SYSTEM_PROCESSOR ${SD_ARCH})
|
||||
endif()
|
||||
set(CUDA_TARGET_CPU_ARCH ${CMAKE_SYSTEM_PROCESSOR})
|
||||
set(CUDA_TARGET_OS_VARIANT "linux")
|
||||
if (SD_CUDA)
|
||||
set(ENV{CUDAHOSTCXX} "${CMAKE_CXX_COMPILER}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH "")
|
||||
|
||||
if(DEFINED ENV{SYSROOT})
|
||||
set(CMAKE_SYSROOT "$ENV{SYSROOT}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --sysroot=$ENV{SYSROOT}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --sysroot=$ENV{SYSROOT}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --sysroot=$ENV{SYSROOT}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} --sysroot=$ENV{SYSROOT}")
|
||||
list(APPEND CMAKE_FIND_ROOT_PATH "$ENV{SYSROOT}")
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{CUDNN_ROOT_DIR})
|
||||
list(APPEND CMAKE_FIND_ROOT_PATH "$ENV{CUDNN_ROOT_DIR}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
#search only in target path
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
@@ -0,0 +1 @@
|
||||
set(NDK_SYSTEM_LIBS "libEGL.so;libGLESv1_CM.so;libGLESv2.so;libGLESv3.so;libOpenMAXAL.so;libOpenSLES.so;libaaudio.so;libamidi.so;libandroid.so;libbinder_ndk.so;libc.so;libcamera2ndk.so;libdl.so;libicu.so;libjnigraphics.so;liblog.so;libm.so;libmediandk.so;libnativehelper.so;libnativewindow.so;libneuralnetworks.so;libstdc++.so;libsync.so;libvulkan.so;libz.so")
|
||||
@@ -0,0 +1,124 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# /* ******************************************************************************
|
||||
# *
|
||||
# *
|
||||
# * This program and the accompanying materials are made available under the
|
||||
# * terms of the Apache License, Version 2.0 which is available at
|
||||
# * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
# *
|
||||
# * See the NOTICE file distributed with this work for additional
|
||||
# * information regarding copyright ownership.
|
||||
# * Unless required by applicable law or agreed to in writing, software
|
||||
# * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT
|
||||
# * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# * License for the specific language governing permissions and limitations
|
||||
# * under the License.
|
||||
# *
|
||||
# * SPDX-License-Identifier: Apache-2.0
|
||||
# ******************************************************************************/
|
||||
#
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
# Determine script location
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
# Find the project structure
|
||||
# First try to detect libnd4j directory
|
||||
if [[ "$SCRIPT_DIR" == */libnd4j* ]]; then
|
||||
# We're already in or under libnd4j directory
|
||||
LIBND4J_DIR=$(echo "$SCRIPT_DIR" | sed 's/\(.*libnd4j\).*/\1/')
|
||||
PROJECT_ROOT=$(dirname "$LIBND4J_DIR")
|
||||
else
|
||||
# Check if we're in the parent deeplearning4j directory
|
||||
if [ -d "$SCRIPT_DIR/libnd4j" ]; then
|
||||
LIBND4J_DIR="$SCRIPT_DIR/libnd4j"
|
||||
PROJECT_ROOT="$SCRIPT_DIR"
|
||||
else
|
||||
# Try going up one directory to see if libnd4j is there
|
||||
if [ -d "$SCRIPT_DIR/../libnd4j" ]; then
|
||||
LIBND4J_DIR="$SCRIPT_DIR/../libnd4j"
|
||||
PROJECT_ROOT=$(dirname "$SCRIPT_DIR")
|
||||
else
|
||||
echo "Error: Could not locate libnd4j directory"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set the absolute paths for source and target
|
||||
SOURCE_DIR="$LIBND4J_DIR/include/graph/generated/org/nd4j/graph"
|
||||
TARGET_DIR="$PROJECT_ROOT/nd4j/nd4j-backends/nd4j-api-parent/nd4j-api/src/main/java/org/nd4j/graph"
|
||||
|
||||
|
||||
echo "Script directory: $SCRIPT_DIR"
|
||||
echo "LibND4J directory: $LIBND4J_DIR"
|
||||
echo "Project root: $PROJECT_ROOT"
|
||||
echo "Source directory: $SOURCE_DIR"
|
||||
echo "Target directory: $TARGET_DIR"
|
||||
|
||||
# Check if source directory exists and has content
|
||||
if [ ! -d "$SOURCE_DIR" ]; then
|
||||
echo "Error: Source directory does not exist: $SOURCE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Create copyright header content
|
||||
COPYRIGHT="/*
|
||||
* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
"
|
||||
|
||||
# Ensure target directory exists
|
||||
mkdir -p "$TARGET_DIR"
|
||||
|
||||
# Check if any Java files exist in source directory
|
||||
if ! ls "$SOURCE_DIR"/*.java &> /dev/null; then
|
||||
echo "Error: No Java files found in source directory: $SOURCE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Process each Java file
|
||||
for file in "$SOURCE_DIR"/*.java; do
|
||||
if [ -f "$file" ]; then
|
||||
filename=$(basename "$file")
|
||||
target_file="$TARGET_DIR/$filename"
|
||||
echo "Processing: $filename"
|
||||
|
||||
# Create temp file
|
||||
temp_file=$(mktemp)
|
||||
# Add copyright header
|
||||
echo "$COPYRIGHT" > "$temp_file"
|
||||
# Add a newline
|
||||
echo "" >> "$temp_file"
|
||||
# Append the original file content
|
||||
cat "$file" >> "$temp_file"
|
||||
# Move to final destination
|
||||
cp "$temp_file" "$target_file"
|
||||
# Clean up temp file
|
||||
rm "$temp_file"
|
||||
|
||||
echo "Created: $target_file"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Java files copied to target location with copyright headers successfully"
|
||||
@@ -0,0 +1,233 @@
|
||||
There's multiple different Ops designs supported in libND4j, and in this guide we'll try to explain how to build your very own operation.
|
||||
|
||||
## XYZ operations
|
||||
|
||||
This kind of operations is actually split into multiple subtypes, based on element-access and result type:
|
||||
- Transform operations: These operations typically take some NDArray in, and change each element independent of others.
|
||||
- Reduction operations: These operations take some NDArray and dimensions, and return reduced NDArray (or scalar) back. I.e. sum along dimension(s).
|
||||
- Scalar operations: These operations are similar to transforms, but they only do arithmetic operations, and second operand is scalar. I.e. each element in given NDArray will add given scalar value.
|
||||
- Pairwise operations: These operations are between regular transform operations and scalar operations. I.e. element-wise addition of two NDArrays.
|
||||
- Random operations: Most of these operations related to random numbers distributions: Uniform, Gauss, Bernoulli etc.
|
||||
|
||||
Despite differences between these operations, they are all using XZ/XYZ three-operand design, where X and Y are inputs, and Z is output.
|
||||
Data access in these operations is usually trivial, and loop based. I.e. most trivial loop for scalar transform will look like this:
|
||||
```c++
|
||||
for (sd::LongType i = start; i < end; i++) {
|
||||
result[i] = OpType::op(x[i], scalar, extraParams);
|
||||
}
|
||||
```
|
||||
|
||||
Operation used in this loop will be template-driven, and compiled statically. There are another loops implementation, depending on op group or strides within NDArrays, but idea will be the same all the time: each element of the NDArray will be accessed within loop.
|
||||
|
||||
Now, let's take a look into typical XYZ op implementation. Here's how `Add` operation will look like:
|
||||
|
||||
```c++
|
||||
|
||||
template<typename T>
|
||||
class Add {
|
||||
public:
|
||||
SD_OP_DEF static T op(T d1, T d2) {
|
||||
return d1 + d2;
|
||||
}
|
||||
|
||||
// this signature will be used in Scalar loops
|
||||
SD_OP_DEF static T op(T d1, T d2, T *params) {
|
||||
return d1 + d2;
|
||||
}
|
||||
|
||||
// this signature will be used in reductions
|
||||
SD_OP_DEF static T op(T d1) {
|
||||
return d1;
|
||||
}
|
||||
|
||||
// op for MetaOps
|
||||
SD_OP_DEF static T op(T d1, T *params) {
|
||||
return d1 + params[0];
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
This particular operation is used in different XYZ op groups, but you see the idea: element-wise operation, which is invoked on each element in given NDArray.
|
||||
So, if you want to add new XYZ operation to libnd4j, you should just add operation implementation to file `includes/ops/ops.h`, and assign it to specific ops group in file `includes/loops/legacy_ops.h` together with some number unique to this ops group, i.e.: `(21, simdOps::Add)`
|
||||
|
||||
After libnd4j is recompiled, this op will become available for legacy execution mechanism, NDArray wrappers, and `LegacyOp` wrappers (those are made to map legacy operations to CustomOps design for Graph).
|
||||
|
||||
|
||||
## Custom operations
|
||||
|
||||
Custom operations is a new concept, added recently and mostly suits SameDiff/Graph needs.
|
||||
For CustomOps we defined universal signature, with variable number of input/output NDArrays, and variable number of floating-point and integer arguments.
|
||||
However, there are some minor differences between various CustomOp declarations:
|
||||
- **DECLARE_OP**(string, int, int, bool): these operations take no fp/int arguments, and output shape equals to input shape.
|
||||
- **DECLARE_CONFIGURABLE_OP**(string, int, int, bool, int, int): these operations do take fp/int output arguments, and output shape equals to input shape.
|
||||
- **DECLARE_REDUCTION_OP**(string, int, int, bool, int, int): these operations do take fp/int output arguments, and output shape is calculated as Reduction.
|
||||
- **DECLARE_CUSTOM_OP**(string, int, int, bool, int, int): these operations return NDArray with custom shape, that usually depends on input and arguments.
|
||||
- **DECLARE_BOOLEAN_OP**(string, int, bool): these operations take some NDArrays and return scalar, where 0 is **False**, and other values are treated as **True**.
|
||||
|
||||
Let's take a look at example CustomOp:
|
||||
|
||||
```c++
|
||||
|
||||
CUSTOM_OP_IMPL(tear, 1, -1, false, 0, -1) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
|
||||
REQUIRE_TRUE(!block.getIArguments()->empty(), 0, "At least 1 dimension should be specified for Tear");
|
||||
|
||||
std::vector<int> dims(*block.getIArguments());
|
||||
|
||||
for (auto &v: dims)
|
||||
REQUIRE_TRUE(v >= 0 && v < input->rankOf(), 0, "Tear dimensions should be non-negative values, and lower than input rank. Got %i instead", v);
|
||||
|
||||
auto tads = input->allTensorsAlongDimension(dims);
|
||||
for (int e = 0; e < tads->size(); e++) {
|
||||
auto outE = OUTPUT_VARIABLE(e);
|
||||
outE->assign(tads->at(e));
|
||||
|
||||
this->storeResult(block, e, *outE);
|
||||
}
|
||||
|
||||
delete tads;
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(tear) {
|
||||
auto inShape = inputShape->at(0);
|
||||
|
||||
std::vector<int> dims(*block.getIArguments());
|
||||
|
||||
if (dims.size() > 1)
|
||||
std::sort(dims.begin(), dims.end());
|
||||
|
||||
shape::TAD tad(inShape, dims.data(), (int) dims.size());
|
||||
tad.createTadOnlyShapeInfo();
|
||||
sd::LongType numTads = shape::tadLength(inShape, dims.data(), (int) dims.size());
|
||||
|
||||
auto result = SHAPELIST();
|
||||
for (int e = 0; e < numTads; e++) {
|
||||
result->push_back(tad.tadOnlyShapeInfo);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
In the example above, we declare `tear` CustomOp implementation, and shape function for this op.
|
||||
So, at the moment of op execution, we assume that we will either have output array(s) provided by end-user, or they will be generated with shape function.
|
||||
|
||||
You can also see number of macros used, we'll cover those later as well. Beyond that - op execution logic is fairly simple & linear:
|
||||
Each new op implements protected member function `DeclarableOp<T>::validateAndExecute(Block<T>& block)`, and this method is eventually called either from GraphExecutioner, or via direct call, like `DeclarableOp<T>::execute(Block<T>& block)`.
|
||||
|
||||
Important part of op declaration is input/output description for the op. I.e. as shown above: `CUSTOM_OP_IMPL(tear, 1, -1, false, 0, -1)`.
|
||||
This declaration means:
|
||||
- Op name: `tear`
|
||||
- Op expects at least 1 NDArray as input
|
||||
- Op returns unknown positive number of NDArrays as output
|
||||
- Op can't be run in-place, so under any circumstances original NDArray will stay intact
|
||||
- Op doesn't expect any T (aka floating point) arguments
|
||||
- Op expects unknown positive number of integer arguments. In case of this op it's dimensions to split input NDArray.
|
||||
|
||||
Here's another example: `DECLARE_CUSTOM_OP(permute, 1, 1, true, 0, -2);`
|
||||
This declaration means:
|
||||
- Op name: `permute`
|
||||
- Op expects at least 1 NDArray as input
|
||||
- Op returns 1 NDArray as output
|
||||
- Op can be run in-place if needed (it means: input == output, and input is modified and returned as output)
|
||||
- Op doesn't expect any T arguments
|
||||
- Op expects unknown number of integer arguments OR no integer arguments at all.
|
||||
|
||||
## c++11 syntactic sugar
|
||||
|
||||
In ops you can easily use c++11 features, including lambdas. In some cases it might be easiest way to build your custom op (or some part of it) via `NDArray::applyLambda` or `NDArray::applyPairwiseLambda`:
|
||||
```c++
|
||||
auto lambda = LAMBDA_TT(_x, _y) {
|
||||
return (_x + _y) * 2;
|
||||
};
|
||||
|
||||
x.applyPairwiseLambda(&y, lambda);
|
||||
```
|
||||
|
||||
In this simple example, each element of NDArray `x` will get values set to `x[e] = (x[e] + y[e]) * 2`.
|
||||
|
||||
## Tests
|
||||
|
||||
For tests libnd4j uses Google Tests suit. All tests are located at `tests_cpu/layers_tests` folder. Here's a simple way to run those from command line:
|
||||
```
|
||||
cd tests_cpu
|
||||
cmake -G "Unix Makefiles"
|
||||
make -j 4
|
||||
./layers_tests/runtests
|
||||
```
|
||||
|
||||
You can also use your IDE (i.e. Jetbrains CLion) to run tests via GUI.
|
||||
|
||||
**PLEASE NOTE:** if you're considering submitting your new op to libnd4j repository via pull request - consider adding tests for it. Ops without tests won't be approved.
|
||||
|
||||
## Backend-specific operation
|
||||
|
||||
GPU/MPI/whatever to be added soon.
|
||||
|
||||
|
||||
## Utility macros
|
||||
We have number of utility macros, suitable for custom ops. Here they are:
|
||||
- **INPUT_VARIABLE**(int): this macro returns you NDArray at specified input index.
|
||||
- **OUTPUT_VARIABLE**(int): this macro returns you NDArray at specified output index.
|
||||
- **STORE_RESULT**(NDArray<T>): this macro stores result to VariableSpace.
|
||||
- **STORE_2_RESULTS**(NDArray<T>, NDArray<T>): this macro stores results according to VariableSpace.
|
||||
- **INT_ARG**(int): this macro returns you specific Integer argument passed to the given op.
|
||||
- **T_ARG**(int): this macro returns you specific T argument passed to the given op.
|
||||
- **ALLOCATE**(...): this macro check if Workspace is available, and either uses Workspace or direct memory allocation if Workspace isn't available.
|
||||
- **RELEASE**(...): this macro is made to release memory allocated with **ALLOCATE()** macro.
|
||||
- **REQUIRE_TRUE**(...): this macro takes condition, and evaluates it. If evaluation doesn't end up as True - exception is raised, and specified message is printed out.
|
||||
- **LAMBDA_T**(X) and **LAMBDA_TT**(X, Y): lambda declaration for `NDArray::applyLambda` and `NDArray::applyPairwiseLambda`
|
||||
- **COPY_SHAPE**(SRC, TGT): this macro allocates memory for TGT pointer and copies shape from SRC pointer
|
||||
- **ILAMBDA_T**(X) and **ILAMBDA_TT**(X, Y): lambda declaration for indexed lambdas, index argument is passed in as sd::LongType (aka **long long**)
|
||||
- **SD_INLINE**: platform-specific definition for functions inlining
|
||||
|
||||
|
||||
#### Explicit template instantiations in helper methods.
|
||||
We should explicitly instantiate template methods for different data types in libraries. Furthermore, to speed up parallel compilation we need to add those template instantiations in separate source files. Besides, another reason is that: some compilers are choked when these template instantiations are many in one translation unit.
|
||||
To ease this cumbersome operation we have Cmake helper and macros helpers.
|
||||
Example:
|
||||
Suppose we have such function:
|
||||
|
||||
template<typename X, typename Z>
|
||||
void argMin_(const NDArray& input, NDArray& output, const std::vector<sd::LongType>& dimensions);
|
||||
|
||||
We should write this to explicitly instantiate it.
|
||||
|
||||
BUILD_DOUBLE_TEMPLATE(template void argMin_, (const NDArray& input, NDArray& output, const std::vector<sd::LongType>& dimensions),
|
||||
SD_COMMON_TYPES, SD_INDEXING_TYPES);
|
||||
|
||||
Here:
|
||||
- ***SD_COMMON_TYPES*** means we want to use all types in the place of X
|
||||
- ***SD_INDEXING_TYPES*** means we will use index types ( int, int64_t) as Z type
|
||||
|
||||
But to speed up compilation process and also helping compilers we can further separate it into different source files. Firstly we rename the original template source with ***hpp*** extension:
|
||||
Secondly we add file with the suffix ***cpp.in*** (or ***cu.in*** for cuda) that will include that hpp header and place it in the appropriate compilation units folder. in our case it will be in **./libnd4j/include/ops/declarable/helpers/cpu/compilation_units** folder with the name ***argmax.cpp.in*** .
|
||||
Later we decide which type we want to separate into different sources. In our case we want to split ***SD_COMMON_TYPES*** (other ones: ***SD_INTEGER_TYPES , SD_FLOAT_TYPES, SD_PAIRWISE_TYPES*** ). We hint cmake that case with this (adding ***_GEN*** suffix):
|
||||
|
||||
#cmakedefine SD_COMMON_TYPES_GEN
|
||||
|
||||
Then we just add ***_@FL_TYPE_INDEX@*** as suffix in type name and it will split those types for us and generate cpp files inside ${CMAKE_BINARY_DIR}/compilation_units folder.
|
||||
|
||||
LIBND4J_TYPE_@FL_TYPE_INDEX@
|
||||
|
||||
Here is how the complete cpp.in file will look like:
|
||||
|
||||
#cmakedefine SD_COMMON_TYPES_GEN
|
||||
//this header is where our template functions resides
|
||||
#include <ops/declarable/helpers/cpu/indexReductions.hpp>
|
||||
|
||||
//guard against undefined cases
|
||||
#if defined(SD_COMMON_TYPES_GEN) && defined(SD_COMMON_TYPES_@FL_TYPE_INDEX@)
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
namespace helpers {
|
||||
BUILD_DOUBLE_TEMPLATE(template void argMax_, (const NDArray& input, NDArray& output, const std::vector<sd::LongType>& dimensions),
|
||||
SD_COMMON_TYPES_@FL_TYPE_INDEX@, SD_INDEXING_TYPES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
# Debugging Practices with C++ Tests in libnd4j Library
|
||||
|
||||
In this document, we will walk through some general debugging practices while working with C++ tests in the libnd4j library. This involves the use of Google Test framework (gtest), building with debug flags, and employing memory checking tools like Valgrind.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Ensure that you have the following installed on your system:
|
||||
|
||||
- Google Test framework (gtest)
|
||||
- CMake (for building the project)
|
||||
- Valgrind (for memory leak checking)
|
||||
- A modern C++ compiler that supports C++11 or later
|
||||
|
||||
## Building with Debug Flags
|
||||
|
||||
In order to debug effectively, you will need to compile your project with debugging information. This can be accomplished by adding debug flags during the build process.
|
||||
|
||||
If you're using CMake, you can do this by setting the `CMAKE_BUILD_TYPE` variable to `Debug`. This can be done through the command line as follows:
|
||||
|
||||
```
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
```
|
||||
|
||||
When you're building your project with debug flags, the compiler will include extra information in the resulting executable that can be used to help find bugs.
|
||||
|
||||
## Debugging with Google Test (gtest)
|
||||
|
||||
Google Test is a powerful framework for writing C++ tests. It provides a simple and flexible way to write reliable tests, including features like test suites and assertions that make it easy to structure your tests and verify your code.
|
||||
|
||||
You can run a specific test using the `--gtest_filter` flag. The value passed to `--gtest_filter` is a colon-separated list of wildcard patterns (they may include `*` as a wildcard). Only the tests whose full names match one of the patterns will be executed.
|
||||
|
||||
For example, to run the `BasicTest_Scatter_1` test of the `ListOperationsTests` test case, you can use:
|
||||
|
||||
```
|
||||
./blasbuild/cpu/tests_cpu/layers_tests/runtests --gtest_filter=ListOperationsTests.BasicTest_Scatter_1
|
||||
```
|
||||
|
||||
## Debugging with Valgrind
|
||||
|
||||
Valgrind is an open-source tool that can be used for memory debugging, memory leak detection, and profiling. If your program is crashing or behaving unexpectedly, Valgrind can help identify memory leaks, uninitialized memory, and other related problems.
|
||||
|
||||
To run your tests under Valgrind, use the following command:
|
||||
|
||||
```
|
||||
valgrind --track-origins=yes -v ./blasbuild/cpu/tests_cpu/layers_tests/runtests --gtest_filter=ListOperationsTests.BasicTest_Scatter_1
|
||||
```
|
||||
|
||||
Here's what the flags do:
|
||||
|
||||
- `--track-origins=yes`: This tells Valgrind to track the origin of uninitialized values. This can be useful for finding the source of uninitialized value errors.
|
||||
- `-v`: This increases the verbosity of Valgrind's output, giving you more information about what's happening.
|
||||
- `--gtest_filter=ListOperationsTests.BasicTest_Scatter_1`: This is telling gtest to run only the `BasicTest_Scatter_1` test from the `ListOperationsTests` test suite.
|
||||
|
||||
## Conclusion
|
||||
|
||||
This should give you a solid foundation for debugging C++ tests in the libnd4j library. Remember, the key to effective debugging is to take a systematic approach, carefully observing the behavior of your program and making hypotheses about what could be causing any issues.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Deeplearning4j: Enhanced Stack Trace Feature Overview
|
||||
|
||||
## Introduction
|
||||
|
||||
For developers who are knee-deep in troubleshooting, understanding where a problem originated can be invaluable. In line with that, Deeplearning4j now introduces an advanced feature that provides an insightful fusion of Java and C++ stack traces. This is especially useful when debugging issues related to memory allocation and deallocation.
|
||||
|
||||
## Feature: SD_GCC_FUNCTRACE
|
||||
|
||||
When you build Deeplearning4j with the `SD_GCC_FUNCTRACE` option turned on, it activates the ability to display C++ stack traces. This powerful feature, however, comes with a caveat: it requires numerous platform-specific dependencies to function seamlessly.
|
||||
|
||||
### What's New?
|
||||
|
||||
When the aforementioned feature is active, developers can now enable a fresh capability that showcases both Java and C++ stack traces at every instance of memory allocation and deallocation in the Deeplearning4j codebase.
|
||||
|
||||
Here's the crux of this new feature:
|
||||
|
||||
1. **Allocation and Deallocation Triggers**: The stack traces will be printed just as a buffer is about to be deallocated.
|
||||
2. **Crash Insights**: Typically, the last deallocation that took place will pinpoint the site of the crash.
|
||||
3. **Full Problem Context**: By analyzing Java and C++ stack traces side by side, developers can derive a comprehensive understanding of the issue at hand.
|
||||
4. **Enhancement Over Sanitizers**: This feature is a supplement to sanitizers, which occasionally falter in showing internal stack traces instead of the real underlying problem.
|
||||
|
||||
## Enabling the Feature
|
||||
|
||||
Activating this feature is straightforward. Here's a snippet to do just that:
|
||||
|
||||
```java
|
||||
Nd4j.getEnvironment().setFuncTraceForAllocate(true);
|
||||
Nd4j.getEnvironment().setFuncTraceForDeallocate(true);
|
||||
```
|
||||
|
||||
With these lines of code:
|
||||
|
||||
- The first line will enable the printing of stack traces during memory allocation.
|
||||
- The second line will do the same for deallocation.
|
||||
|
||||
## Conclusion
|
||||
|
||||
By leveraging this new feature, developers can achieve a granular understanding of memory-related issues in Deeplearning4j's operations. This comprehensive insight into both Java and C++ realms will significantly streamline the debugging process and enhance code reliability.
|
||||
|
||||
_Remember, while powerful, this feature can also be verbose. Hence, it's recommended to use it judiciously, primarily when deep troubleshooting is necessary._
|
||||
@@ -0,0 +1,172 @@
|
||||
## Helpers
|
||||
|
||||
### Requirements Helper
|
||||
|
||||
Requirements helper was introduced to replace plain checks for making them output informative messages (Debug and Verbose mode) and also replace macros REQUIRE_TRUE.
|
||||
|
||||
- it will lazily evaluate values and messages if the type wrapped and has` getValue` and `getMsg` methods
|
||||
- it is implicit bool. this makes it usable with logical operators and also inside if conditions. Besides it will benefit from shortcircuit nature of those operators.
|
||||
- it has the following check methods
|
||||
```cpp
|
||||
Requirements& expect(const T& expVar,const T1& reqVar, Op comparison, const char *first_half="")
|
||||
Requirements& expectEq(const T& exp,const T1& req)
|
||||
Requirements& expectNotEq(const T& exp,const T1& req)
|
||||
Requirements& expectLess(const T& exp,const T1& req)
|
||||
Requirements& expectLessEq(const T& exp,const T1& req)
|
||||
Requirements& expectGreater(T exp, T1 req)
|
||||
Requirements& expectGreaterEq(const T& exp,const T1& req
|
||||
Requirements& expectTrue(const T& expVar, const char *msg=)
|
||||
Requirements& expectFalse(const T& expVar, const char *msg=)
|
||||
```
|
||||
- you can either log the success case or throw error on the failure
|
||||
- it can use plain types for checks.
|
||||
- if value has stream operator it will be used to output its value. for custom types you may need add that by yourself
|
||||
`ostream& operator<<(ostream& os, const CustomUserType& dt)`
|
||||
- there is generic template `InfoVariable` wrapper for types to make it informative. you can use lambda operators with them as well to make it lazily evaluated
|
||||
- we added custom `ShapeInfoVariable` wrapper for the NDArray and vector<> shapes to make them informative
|
||||
- one can use `expect` to add its own proper comparison. simple lambda for that will be like this:
|
||||
```cpp
|
||||
[](const decltype(expType)& l, const decltype(reqType)& r){
|
||||
//compare and return
|
||||
return ....;
|
||||
}
|
||||
```
|
||||
|
||||
#### Examples:
|
||||
|
||||
firstly, we should enable logging
|
||||
```cpp
|
||||
sd::Environment::getInstance().setDebug(true);
|
||||
sd::Environment::getInstance().setVerbose(true);
|
||||
```
|
||||
|
||||
1. simple case
|
||||
|
||||
```cpp
|
||||
Requirements req1("Requirement Helper Example#1");
|
||||
int x = 20;
|
||||
req1.expectLess(x, 22);
|
||||
req1.expectEq(x, 21); //should fail
|
||||
```
|
||||
|
||||
|
||||
Output:
|
||||
``` Requirement Helper Example#1: {20} expected to be equal to 21```
|
||||
|
||||
2. using InfoVariable wrapper
|
||||
```cpp
|
||||
int age = 15;
|
||||
Requirements req2("Requirement Helper Example#2");
|
||||
req2.expectGreaterEq(makeInfoVariable(age, "the user's age"), 18);
|
||||
```
|
||||
Output:
|
||||
```
|
||||
Requirement Helper Example#2: the user's age {15} expected to be greater than or equal 18
|
||||
```
|
||||
|
||||
3. helper behavior while using many checks in one block
|
||||
```cpp
|
||||
int getAge(){
|
||||
std::cout<<"getAge() was called"<<std::endl;
|
||||
return 15;
|
||||
}
|
||||
....
|
||||
Requirements req3("Requirement Helper Example#3");
|
||||
int z = 20;
|
||||
req3.expectEq(z, 21);
|
||||
req3.expectGreaterEq(makeInfoVariable(getAge(), "the user's age"), 18);
|
||||
```
|
||||
Output:
|
||||
```
|
||||
Requirement Helper Example#3: {20} expected to be equal to 21
|
||||
getAge() was called
|
||||
```
|
||||
|
||||
As it is seen the second check did not happen as the previous failed. But still ```getAge()``` method was called as its function argument.
|
||||
|
||||
4. using **shortcircuit** to avoid Requirement call at all if the previous one was failed
|
||||
```cpp
|
||||
Requirements req4("Requirement Helper Example#4");
|
||||
int zz = 20;
|
||||
req4.expectEq(zz, 21) && //shortcircuit And
|
||||
req4.expectGreaterEq(makeInfoVariable(getAge(), "the user's age"), 18);
|
||||
```
|
||||
Output:
|
||||
```
|
||||
Requirement Helper Example#4: {20} expected to be equal to 21
|
||||
```
|
||||
5. using lambdas with InfoVariable. it will make it lazily evaluated
|
||||
```cpp
|
||||
Requirements req5("Requirement Helper Example#5");
|
||||
req5.expectEq( 21,
|
||||
makeInfoVariable(21, []{
|
||||
std::cout<<"lambda call#1"<<std::endl;
|
||||
return "twenty one";
|
||||
}));
|
||||
req5.expectEq(makeInfoVariable([]{ return 20;}, []{return "twenty";}),
|
||||
makeInfoVariable(21, []{
|
||||
std::cout<<"lambda call#2"<<std::endl;
|
||||
return "twenty one";
|
||||
}));
|
||||
req5.expectGreaterEq(makeInfoVariable([]{
|
||||
std::cout<<"lambda call#3" <<std::endl;
|
||||
return 15;
|
||||
},
|
||||
[]{ return "the user's age";}),
|
||||
makeInfoVariable([]{return 18;}, []{return "the allowed age";})
|
||||
);
|
||||
```
|
||||
Output:
|
||||
```
|
||||
lambda call#2
|
||||
Requirement Helper Example#5: twenty {20} expected to be equal to twenty one 21
|
||||
|
||||
```
|
||||
|
||||
6. use bool nature and also log the success case
|
||||
```cpp
|
||||
Requirements req6("Requirement Helper Example#6");
|
||||
NDArray * arr= nullptr;
|
||||
arr !=nullptr && req6.expectEq(arr->rankOf(), 3) ;
|
||||
req6.logTheSuccess();
|
||||
```
|
||||
Output:
|
||||
```
|
||||
Requirement Helper Example#6: meets the requirements
|
||||
```
|
||||
|
||||
7. custom comparision lambda and also another usage of the custom wrapper written by us ```ShapeInfoVariable```. Note: we will use ```std::vector<int>```. this wrapper can be used with ```NDArray``` as well.
|
||||
```cpp
|
||||
Requirements req7("Requirement Helper Example#7");
|
||||
req7.expect(makeShapeInfoVariable(std::vector<sd::LongType>{2,3,4,5}, SHAPE_MSG_INPUT0), makeShapeInfoVariable(std::vector<sd::LongType>{2,3,4,7}, SHAPE_MSG_INPUT1),
|
||||
[](const std::vector<sd::LongType>& l, const std::vector<sd::LongType>& r){
|
||||
return l == r;
|
||||
}
|
||||
, EXPECTED_EQ_MSG);
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
```
|
||||
Requirement Helper Example#7: the Shape of the Input NDArray#0 {[2, 3, 4, 5]} expected to be equal to the Shape of the Input NDArray#1 [2, 3, 4, 7]
|
||||
```
|
||||
|
||||
8. throw error when there is failure
|
||||
```cpp
|
||||
Requirements req8("Requirement Helper Example#8");
|
||||
req8.expectEq(6,6) &&
|
||||
req8.expectIn(6, {1,2,3,7,8,9});
|
||||
req8.throws();
|
||||
```
|
||||
Output:
|
||||
```
|
||||
terminate called after throwing an instance of 'std::invalid_argument'
|
||||
what(): Op validation failed
|
||||
...
|
||||
Requirement Helper Example#8: {6} expected to be one of these {[1, 2, 3, 7, 8, 9, ]}
|
||||
```
|
||||
|
||||
|
||||
##### Here is live example:
|
||||
**Note:** some classes were mocked there and do not represent the exact implementations in libnd4j.
|
||||
https://godbolt.org/z/sq98vchs5
|
||||
@@ -0,0 +1,32 @@
|
||||
# libnd4j CUDA Kernel Launch Configuration
|
||||
|
||||
This part of the libnd4j codebase provides a centralized way to handle CUDA launch configurations. It allows customization of launch dimensions using environment variables.
|
||||
|
||||
## Conceptual Overview
|
||||
|
||||
The code sets up CUDA launch configurations for a wide range of algorithms used in the libnd4j codebase. These configurations are expressed as `dim3` structures, representing grid and block dimensions for launching CUDA kernels. The configurations are stored in a map, improving performance via a caching mechanism.
|
||||
|
||||
### Key Feature
|
||||
|
||||
A significant feature of this code is the flexibility it offers, allowing users to specify custom launch dimensions through environment variables. This enables modifications of these configurations at both compile-time and runtime.
|
||||
|
||||
## Examples of Usage
|
||||
|
||||
```cpp
|
||||
// Fetching Launch Dimensions
|
||||
dim3 launchDims = getLaunchDims("matrixMultiply");
|
||||
//invoke your cuda function
|
||||
yourKernel<<<launchDims.y,launchDims.x,launchDims.z>>>
|
||||
//This returns the blocks, threads and shared memory used for the kernel.
|
||||
```
|
||||
|
||||
|
||||
The launch configuration can be found in
|
||||
```bash
|
||||
../include/execution/cuda/LaunchDims.h
|
||||
../include/execution/cuda/LaunchDims.cu
|
||||
```
|
||||
|
||||
Every kernel has environment variables that work at build time and runtime.
|
||||
Build time is used to modify defaults. Runtime is used to override buildtime and defaults.
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
Please follow following instructions to build nd4j for raspberry PI:
|
||||
|
||||
1. download cross compilation tools for Raspberry PI
|
||||
|
||||
```
|
||||
$ apt-get/yum install git cmake
|
||||
(You may substitute any path you prefer instead of $HOME/raspberrypi in the following two steps)
|
||||
$ mkdir $HOME/raspberrypi
|
||||
$ export RPI_HOME=$HOME/raspberrypi
|
||||
$ cd $RPI_HOME
|
||||
$ git clone git://github.com/raspberrypi/tools.git
|
||||
$ export PATH=$PATH:$RPI_HOME/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin
|
||||
```
|
||||
|
||||
2. download deeplearning4j:
|
||||
|
||||
```
|
||||
$ cd $HOME
|
||||
$ git clone https://github.com/eclipse/deeplearning4j.git
|
||||
```
|
||||
|
||||
3. build libnd4j:
|
||||
|
||||
```
|
||||
$ cd deeplearning4j/libnd4j
|
||||
$ ./buildnativeoperations.sh -o linux-armhf
|
||||
```
|
||||
|
||||
4. build nd4j
|
||||
|
||||
```
|
||||
$ export LIBND4J_HOME=<pathTond4JNI>
|
||||
$ cd $HOME/deeplearning4j/nd4j
|
||||
$ mvn clean install -Djavacpp.platform=linux-armhf -Djavacpp.platform.compiler=$HOME/raspberrypi/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ -DskipTests -Dmaven.javadoc.skip=true -pl '!:nd4j-cuda-9.1,!:nd4j-cuda-9.1-platform,!:nd4j-tests'
|
||||
```
|
||||
@@ -0,0 +1,12 @@
|
||||
Due to the macros and sheer number of type combinations we often run in to undefined symbols when linking.
|
||||
|
||||
We typically use this command on linux to find issues:
|
||||
nm -uC libnd4j/blasbuild/cpu/blas/libnd4jcpu.so
|
||||
|
||||
or cuda:
|
||||
nm -uC libnd4j/blasbuild/cuda/blas/libnd4jcuda.so
|
||||
|
||||
|
||||
You can also do the same for *just* undefined:
|
||||
nm -C --undefined-only libnd4jcpu.so
|
||||
nm -C --undefined-only libnd4jcuda.so
|
||||
@@ -0,0 +1,145 @@
|
||||
# Graph
|
||||
|
||||
### Basic idea
|
||||
libnd4j contains Directed Acyclic Graph execution engine, suited for both local and remote execution. However, main goal here is execution of externally originated graphs, serialized into FlatBuffers and provided either via pointer, or file.
|
||||
|
||||
|
||||
This basic example shows execution of graph loaded from file:
|
||||
```c++
|
||||
auto graph = GraphExecutioner<float>::importFromFlatBuffers("./some_file.fb");
|
||||
GraphExecutioner<float>::execute(graph);
|
||||
// ... do something with results ...
|
||||
delete graph;
|
||||
```
|
||||
|
||||
### FlatBuffers schemas
|
||||
You can find scheme files [here](https://github.com/eclipse/deeplearning4j/tree/master/libnd4j/include/graph/scheme).
|
||||
|
||||
At this moment libnd4j repo contains compiled definitions for C++, Python, Java, and JSON, but FlatBuffers can be compiled for PHP, C#, JavaScript, TypeScript and Go as well. Please refer to `flatc` instructions to do that.
|
||||
|
||||
Such bindings allow you to build FlatBuffers files/buffers suitable for remote execution of your graph and obtaining results back. I.e. you can use JavaScript to build graph (or just update variables/placeholders), send them to remote RPC server powered by libnd4j, and get results back.
|
||||
|
||||
Use flatc-generate.sh to generate the relevant source files if you need to change anything related to flatbuffers such
|
||||
as the samediff file format or the UI.
|
||||
|
||||
### Graph execution logic
|
||||
No matter how graph is represented on the front-end, on backend it's rather simple: topologically sorted list of operations executed sequentially if there's shared dependencies, or (optionally) in parallel, if there's no shared dependencies for current graph nodes.
|
||||
|
||||
Each node in the graph represents single linear algebra operation applied to input(s) of the node. For example: `z = Add(x, y)` is operation that takes 2 NDArrays as input, and produes 1 NDArray as output. So, graph is built of such primitive operations, which are executed sequentially.
|
||||
|
||||
### Memory management within graph
|
||||
Everything that happens within graph during execution, stays within VariableSpace. It acts as storage for Variables and NDArrays produced during graph execution. On top of that, there's an option to use pre-allocated Workspaces for allocation of NDArrays.
|
||||
|
||||
|
||||
### Current graph limitations
|
||||
There are some limitations. Some of them will be lifted eventually, others won't be. Here's the list:
|
||||
- Graph has single data type. I.e. Graph<float> or Graph<float16> or Graph<double> _This limitation will be lifted soon._
|
||||
- On some platforms, like Java, single Variable/Placeholder size is limited to 2GB buffer size. However, on libnd4j side there's no such limitation.
|
||||
- Variable size/dimensionality has limitations: max NDArray rank is limited to 32 at this moment, and any single dimension is limited to SD_MAX_INT size.
|
||||
- Recursion isn't directly supported at this moment.
|
||||
- CUDA isn't supported at this moment. _This limitation will be lifted soon._
|
||||
- When used from C++, Graph only supports FeedForward mode. _This limitation will be lifted soon._
|
||||
|
||||
|
||||
### Documentation
|
||||
Documentation for individual operations, and basic classes (like NDArray, Graph etc) is available as part of Nd4j javadoc: https://javadoc.io/doc/org.nd4j/nd4j-api/latest/index.html
|
||||
|
||||
### Embedded profiling
|
||||
If you're adding new ops, and want to make sure they run ok on your specific device - you might want to give a shot to embedded Graph profiling helper.
|
||||
Despite being simple - it still provides you with time spent in various parts of Graph.
|
||||
|
||||
```c++
|
||||
Environment::getInstance().setProfiling(true);
|
||||
auto graph = GraphExecutioner::importFromFlatBuffers("./resources/ae_00.fb");
|
||||
|
||||
auto profile = GraphProfilingHelper::profile(graph, 1000);
|
||||
profile->printOut();
|
||||
|
||||
delete graph;
|
||||
```
|
||||
|
||||
1000 iterations laterm you'll get statistics printed out. Statistics basically includes time spent in various parts of code and memory allocation details.
|
||||
|
||||
Here's how it'll look like:
|
||||
```
|
||||
Printing out Graph...
|
||||
8. matmul; Inputs: [{1:0}, {2:0}];
|
||||
9. biasadd; Inputs: [{8:0}, {3:0}];
|
||||
10. TRANSFORM:{15}; Inputs: [{9:0}];
|
||||
11. rank; Inputs: [{2:0}];
|
||||
12. subtract; Inputs: [{11:0}, {4:0}];
|
||||
13. range; Inputs: [{5:0}, {11:0}, {6:0}];
|
||||
14. subtract; Inputs: [{12:0}, {13:0}];
|
||||
15. transpose; Inputs: [{2:0}, {14:0}];
|
||||
16. matmul; Inputs: [{10:0}, {15:0}];
|
||||
17. biasadd; Inputs: [{16:0}, {7:0}];
|
||||
18. TRANSFORM:{15}; Inputs: [{17:0}];
|
||||
|
||||
Printing out Scopes...
|
||||
Graph profile: 1000 executions
|
||||
|
||||
Memory:
|
||||
ACT: 0; TMP: 0; OBJ: 0; TTL: 1788;
|
||||
|
||||
Time:
|
||||
Construction time: 2135 ns;
|
||||
Execution time: 41820 ns;
|
||||
|
||||
Per-node reports:
|
||||
Node: <8:MatMul>
|
||||
Memory: ACT: 0; TMP: 0; OBJ: 0; TTL: 200;
|
||||
Time: PREP: 1160 ns; EXEC: 3167 ns; TTL: 5929 ns;
|
||||
PREP: INPUT: 251 ns; SHAPE: 382 ns; ARRAY: 217 ns;
|
||||
Node: <9:BiasAdd>
|
||||
Memory: ACT: 0; TMP: 0; OBJ: 0; TTL: 104;
|
||||
Time: PREP: 917 ns; EXEC: 3580 ns; TTL: 5957 ns;
|
||||
PREP: INPUT: 220 ns; SHAPE: 213 ns; ARRAY: 217 ns;
|
||||
Node: <10:Tanh>
|
||||
Memory: ACT: 0; TMP: 0; OBJ: 0; TTL: 104;
|
||||
Time: PREP: 756 ns; EXEC: 241 ns; TTL: 1927 ns;
|
||||
PREP: INPUT: 140 ns; SHAPE: 195 ns; ARRAY: 205 ns;
|
||||
Node: <11:transpose/Rank>
|
||||
Memory: ACT: 0; TMP: 0; OBJ: 0; TTL: 36;
|
||||
Time: PREP: 522 ns; EXEC: 119 ns; TTL: 1403 ns;
|
||||
PREP: INPUT: 109 ns; SHAPE: 69 ns; ARRAY: 171 ns;
|
||||
Node: <12:transpose/sub>
|
||||
Memory: ACT: 0; TMP: 0; OBJ: 0; TTL: 36;
|
||||
Time: PREP: 666 ns; EXEC: 185 ns; TTL: 1684 ns;
|
||||
PREP: INPUT: 192 ns; SHAPE: 94 ns; ARRAY: 168 ns;
|
||||
Node: <13:transpose/Range>
|
||||
Memory: ACT: 0; TMP: 0; OBJ: 0; TTL: 556;
|
||||
Time: PREP: 808 ns; EXEC: 647 ns; TTL: 2416 ns;
|
||||
PREP: INPUT: 297 ns; SHAPE: 228 ns; ARRAY: 181 ns;
|
||||
Node: <14:transpose/sub_1>
|
||||
Memory: ACT: 0; TMP: 0; OBJ: 0; TTL: 56;
|
||||
Time: PREP: 721 ns; EXEC: 541 ns; TTL: 2205 ns;
|
||||
PREP: INPUT: 23 ns; SHAPE: 92 ns; ARRAY: 165 ns;
|
||||
Node: <15:transpose>
|
||||
Memory: ACT: 0; TMP: 0; OBJ: 0; TTL: 96;
|
||||
Time: PREP: 3936 ns; EXEC: 602 ns; TTL: 5811 ns;
|
||||
PREP: INPUT: 194 ns; SHAPE: 3241 ns; ARRAY: 257 ns;
|
||||
Node: <16:MatMul_1>
|
||||
Memory: ACT: 0; TMP: 0; OBJ: 0; TTL: 312;
|
||||
Time: PREP: 970 ns; EXEC: 3565 ns; TTL: 6066 ns;
|
||||
PREP: INPUT: 203 ns; SHAPE: 320 ns; ARRAY: 193 ns;
|
||||
Node: <17:BiasAdd_1>
|
||||
Memory: ACT: 0; TMP: 0; OBJ: 0; TTL: 144;
|
||||
Time: PREP: 914 ns; EXEC: 3528 ns; TTL: 5870 ns;
|
||||
PREP: INPUT: 231 ns; SHAPE: 191 ns; ARRAY: 223 ns;
|
||||
Node: <18:output>
|
||||
Memory: ACT: 0; TMP: 0; OBJ: 0; TTL: 144;
|
||||
Time: PREP: 805 ns; EXEC: 285 ns; TTL: 1928 ns;
|
||||
PREP: INPUT: 157 ns; SHAPE: 192 ns; ARRAY: 232 ns;
|
||||
|
||||
Special timers:
|
||||
No special timers were set
|
||||
```
|
||||
|
||||
|
||||
### Roadmap
|
||||
In short-to-medium term following improvements are expected:
|
||||
- CUDA support for all new ops
|
||||
- Additional data types support: int, long long, q types, bool
|
||||
- Sparse tensors support
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
### Note to iOS build
|
||||
|
||||
I used LLVM 4.0 to build `ios-arm`, `ios-x86`, and `ios-x86_64`. LLVM clang seems to have a bug in recognizing arm64, I used Xcode 9.0 to build `ios-arm64` without `-fopenmp`.
|
||||
This is for build only, though. Since I have not built nd4j yet, it is to be decided later if MLPMnistSingleLayerExample and MLPMnistTwoLayerExample will run on iOS.
|
||||
@@ -0,0 +1,82 @@
|
||||
# Build DL4J for Linux on Power
|
||||
|
||||
This document explains how to build DL4J for Linux on Power
|
||||
|
||||
## Check pre-requirements
|
||||
|
||||
The following tools are necessary to build DL4J for Linux on Power
|
||||
|
||||
1. gcc version 4.9.X (older or newer version may cause build errors.)
|
||||
Check the version by "gcc --version", and install it from https://gcc.gnu.org/ if necessary.
|
||||
Look at Apppendix of this document to install gcc 4.9.
|
||||
|
||||
2. OpenJDK java 1.8
|
||||
Check the version is OpenJDK and 1.8 by "java -version".
|
||||
|
||||
3. Apache Maven 3.3 or later
|
||||
Check the version by "mvn -v", and install it from https://maven.apache.org/ if necessary.
|
||||
|
||||
4. CUDA7.5 (CUDA7.0 is not supported)
|
||||
Check the version by "nvcc -V"
|
||||
|
||||
5. cmake version 3.5.0 or later
|
||||
|
||||
## Set Environment Variables
|
||||
|
||||
Edit the CUDA, JAVA_HOME, CC, CXX environment variables according to your system
|
||||
|
||||
```
|
||||
export CUDA=/usr/local/cuda-7.5 # CUDA Directory
|
||||
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-ppc64el # JAVA Directory
|
||||
export CC=/path/to/gcc # gcc command for build
|
||||
export CXX=/path/to/g++ # g++ command for build
|
||||
export MAVEN_OPTS='-Xmx4096M -Dos.arch=ppc64le'
|
||||
export _JAVA_OPTIONS=-Dos.arch=ppc64le
|
||||
export LIBND4J_HOME=`/bin/pwd`/libnd4j
|
||||
export CUDA_VISIBLE_DEVICES=0
|
||||
```
|
||||
|
||||
## Clone and build DL4J, and execute a sample program
|
||||
|
||||
1. Clone necessary modules from github as follows.
|
||||
```
|
||||
git clone https://github.com/eclipse/deeplearning4j.git
|
||||
```
|
||||
|
||||
2. Modify the setting file to enable GPU. (Skip this step if you do not use GPU)
|
||||
Modify the following line in dl4j-0.4-examples/pom.xml as follows.
|
||||
```
|
||||
Before: <nd4j.backend>nd4j-native</nd4j.backend>
|
||||
After: <nd4j.backend>nd4j-cuda-7.5</nd4j.backend>
|
||||
```
|
||||
|
||||
3. Build modules as follows. (Make sure you follow the instructions in order.)
|
||||
```
|
||||
(cd javacpp/; mvn clean install -DskipTests)
|
||||
(cd libnd4j; ./buildnativeoperations.sh)
|
||||
(cd libnd4j; ./buildnativeoperations.sh -c cuda)
|
||||
(cd nd4j; mvn -e clean install -DskipTests -DskipTests -Djavacpp.platform.dependency=false -Dmaven.javadoc.skip=true)
|
||||
(cd Canova/; mvn clean install -DskipTests -Djavacpp.platform.dependency=false)
|
||||
(cd deeplearning4j; mvn clean package -DskipTests -Djavacpp.platform.dependency=false)
|
||||
(cd dl4j-0.4-examples; mvn clean package -DskipTests)
|
||||
```
|
||||
|
||||
4. Test the module by running the LenetMnist example
|
||||
```
|
||||
(cd dl4j-0.4-examples; java -cp target/deeplearning4j-examples-0.4-rc0-SNAPSHOT-bin.jar org.deeplearning4j.examples.convolution.LenetMnistExample)
|
||||
```
|
||||
|
||||
## Appendix
|
||||
|
||||
How to build gcc 4.9.3 on Linux on Power
|
||||
|
||||
```
|
||||
$ tar xvfz gcc-4.9.3.tar.gz
|
||||
$ cd gcc-4.9.3
|
||||
$ mkdir -p build
|
||||
$ (cd build; ../configure --enable-languages=c,c++ --prefix=<install path> --disable-bootstrap --disable-multilib)
|
||||
$ (cd build; make)
|
||||
$ (cd build; make install)
|
||||
# You need to add <install path>/lib64 in LD_LIBRRY_PATH
|
||||
# BLAS need to be specified in LD_LIBRARY_PATH to run CPU(native) version
|
||||
```
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
|
||||
## Overview
|
||||
|
||||
The nd4j and libnd4j code base can be difficult to debug due to the lack of tools for tracing program execution. We have implemented function tracing using the `-finstrument-functions` flag provided by GCC to trace function calls and exits in the code base. This feature will help developers better understand the flow of the program and identify potential issues.
|
||||
|
||||
## How to Enable Function Tracing
|
||||
|
||||
To enable function tracing, follow these steps:
|
||||
|
||||
1. Build the code base with `-Dlibnd4j.functrace=ON`.
|
||||
2. Add the correct compiler flags to the javacpp plugin.
|
||||
3. Add the correct flags to the cmake build.
|
||||
4. Add a maven profile to each nd4j backend containing the correct compiler flags to work with `-finstrument-functions`.
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Compiler Flags
|
||||
|
||||
We have used the following compiler flags to enable function tracing:
|
||||
|
||||
- `-Bsymbolic`: Bind references to global symbols at link time, reducing the runtime overhead.
|
||||
- `-rdynamic`: Export all dynamic symbols to the dynamic symbol table, making them available for backtracing.
|
||||
- `-fno-omit-frame-pointer`: Do not omit the frame pointer, allowing for accurate backtraces.
|
||||
- `-fno-optimize-sibling-calls`: Disable sibling call optimization to maintain the correct call stack.
|
||||
- `-finstrument-functions`: Enable instrumentation of function entry and exit points.
|
||||
- `-g`: Enable debugging information.
|
||||
- `-O0`: Set the optimization level to zero for easier debugging.
|
||||
|
||||
### Setting the Output File
|
||||
|
||||
We have implemented a method in each backend to set the output file for tracing results. For example, in the Nd4jCpu class:
|
||||
|
||||
```java
|
||||
Nd4jCpu nd4jCpu = (Nd4jCpu) NativeOpsHolder.getInstance().getDeviceNativeOps();
|
||||
nd4jCpu.setInstrumentOut("profilerout.txt");
|
||||
```
|
||||
|
||||
This calls a C++ method that sets the appropriate file to use. Each backend will have this call. Note that we don't put this in NativeOps (the parent backend agnostic interface for this) because this normally should not be included in any builds due to overhead.
|
||||
|
||||
### LD_PRELOAD and LD_DEBUG
|
||||
|
||||
To ensure the correct implementation of the enter/exit functions is used, `LD_PRELOAD` is utilized to preload the libnd4j binary generated during the build. The built-in libc implementation of these functions is a no-op, so preloading the libnd4j binary is necessary.
|
||||
|
||||
`LD_DEBUG` can be used to verify that the correct implementation is being used by showing the symbols being loaded and their origin.
|
||||
|
||||
## Sample Log Output
|
||||
|
||||
```
|
||||
g long> > >::end() (/home/agibsonccc/Documents/GitHub/deeplearning4j/libnd4j/blasbuild/cpu/blas/libnd4jcpu.so)
|
||||
enter std::operator==(std::_Rb_tree_iterator<std::pair<int const, long long> > const&, std::_Rb_tree_iterator<std::pair<int const, long long> > const&) (/home/agibsonccc/Documents/GitHub/deeplearning4j/libnd4j/blasbuild/cpu/blas/libnd4jcpu.so)
|
||||
exit std::operator==(std::_Rb_tree_iterator<std::pair<int const, long long> > const&, std::_Rb_tree_iterator<std::pair<int const, long long> > const&) (/home/agibsonccc/Documents/GitHub/deeplearning4j/libnd4j/blasbuild/cpu/blas/libnd4
|
||||
@@ -0,0 +1,234 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# /* ******************************************************************************
|
||||
# *
|
||||
# *
|
||||
# * This program and the accompanying materials are made available under the
|
||||
# * terms of the Apache License, Version 2.0 which is available at
|
||||
# * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
# *
|
||||
# * See the NOTICE file distributed with this work for additional
|
||||
# * information regarding copyright ownership.
|
||||
# * Unless required by applicable law or agreed to in writing, software
|
||||
# * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# * License for the specific language governing permissions and limitations
|
||||
# * under the License.
|
||||
# *
|
||||
# * SPDX-License-Identifier: Apache-2.0
|
||||
# ******************************************************************************/
|
||||
#
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
# Enable more verbose error reporting
|
||||
set -o pipefail
|
||||
|
||||
if [ -z "$FLATC_PATH" ]; then
|
||||
echo "❌ FLATC_PATH not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔧 Using flatc compiler from: $FLATC_PATH"
|
||||
if [ ! -f "$FLATC_PATH" ]; then
|
||||
echo "❌ Error: flatc not found at $FLATC_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$FLATC_PATH" ]; then
|
||||
echo "❌ Error: $FLATC_PATH exists but is not executable"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to safely copy directory contents without self-copying
|
||||
safe_copy_directory() {
|
||||
local source_dir="$1"
|
||||
local dest_dir="$2"
|
||||
|
||||
# Get absolute paths to avoid issues with relative paths
|
||||
source_dir=$(realpath "$source_dir" 2>/dev/null || echo "$source_dir")
|
||||
dest_dir=$(realpath "$dest_dir" 2>/dev/null || echo "$dest_dir")
|
||||
|
||||
if [ ! -d "$source_dir" ]; then
|
||||
echo "⚠️ Warning: Source directory does not exist: $source_dir"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Create destination directory
|
||||
mkdir -p "$dest_dir"
|
||||
|
||||
# Check if source and destination are the same
|
||||
if [ "$source_dir" = "$dest_dir" ]; then
|
||||
echo "ℹ️ Source and destination are identical, skipping copy: $source_dir"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if destination is a subdirectory of source to avoid infinite recursion
|
||||
case "$dest_dir" in
|
||||
"$source_dir"/*)
|
||||
echo "⚠️ Warning: Destination is inside source directory, this could cause issues"
|
||||
echo " Source: $source_dir"
|
||||
echo " Dest: $dest_dir"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "📋 Copying contents from $source_dir to $dest_dir"
|
||||
|
||||
# Use rsync if available for better handling, otherwise fall back to cp
|
||||
if command -v rsync >/dev/null 2>&1; then
|
||||
rsync -av --exclude="$dest_dir" "$source_dir"/ "$dest_dir"/
|
||||
else
|
||||
# Use find to avoid copying destination into itself
|
||||
find "$source_dir" -mindepth 1 -maxdepth 1 -not -path "$dest_dir" -exec cp -r {} "$dest_dir"/ \;
|
||||
fi
|
||||
|
||||
echo "✅ Copy completed successfully"
|
||||
}
|
||||
|
||||
# Find flatbuffers directory in any subdirectory
|
||||
echo "🔍 Searching for flatbuffers directory..."
|
||||
FLATBUFFERS_DIR=$(find . -name "flatbuffers" -type d | head -1)
|
||||
|
||||
if [ -z "$FLATBUFFERS_DIR" ]; then
|
||||
echo "⚠️ Warning: flatbuffers directory not found in any subdirectory"
|
||||
echo " This might be expected if headers are already in place"
|
||||
echo " Continuing with flatbuffer generation..."
|
||||
else
|
||||
echo "✅ Found flatbuffers directory at: $FLATBUFFERS_DIR"
|
||||
|
||||
# Create flatbuffers directory under ./include
|
||||
mkdir -p ./include/flatbuffers
|
||||
|
||||
# Safely copy everything from the found flatbuffers directory to ./include/flatbuffers/
|
||||
safe_copy_directory "$FLATBUFFERS_DIR" "./include/flatbuffers"
|
||||
|
||||
echo "📋 Verifying copied files:"
|
||||
ls -la ./include/flatbuffers/ || echo "⚠️ Directory listing failed"
|
||||
fi
|
||||
|
||||
# Ensure output directories exist
|
||||
mkdir -p ./include/graph/generated
|
||||
|
||||
# Check if required .fbs files exist before proceeding
|
||||
FBS_FILES=(
|
||||
"./include/graph/scheme/node.fbs"
|
||||
"./include/graph/scheme/graph.fbs"
|
||||
"./include/graph/scheme/result.fbs"
|
||||
"./include/graph/scheme/request.fbs"
|
||||
"./include/graph/scheme/config.fbs"
|
||||
"./include/graph/scheme/array.fbs"
|
||||
"./include/graph/scheme/utils.fbs"
|
||||
"./include/graph/scheme/variable.fbs"
|
||||
"./include/graph/scheme/properties.fbs"
|
||||
"./include/graph/scheme/sequence.fbs"
|
||||
)
|
||||
|
||||
UI_FBS_FILES=(
|
||||
"./include/graph/scheme/uigraphstatic.fbs"
|
||||
"./include/graph/scheme/uigraphevents.fbs"
|
||||
)
|
||||
|
||||
echo "🔍 Checking for required .fbs files..."
|
||||
missing_files=0
|
||||
for fbs_file in "${FBS_FILES[@]}"; do
|
||||
if [ ! -f "$fbs_file" ]; then
|
||||
echo "❌ Missing required file: $fbs_file"
|
||||
missing_files=$((missing_files + 1))
|
||||
else
|
||||
echo "✅ Found: $fbs_file"
|
||||
fi
|
||||
done
|
||||
|
||||
for fbs_file in "${UI_FBS_FILES[@]}"; do
|
||||
if [ ! -f "$fbs_file" ]; then
|
||||
echo "⚠️ Optional UI file missing: $fbs_file"
|
||||
else
|
||||
echo "✅ Found: $fbs_file"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $missing_files -gt 0 ]; then
|
||||
echo "❌ Error: $missing_files required .fbs files are missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🚀 Starting flatbuffer generation..."
|
||||
|
||||
# Generate flatbuffer files using built flatc with correct package (first command)
|
||||
echo "🔧 Generating flatbuffers with full options (Java, Binary, Text, C++)..."
|
||||
if ! "$FLATC_PATH" -o ./include/graph/generated -I ./include/graph/scheme -j -b -t -c \
|
||||
--java-package-prefix org.nd4j \
|
||||
"${FBS_FILES[@]}"; then
|
||||
echo "❌ Error: First flatc command failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Generate flatbuffer files (second command - Java and Binary only)
|
||||
echo "🔧 Generating flatbuffers (Java and Binary only)..."
|
||||
if ! "$FLATC_PATH" -o ./include/graph/generated -I ./include/graph/scheme -j -b \
|
||||
--java-package-prefix org.nd4j \
|
||||
"${FBS_FILES[@]}"; then
|
||||
echo "❌ Error: Second flatc command failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Generate gRPC flatbuffers if UI files exist
|
||||
ui_files_exist=true
|
||||
for fbs_file in "${UI_FBS_FILES[@]}"; do
|
||||
if [ ! -f "$fbs_file" ]; then
|
||||
ui_files_exist=false
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$ui_files_exist" = true ]; then
|
||||
echo "🔧 Generating gRPC flatbuffers..."
|
||||
if ! "$FLATC_PATH" -o ./include/graph/generated -I ./include/graph/scheme -j -b --grpc \
|
||||
--java-package-prefix org.nd4j \
|
||||
"${UI_FBS_FILES[@]}"; then
|
||||
echo "❌ Error: gRPC flatc command failed"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Skipping gRPC generation - UI files not found"
|
||||
fi
|
||||
|
||||
# Generate TypeScript files if target directory exists
|
||||
TS_OUTPUT_DIR="../nd4j/nd4j-web/nd4j-webjar/src/main/typescript"
|
||||
if [ -d "$(dirname "$TS_OUTPUT_DIR")" ]; then
|
||||
echo "🔧 Generating TypeScript files..."
|
||||
mkdir -p "$TS_OUTPUT_DIR"
|
||||
|
||||
# Combine all FBS files for TypeScript generation
|
||||
ALL_TS_FILES=("${FBS_FILES[@]}")
|
||||
if [ "$ui_files_exist" = true ]; then
|
||||
ALL_TS_FILES+=("${UI_FBS_FILES[@]}")
|
||||
fi
|
||||
|
||||
if ! "$FLATC_PATH" -o "$TS_OUTPUT_DIR" -I ./include/graph/scheme --ts \
|
||||
--ts-flat-files \
|
||||
"${ALL_TS_FILES[@]}"; then
|
||||
echo "❌ Error: TypeScript flatc command failed"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ TypeScript files generated successfully"
|
||||
else
|
||||
echo "ℹ️ Skipping TypeScript generation - target directory doesn't exist: $TS_OUTPUT_DIR"
|
||||
fi
|
||||
|
||||
echo "✅ Flatbuffer sources generated successfully"
|
||||
|
||||
# Verify that some expected output files were created
|
||||
echo "🔍 Verifying generated files..."
|
||||
if [ -d "./include/graph/generated" ]; then
|
||||
generated_count=$(find ./include/graph/generated -name "*.h" -o -name "*.java" | wc -l)
|
||||
echo "✅ Found $generated_count generated files in ./include/graph/generated"
|
||||
|
||||
# List some example files
|
||||
find ./include/graph/generated -name "*.h" -o -name "*.java" | head -5 | while read -r file; do
|
||||
echo " - $file"
|
||||
done
|
||||
else
|
||||
echo "⚠️ Warning: Generated directory not found"
|
||||
fi
|
||||
@@ -0,0 +1,118 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
#include <ConstMessages.h>
|
||||
|
||||
namespace sd {
|
||||
|
||||
const char *UNIQUE_TRANSFORM_STRICT_PREFIX = "__transform__strict__";
|
||||
const char *UNIQUE_SCALAROP_PREFIX= "__scalarop__";
|
||||
const char *OP_VALIDATION_FAIL_MSG = "Op validation failed";
|
||||
const char *HAVE_PEEPHOLE = "Having the Peephole connections";
|
||||
const char *HAVE_SEQLENARR = "Having theSequence length array";
|
||||
const char *MSG_CELL_CLIPPING = "Cell clipping";
|
||||
const char *TYPECHECK_MSG = "Checking the Type requirments for the NDArrays";
|
||||
const char *NO_MSG = "";
|
||||
const char *EXPECTED_TRUE = "expected to be True";
|
||||
const char *EXPECTED_FALSE = "expected to be False";
|
||||
const char *EXPECTED_NOT_SUPPORTED = "not supported";
|
||||
const char *EXPECTED_EQ_MSG = "expected to be equal to";
|
||||
const char *EXPECTED_NE_MSG = "expected to be different than";
|
||||
const char *EXPECTED_LT_MSG = "expected to be less than";
|
||||
const char *EXPECTED_LE_MSG = "expected to be less than or equal";
|
||||
const char *EXPECTED_GT_MSG = "expected to be greater than";
|
||||
const char *EXPECTED_GE_MSG = "expected to be greater than or equal";
|
||||
|
||||
const char *EXPECTED_IN = "expected to be one of these";
|
||||
|
||||
const char *IS_EMPTY_MSG_INPUT = IS_EMPTY_MSG_INPUT_;
|
||||
const char *IS_EMPTY_MSG_INPUT0 = IS_EMPTY_MSG_INPUT_ "#0";
|
||||
const char *IS_EMPTY_MSG_INPUT1 = IS_EMPTY_MSG_INPUT_ "#1";
|
||||
const char *IS_EMPTY_MSG_INPUT2 = IS_EMPTY_MSG_INPUT_ "#2";
|
||||
const char *IS_EMPTY_MSG_INPUT3 = IS_EMPTY_MSG_INPUT_ "#3";
|
||||
|
||||
const char *RANK_MSG_INPUT = RANK_MSG_INPUT_;
|
||||
const char *RANK_MSG_INPUT0 = RANK_MSG_INPUT_ "#0";
|
||||
const char *RANK_MSG_INPUT1 = RANK_MSG_INPUT_ "#1";
|
||||
const char *RANK_MSG_INPUT2 = RANK_MSG_INPUT_ "#2";
|
||||
const char *RANK_MSG_INPUT3 = RANK_MSG_INPUT_ "#3";
|
||||
|
||||
const char *LENGTH_MSG_INPUT = LENGTH_MSG_INPUT_;
|
||||
const char *LENGTH_MSG_INPUT0 = LENGTH_MSG_INPUT_ "#0";
|
||||
const char *LENGTH_MSG_INPUT1 = LENGTH_MSG_INPUT_ "#1";
|
||||
const char *LENGTH_MSG_INPUT2 = LENGTH_MSG_INPUT_ "#2";
|
||||
const char *LENGTH_MSG_INPUT3 = LENGTH_MSG_INPUT_ "#3";
|
||||
|
||||
const char *SHAPE_MSG_INPUT = SHAPE_MSG_INPUT_;
|
||||
const char *SHAPE_MSG_INPUT0 = SHAPE_MSG_INPUT_ "#0";
|
||||
const char *SHAPE_MSG_INPUT1 = SHAPE_MSG_INPUT_ "#1";
|
||||
const char *SHAPE_MSG_INPUT2 = SHAPE_MSG_INPUT_ "#2";
|
||||
const char *SHAPE_MSG_INPUT3 = SHAPE_MSG_INPUT_ "#3";
|
||||
|
||||
const char *TYPE_MSG_INPUT = TYPE_MSG_INPUT_;
|
||||
const char *TYPE_MSG_INPUT0 = TYPE_MSG_INPUT_ "#0";
|
||||
const char *TYPE_MSG_INPUT1 = TYPE_MSG_INPUT_ "#1";
|
||||
const char *TYPE_MSG_INPUT2 = TYPE_MSG_INPUT_ "#2";
|
||||
const char *TYPE_MSG_INPUT3 = TYPE_MSG_INPUT_ "#3";
|
||||
|
||||
const char *EWS_MSG_INPUT = EWS_MSG_INPUT_;
|
||||
const char *EWS_MSG_INPUT0 = EWS_MSG_INPUT_ "#0";
|
||||
const char *EWS_MSG_INPUT1 = EWS_MSG_INPUT_ "#1";
|
||||
const char *EWS_MSG_INPUT2 = EWS_MSG_INPUT_ "#2";
|
||||
const char *EWS_MSG_INPUT3 = EWS_MSG_INPUT_ "#3";
|
||||
|
||||
const char *ORDERING_MSG_INPUT = ORDERING_MSG_INPUT_;
|
||||
const char *ORDERING_MSG_INPUT0 = ORDERING_MSG_INPUT_ "#0";
|
||||
const char *ORDERING_MSG_INPUT1 = ORDERING_MSG_INPUT_ "#1";
|
||||
const char *ORDERING_MSG_INPUT2 = ORDERING_MSG_INPUT_ "#2";
|
||||
const char *ORDERING_MSG_INPUT3 = ORDERING_MSG_INPUT_ "#3";
|
||||
|
||||
const char *RANK_MSG_OUTPUT = RANK_MSG_OUTPUT_;
|
||||
const char *RANK_MSG_OUTPUT0 = RANK_MSG_OUTPUT_ "#0";
|
||||
const char *RANK_MSG_OUTPUT1 = RANK_MSG_OUTPUT_ "#1";
|
||||
const char *RANK_MSG_OUTPUT2 = RANK_MSG_OUTPUT_ "#2";
|
||||
|
||||
const char *IS_EMPTY_MSG_OUTPUT = IS_EMPTY_MSG_OUTPUT_;
|
||||
const char *IS_EMPTY_MSG_OUTPUT0 = IS_EMPTY_MSG_OUTPUT_ "#0";
|
||||
const char *IS_EMPTY_MSG_OUTPUT1 = IS_EMPTY_MSG_OUTPUT_ "#1";
|
||||
const char *IS_EMPTY_MSG_OUTPUT2 = IS_EMPTY_MSG_OUTPUT_ "#2";
|
||||
|
||||
const char *TYPE_MSG_OUTPUT = TYPE_MSG_OUTPUT_;
|
||||
const char *TYPE_MSG_OUTPUT0 = TYPE_MSG_OUTPUT_ "#0";
|
||||
const char *TYPE_MSG_OUTPUT1 = TYPE_MSG_OUTPUT_ "#1";
|
||||
const char *TYPE_MSG_OUTPUT2 = TYPE_MSG_OUTPUT_ "#2";
|
||||
|
||||
const char *EWS_MSG_OUTPUT = EWS_MSG_OUTPUT_;
|
||||
const char *EWS_MSG_OUTPUT0 = EWS_MSG_OUTPUT_ "#0";
|
||||
const char *EWS_MSG_OUTPUT1 = EWS_MSG_OUTPUT_ "#1";
|
||||
const char *EWS_MSG_OUTPUT2 = EWS_MSG_OUTPUT_ "#2";
|
||||
|
||||
const char *ORDERING_MSG_OUTPUT = ORDERING_MSG_OUTPUT_;
|
||||
const char *ORDERING_MSG_OUTPUT0 = ORDERING_MSG_OUTPUT_ "#0";
|
||||
const char *ORDERING_MSG_OUTPUT1 = ORDERING_MSG_OUTPUT_ "#1";
|
||||
const char *ORDERING_MSG_OUTPUT2 = ORDERING_MSG_OUTPUT_ "#2";
|
||||
|
||||
const char *SHAPE_MSG_OUTPUT = SHAPE_MSG_OUTPUT_;
|
||||
const char *SHAPE_MSG_OUTPUT0 = SHAPE_MSG_OUTPUT_ "#0";
|
||||
const char *SHAPE_MSG_OUTPUT1 = SHAPE_MSG_OUTPUT_ "#1";
|
||||
const char *SHAPE_MSG_OUTPUT2 = SHAPE_MSG_OUTPUT_ "#2";
|
||||
|
||||
const char *IS_USE_ONEDNN_MSG = "isUseONEDNN should be enabled to use ONEDNN";
|
||||
const char *ONEDNN_STREAM_NOT_SUPPORTED = "ONEDNN stream is not supported";
|
||||
const char *REQUIREMENTS_MEETS_MSG = "meets the requirements";
|
||||
const char *REQUIREMENTS_FAILS_MSG = "fails the requirements";
|
||||
} // namespace sd
|
||||
@@ -0,0 +1,139 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LIBND4J_CONST_MESSAGES_H
|
||||
#define LIBND4J_CONST_MESSAGES_H
|
||||
|
||||
namespace sd {
|
||||
|
||||
#define IS_EMPTY_MSG_INPUT_ "the Emptiness of the Input NDArray"
|
||||
#define IS_EMPTY_MSG_OUTPUT_ "the Emptiness of the Output NDArray"
|
||||
#define RANK_MSG_INPUT_ "the Rank of the Input NDArray"
|
||||
#define LENGTH_MSG_INPUT_ "the Length of the Input NDArray"
|
||||
#define SHAPE_MSG_INPUT_ "the Shape of the Input NDArray"
|
||||
#define SHAPE_MSG_OUTPUT_ "the Shape of the Output NDArray"
|
||||
#define RANK_MSG_OUTPUT_ "the Rank of the Output NDArray"
|
||||
#define TYPE_MSG_INPUT_ "the Type of the Input NDArray"
|
||||
#define TYPE_MSG_OUTPUT_ "the Type of the Output NDArray"
|
||||
#define EWS_MSG_INPUT_ "the EWS of the Input NDArray"
|
||||
#define EWS_MSG_OUTPUT_ "the EWS of the Output NDArray"
|
||||
#define ORDERING_MSG_INPUT_ "the Ordering of the Input NDArray"
|
||||
#define ORDERING_MSG_OUTPUT_ "the Ordering of the Output NDArray"
|
||||
|
||||
extern const char *UNIQUE_TRANSFORM_STRICT_PREFIX;
|
||||
extern const char *UNIQUE_SCALAROP_PREFIX;
|
||||
|
||||
extern const char *OP_VALIDATION_FAIL_MSG;
|
||||
extern const char *HAVE_SEQLENARR;
|
||||
extern const char *HAVE_PEEPHOLE;
|
||||
extern const char *MSG_CELL_CLIPPING;
|
||||
extern const char *TYPECHECK_MSG;
|
||||
extern const char *NO_MSG;
|
||||
extern const char *EXPECTED_TRUE;
|
||||
extern const char *EXPECTED_FALSE;
|
||||
extern const char *EXPECTED_NOT_SUPPORTED;
|
||||
extern const char *EXPECTED_EQ_MSG;
|
||||
extern const char *EXPECTED_NE_MSG;
|
||||
extern const char *EXPECTED_LT_MSG;
|
||||
extern const char *EXPECTED_LE_MSG;
|
||||
extern const char *EXPECTED_GT_MSG;
|
||||
extern const char *EXPECTED_GE_MSG;
|
||||
|
||||
extern const char *EXPECTED_IN;
|
||||
|
||||
extern const char *IS_EMPTY_MSG_INPUT;
|
||||
extern const char *IS_EMPTY_MSG_INPUT0;
|
||||
extern const char *IS_EMPTY_MSG_INPUT1;
|
||||
extern const char *IS_EMPTY_MSG_INPUT2;
|
||||
extern const char *IS_EMPTY_MSG_INPUT3;
|
||||
|
||||
extern const char *RANK_MSG_INPUT;
|
||||
extern const char *RANK_MSG_INPUT0;
|
||||
extern const char *RANK_MSG_INPUT1;
|
||||
extern const char *RANK_MSG_INPUT2;
|
||||
extern const char *RANK_MSG_INPUT3;
|
||||
|
||||
extern const char *LENGTH_MSG_INPUT;
|
||||
extern const char *LENGTH_MSG_INPUT0;
|
||||
extern const char *LENGTH_MSG_INPUT1;
|
||||
extern const char *LENGTH_MSG_INPUT2;
|
||||
extern const char *LENGTH_MSG_INPUT3;
|
||||
|
||||
extern const char *SHAPE_MSG_INPUT;
|
||||
extern const char *SHAPE_MSG_INPUT0;
|
||||
extern const char *SHAPE_MSG_INPUT1;
|
||||
extern const char *SHAPE_MSG_INPUT2;
|
||||
extern const char *SHAPE_MSG_INPUT3;
|
||||
|
||||
extern const char *TYPE_MSG_INPUT;
|
||||
extern const char *TYPE_MSG_INPUT0;
|
||||
extern const char *TYPE_MSG_INPUT1;
|
||||
extern const char *TYPE_MSG_INPUT2;
|
||||
extern const char *TYPE_MSG_INPUT3;
|
||||
|
||||
extern const char *EWS_MSG_INPUT;
|
||||
extern const char *EWS_MSG_INPUT0;
|
||||
extern const char *EWS_MSG_INPUT1;
|
||||
extern const char *EWS_MSG_INPUT2;
|
||||
extern const char *EWS_MSG_INPUT3;
|
||||
|
||||
extern const char *ORDERING_MSG_INPUT;
|
||||
extern const char *ORDERING_MSG_INPUT0;
|
||||
extern const char *ORDERING_MSG_INPUT1;
|
||||
extern const char *ORDERING_MSG_INPUT2;
|
||||
extern const char *ORDERING_MSG_INPUT3;
|
||||
|
||||
extern const char *RANK_MSG_OUTPUT;
|
||||
extern const char *RANK_MSG_OUTPUT0;
|
||||
extern const char *RANK_MSG_OUTPUT1;
|
||||
extern const char *RANK_MSG_OUTPUT2;
|
||||
|
||||
extern const char *IS_EMPTY_MSG_OUTPUT;
|
||||
extern const char *IS_EMPTY_MSG_OUTPUT0;
|
||||
extern const char *IS_EMPTY_MSG_OUTPUT1;
|
||||
extern const char *IS_EMPTY_MSG_OUTPUT2;
|
||||
|
||||
extern const char *TYPE_MSG_OUTPUT;
|
||||
extern const char *TYPE_MSG_OUTPUT0;
|
||||
extern const char *TYPE_MSG_OUTPUT1;
|
||||
extern const char *TYPE_MSG_OUTPUT2;
|
||||
|
||||
extern const char *EWS_MSG_OUTPUT;
|
||||
extern const char *EWS_MSG_OUTPUT0;
|
||||
extern const char *EWS_MSG_OUTPUT1;
|
||||
extern const char *EWS_MSG_OUTPUT2;
|
||||
|
||||
extern const char *ORDERING_MSG_OUTPUT;
|
||||
extern const char *ORDERING_MSG_OUTPUT0;
|
||||
extern const char *ORDERING_MSG_OUTPUT1;
|
||||
extern const char *ORDERING_MSG_OUTPUT2;
|
||||
|
||||
extern const char *SHAPE_MSG_OUTPUT;
|
||||
extern const char *SHAPE_MSG_OUTPUT0;
|
||||
extern const char *SHAPE_MSG_OUTPUT1;
|
||||
extern const char *SHAPE_MSG_OUTPUT2;
|
||||
|
||||
extern const char *IS_USE_ONEDNN_MSG;
|
||||
extern const char *ONEDNN_STREAM_NOT_SUPPORTED;
|
||||
|
||||
extern const char *REQUIREMENTS_MEETS_MSG;
|
||||
extern const char *REQUIREMENTS_FAILS_MSG;
|
||||
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,196 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#ifndef ND4J_ARRAY_OPTIONS_H
|
||||
#define ND4J_ARRAY_OPTIONS_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <system/common.h>
|
||||
#include <system/op_boilerplate.h>
|
||||
#include <array/ArrayType.h>
|
||||
#include <array/DataType.h>
|
||||
#include <array/SpaceType.h>
|
||||
#include <array/SparseType.h>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
|
||||
|
||||
//notice how each flag value is multiplied by 2
|
||||
//if they are too close in value values will clash.
|
||||
#define ARRAY_SPARSE 2
|
||||
#define ARRAY_COMPRESSED 4
|
||||
#define ARRAY_EMPTY 8
|
||||
#define ARRAY_RAGGED 16
|
||||
|
||||
#define ARRAY_CSR 32
|
||||
#define ARRAY_CSC 64
|
||||
#define ARRAY_COO 128
|
||||
|
||||
// complex values
|
||||
#define ARRAY_COMPLEX 512
|
||||
|
||||
// quantized values
|
||||
#define ARRAY_QUANTIZED 1024
|
||||
|
||||
// 16 bit float FP16
|
||||
#define ARRAY_HALF 4096
|
||||
|
||||
// 16 bit bfloat16
|
||||
#define ARRAY_BHALF 2048
|
||||
|
||||
// regular 32 bit float
|
||||
#define ARRAY_FLOAT 8192
|
||||
|
||||
// regular 64 bit float
|
||||
#define ARRAY_DOUBLE 16384
|
||||
|
||||
// 8 bit integer
|
||||
#define ARRAY_CHAR 32768
|
||||
|
||||
// 16 bit integer
|
||||
#define ARRAY_SHORT 65536
|
||||
|
||||
// 32 bit integer
|
||||
#define ARRAY_INT 131072
|
||||
|
||||
// 64 bit integer
|
||||
#define ARRAY_LONG 262144
|
||||
|
||||
// boolean values
|
||||
#define ARRAY_BOOL 524288
|
||||
|
||||
// UTF values
|
||||
#define ARRAY_UTF8 1048576
|
||||
#define ARRAY_UTF16 4194304
|
||||
#define ARRAY_UTF32 16777216
|
||||
|
||||
// flag for extras
|
||||
#define ARRAY_EXTRAS 2097152
|
||||
|
||||
// flag for signed/unsigned integers
|
||||
#define ARRAY_UNSIGNED 8388608
|
||||
|
||||
// flag for arrays with padded buffer
|
||||
#define ARRAY_HAS_PADDED_BUFFER (1 << 25)
|
||||
//flags for when array has a view or not
|
||||
#define ARRAY_IS_VIEW 33554432
|
||||
|
||||
//flag for when array needs a copy
|
||||
//this is mainly used in the reshape_no_copy op but could be used elsewhere
|
||||
#define ARRAY_NEEDS_COPY 67108864
|
||||
|
||||
|
||||
//we need this in order to preserve the offset of the original buffer when creating the output array
|
||||
//when views are created, sometimes we need to use the original offset of the array
|
||||
//we don't need this very often and we don't store the offset in the shape info
|
||||
//this preserves the offsets only being in the ndarray but allowing us to pass information
|
||||
//when creating views, each flag is for an input in to an op, most of the time we only need the first 3
|
||||
//but may need more. For now only the first one is used but may be needed elsewhere.
|
||||
#define ARRAY_COPY_OFFSET_INPUT_0 134217728
|
||||
#define ARRAY_COPY_OFFSET_INPUT_1 268435456
|
||||
#define ARRAY_COPY_OFFSET_INPUT_2 536870912
|
||||
#define ARRAY_COPY_OFFSET_INPUT_3 1073741824
|
||||
#define ARRAY_COPY_OFFSET_INPUT_4 2147483648
|
||||
#define ARRAY_COPY_OFFSET_INPUT_5 4294967296
|
||||
#define ARRAY_COPY_OFFSET_INPUT_6 8589934592
|
||||
#define ARRAY_COPY_OFFSET_INPUT_7 17179869184
|
||||
#define ARRAY_COPY_OFFSET_INPUT_8 34359738368
|
||||
#define ARRAY_COPY_OFFSET_INPUT_9 68719476736
|
||||
#define ARRAY_COPY_OFFSET_INPUT_10 137438953472
|
||||
|
||||
|
||||
#define DEFAULT_FLAG 0
|
||||
|
||||
|
||||
|
||||
|
||||
namespace sd {
|
||||
class SD_LIB_EXPORT ArrayOptions {
|
||||
public:
|
||||
static SD_HOST SD_INLINE LongType extra(const LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE void setExtra(LongType *shapeInfo, LongType value);
|
||||
static SD_HOST SD_INLINE bool isNewFormat(const LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE bool hasPropertyBitSet(const LongType *shapeInfo, LongType property);
|
||||
static SD_HOST SD_INLINE bool togglePropertyBit(LongType *shapeInfo, LongType property);
|
||||
static SD_HOST SD_INLINE void unsetPropertyBit(LongType *shapeInfo, LongType property);
|
||||
static SD_HOST SD_INLINE void validateSingleDataType(LongType property);
|
||||
static SD_HOST SD_INLINE void setPropertyBit(LongType *shapeInfo, LongType property);
|
||||
static SD_HOST SD_INLINE void setPropertyBits(LongType *shapeInfo, std::initializer_list<LongType> properties);
|
||||
static SD_HOST SD_INLINE sd::LongType numDataTypesSet(sd::LongType property);
|
||||
static SD_HOST SD_INLINE bool isUnsigned(LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE bool isSparseArray(sd::LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE DataType dataType(const LongType *shapeInfo);
|
||||
|
||||
static SD_HOST SD_INLINE SpaceType spaceType(LongType *shapeInfo);
|
||||
static SD_INLINE SD_HOST_DEVICE SpaceType spaceType(const LongType *shapeInfo);
|
||||
|
||||
static SD_HOST SD_INLINE ArrayType arrayType(LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE ArrayType arrayType(const LongType *shapeInfo);
|
||||
|
||||
static SD_HOST SD_INLINE bool isView(LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE void toggleIsView(LongType *shapeInfo);
|
||||
|
||||
static SD_INLINE SD_HOST_DEVICE SparseType sparseType(LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE SparseType sparseType(const LongType *shapeInfo);
|
||||
|
||||
static SD_INLINE SD_HOST_DEVICE bool hasExtraProperties(LongType *shapeInfo);
|
||||
|
||||
static SD_HOST SD_INLINE bool hasPaddedBuffer(const LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE void flagAsPaddedBuffer(LongType *shapeInfo);
|
||||
|
||||
static SD_HOST SD_INLINE void resetDataType(LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE LongType propertyWithoutDataType(const LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE void setDataType(LongType *shapeInfo, const DataType dataType);
|
||||
static SD_HOST SD_INLINE LongType setDataTypeValue(LongType extraStorage, const DataType dataType);
|
||||
static SD_HOST SD_INLINE LongType flagForDataType(const DataType dataType);
|
||||
static SD_HOST SD_INLINE void copyDataType(LongType *to, const LongType *from);
|
||||
static SD_HOST SD_INLINE const char *enumerateSetFlags(const LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE void unsetAllFlags(LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE int enumerateSetFlags(const LongType *shapeInfo, const char **setFlagsOutput, int maxFlags);
|
||||
static SD_HOST SD_INLINE const char *findFlagString(int flag);
|
||||
static SD_HOST SD_INLINE LongType extraIndex(const LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE LongType extraIndex(LongType *shapeInfo);
|
||||
static SD_HOST SD_INLINE void unsetAllFlags(LongType &flagStorage);
|
||||
static SD_HOST SD_INLINE const char *enumerateSetFlagsForFlags(const LongType flagStorage);
|
||||
static SD_HOST SD_INLINE SpaceType spaceTypeForFlags(const LongType &flagStorage);
|
||||
static SD_HOST SD_INLINE ArrayType arrayTypeForFlags(const LongType &flagStorage);
|
||||
static SD_HOST SD_INLINE bool togglePropertyBitForFlags(LongType &flagStorage, LongType property);
|
||||
static SD_HOST SD_INLINE LongType unsetPropertyBitForFlags(LongType &flagStorage, LongType property);
|
||||
static SD_HOST SD_INLINE SparseType sparseTypeForFlags(const LongType &flagStorage);
|
||||
static SD_INLINE LongType setPropertyBitForFlagsValue(LongType extraStorage, LongType property);
|
||||
static SD_HOST SD_INLINE bool hasPropertyBitSet(const LongType extra, LongType property);
|
||||
static SD_HOST SD_INLINE void resetFlags(LongType *to);
|
||||
static SD_HOST SD_INLINE LongType defaultFlag();
|
||||
|
||||
static SD_HOST SD_INLINE LongType propertyWithoutDataTypeValue(LongType extra);
|
||||
static SD_HOST SD_INLINE DataType dataTypeValue(LongType property);
|
||||
static SD_INLINE bool isEmpty(LongType *shapeInfo);
|
||||
static SD_INLINE void toggleIsEmpty(LongType *shapeInfo);
|
||||
|
||||
static SD_INLINE bool arrayNeedsCopy(LongType *shapeInfo);
|
||||
static SD_INLINE void toggleArrayNeedsCopy(LongType *shapeInfo);
|
||||
};
|
||||
|
||||
}
|
||||
#endif // ND4J_ARRAY_OPTIONS_H :)
|
||||
@@ -0,0 +1,799 @@
|
||||
#ifndef ND4J_ARRAY_OPTIONS_HXX
|
||||
#define ND4J_ARRAY_OPTIONS_HXX
|
||||
#include <array/ArrayOptions.h>
|
||||
#include <system/op_boilerplate.h>
|
||||
#include <helpers/shape.h>
|
||||
#include <array/DataTypeUtils.h>
|
||||
#pragma once
|
||||
|
||||
namespace sd {
|
||||
|
||||
|
||||
|
||||
SD_HOST SD_INLINE sd::LongType ArrayOptions::extraIndex(const sd::LongType *shapeInfo) {
|
||||
return ArrayOptions::extraIndex(const_cast<sd::LongType *>(shapeInfo));
|
||||
}
|
||||
|
||||
|
||||
SD_HOST SD_INLINE sd::LongType ArrayOptions::extraIndex(sd::LongType *shapeInfo) {
|
||||
if(shapeInfo == nullptr)
|
||||
THROW_EXCEPTION("Shape info was null!");
|
||||
sd::LongType rank = shapeInfo[0];
|
||||
|
||||
sd::LongType idx = 0;
|
||||
//rank takes up 1 element + usual elements
|
||||
if(rank == 0)
|
||||
idx = 3;
|
||||
else
|
||||
// FIXME magic numbers
|
||||
idx = rank + rank + 1;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::setExtra(sd::LongType *shapeInfo, sd::LongType value) {
|
||||
sd::LongType idx = ArrayOptions::extraIndex(shapeInfo);
|
||||
shapeInfo[idx] = value;
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE LongType ArrayOptions::extra(const LongType *shapeInfo) {
|
||||
sd::LongType idx = ArrayOptions::extraIndex(shapeInfo);
|
||||
if(idx > shape::shapeInfoLength(shape::rank(shapeInfo)))
|
||||
THROW_EXCEPTION("Extra index is out of bounds!");
|
||||
return shapeInfo[idx];
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE bool ArrayOptions::isNewFormat(const sd::LongType *shapeInfo) {
|
||||
return (extra(const_cast<sd::LongType *>(shapeInfo)) != 0);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE bool ArrayOptions::isSparseArray(sd::LongType *shapeInfo) {
|
||||
return hasPropertyBitSet(shapeInfo, ARRAY_SPARSE);
|
||||
}
|
||||
|
||||
SD_HOST_DEVICE SD_INLINE bool ArrayOptions::hasExtraProperties(sd::LongType *shapeInfo) {
|
||||
return hasPropertyBitSet(shapeInfo, ARRAY_EXTRAS);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE bool ArrayOptions::hasPropertyBitSet(const sd::LongType extra, LongType property) {
|
||||
return ((static_cast<int>(extra) & static_cast<int>(property)) == static_cast<int>(property));
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE bool ArrayOptions:: hasPropertyBitSet(const sd::LongType *shapeInfo, LongType property) {
|
||||
if (!isNewFormat(shapeInfo)) return false;
|
||||
|
||||
return ((static_cast<int>(extra(const_cast<sd::LongType *>(shapeInfo)) & property)) == static_cast<int>(property));
|
||||
}
|
||||
|
||||
|
||||
SD_HOST_DEVICE SD_INLINE bool hasPropertyBitSetForFlags(const sd::LongType& flagStorage, LongType property) {
|
||||
return static_cast<sd::LongType>(flagStorage & (property)) == (property);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void unsetPropertyBitForFlags(sd::LongType& flagStorage, LongType property) {
|
||||
flagStorage &= ~property;
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE const char *ArrayOptions::enumerateSetFlagsForFlags(const LongType flagStorage) {
|
||||
int maxFlags = 24;
|
||||
int flagsArray[] = {
|
||||
ARRAY_SPARSE,
|
||||
ARRAY_COMPRESSED,
|
||||
ARRAY_EMPTY,
|
||||
ARRAY_RAGGED,
|
||||
ARRAY_CSR,
|
||||
ARRAY_CSC,
|
||||
ARRAY_COO,
|
||||
ARRAY_COMPLEX,
|
||||
ARRAY_QUANTIZED,
|
||||
ARRAY_HALF,
|
||||
ARRAY_BHALF,
|
||||
ARRAY_FLOAT,
|
||||
ARRAY_DOUBLE,
|
||||
ARRAY_CHAR,
|
||||
ARRAY_SHORT,
|
||||
ARRAY_INT,
|
||||
ARRAY_LONG,
|
||||
ARRAY_BOOL,
|
||||
ARRAY_UTF8,
|
||||
ARRAY_UTF16,
|
||||
ARRAY_UTF32,
|
||||
ARRAY_EXTRAS,
|
||||
ARRAY_UNSIGNED,
|
||||
ARRAY_HAS_PADDED_BUFFER,
|
||||
ARRAY_IS_VIEW
|
||||
};
|
||||
|
||||
const char* flagsStrings[] = {
|
||||
"ARRAY_SPARSE",
|
||||
"ARRAY_COMPRESSED",
|
||||
"ARRAY_EMPTY",
|
||||
"ARRAY_RAGGED",
|
||||
"ARRAY_CSR",
|
||||
"ARRAY_CSC",
|
||||
"ARRAY_COO",
|
||||
"ARRAY_COMPLEX",
|
||||
"ARRAY_QUANTIZED",
|
||||
"ARRAY_HALF",
|
||||
"ARRAY_BHALF",
|
||||
"ARRAY_FLOAT",
|
||||
"ARRAY_DOUBLE",
|
||||
"ARRAY_CHAR",
|
||||
"ARRAY_SHORT",
|
||||
"ARRAY_INT",
|
||||
"ARRAY_LONG",
|
||||
"ARRAY_BOOL",
|
||||
"ARRAY_UTF8",
|
||||
"ARRAY_UTF16",
|
||||
"ARRAY_UTF32",
|
||||
"ARRAY_EXTRAS",
|
||||
"ARRAY_UNSIGNED",
|
||||
"ARRAY_HAS_PADDED_BUFFER",
|
||||
"ARRAY_IS_VIEW"
|
||||
};
|
||||
|
||||
std::string flags;
|
||||
for (int i = 0; i < maxFlags; i++) {
|
||||
if (hasPropertyBitSetForFlags(flagStorage, flagsArray[i])) {
|
||||
flags += flagsStrings[i];
|
||||
flags += " ";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
auto ret = new std::string(flags); // Returns the number of set flags found
|
||||
return ret->c_str();
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::unsetAllFlags(sd::LongType& flagStorage) {
|
||||
|
||||
int flagsArray[] = {
|
||||
ARRAY_SPARSE,
|
||||
ARRAY_COMPRESSED,
|
||||
ARRAY_EMPTY,
|
||||
ARRAY_RAGGED,
|
||||
ARRAY_CSR,
|
||||
ARRAY_CSC,
|
||||
ARRAY_COO,
|
||||
ARRAY_COMPLEX,
|
||||
ARRAY_QUANTIZED,
|
||||
ARRAY_HALF,
|
||||
ARRAY_BHALF,
|
||||
ARRAY_FLOAT,
|
||||
ARRAY_DOUBLE,
|
||||
ARRAY_CHAR,
|
||||
ARRAY_SHORT,
|
||||
ARRAY_INT,
|
||||
ARRAY_LONG,
|
||||
ARRAY_BOOL,
|
||||
ARRAY_UTF8,
|
||||
ARRAY_UTF16,
|
||||
ARRAY_UTF32,
|
||||
ARRAY_EXTRAS,
|
||||
ARRAY_UNSIGNED,
|
||||
ARRAY_HAS_PADDED_BUFFER
|
||||
};
|
||||
|
||||
for (int i = 0; i < 24; i++) {
|
||||
unsetPropertyBitForFlags(flagStorage, flagsArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE const char *ArrayOptions::enumerateSetFlags(const sd::LongType *shapeInfo) {
|
||||
return enumerateSetFlagsForFlags(shapeInfo[ArrayOptions::extraIndex(shapeInfo)]);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::unsetAllFlags(sd::LongType *shapeInfo) {
|
||||
ArrayOptions::unsetAllFlags(shapeInfo[ArrayOptions::extraIndex(shapeInfo)]);
|
||||
}
|
||||
|
||||
|
||||
SD_HOST SD_INLINE bool ArrayOptions::isUnsigned(sd::LongType *shapeInfo) {
|
||||
if (!isNewFormat(shapeInfo)) return false;
|
||||
|
||||
return hasPropertyBitSet(shapeInfo, ARRAY_UNSIGNED);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define DATA_TYPE_FLAGS { \
|
||||
ARRAY_FLOAT, \
|
||||
ARRAY_DOUBLE, \
|
||||
ARRAY_HALF, \
|
||||
ARRAY_BHALF, \
|
||||
ARRAY_BOOL, \
|
||||
ARRAY_CHAR, \
|
||||
ARRAY_SHORT, \
|
||||
ARRAY_INT, \
|
||||
ARRAY_LONG, \
|
||||
ARRAY_UTF8, \
|
||||
ARRAY_UTF16, \
|
||||
ARRAY_UTF32 \
|
||||
}
|
||||
|
||||
#define DATA_TYPES { \
|
||||
sd::DataType::FLOAT32, \
|
||||
sd::DataType::DOUBLE, \
|
||||
sd::DataType::HALF, \
|
||||
sd::DataType::BFLOAT16, \
|
||||
sd::DataType::BOOL, \
|
||||
sd::DataType::INT8, \
|
||||
sd::DataType::INT16, \
|
||||
sd::DataType::INT32, \
|
||||
sd::DataType::INT64, \
|
||||
sd::DataType::UTF8, \
|
||||
sd::DataType::UTF16, \
|
||||
sd::DataType::UTF32 \
|
||||
}
|
||||
|
||||
#define ARRAY_UNSIGNED_TYPES { \
|
||||
ARRAY_CHAR, \
|
||||
ARRAY_SHORT, \
|
||||
ARRAY_INT, \
|
||||
ARRAY_LONG, \
|
||||
ARRAY_UTF8, \
|
||||
ARRAY_UTF16, \
|
||||
ARRAY_UTF32 \
|
||||
}
|
||||
|
||||
#define UNSIGNED_DATA_TYPES { \
|
||||
sd::DataType::UINT8, \
|
||||
sd::DataType::UINT16, \
|
||||
sd::DataType::UINT32, \
|
||||
sd::DataType::UINT64, \
|
||||
sd::DataType::UTF8, \
|
||||
sd::DataType::UTF16, \
|
||||
sd::DataType::UTF32 \
|
||||
}
|
||||
|
||||
|
||||
SD_HOST SD_INLINE sd::DataType ArrayOptions::dataTypeValue(sd::LongType property) {
|
||||
const sd::LongType dataTypeFlags[] = DATA_TYPE_FLAGS;
|
||||
const sd::DataType dataTypes[] = DATA_TYPES;
|
||||
const size_t numTypes = sizeof(dataTypeFlags) / sizeof(sd::LongType);
|
||||
|
||||
|
||||
if (hasPropertyBitSetForFlags(property, ARRAY_UNSIGNED)) {
|
||||
const sd::LongType unsignedTypeFlags[] = ARRAY_UNSIGNED_TYPES;
|
||||
const sd::DataType unsignedDataTypes[] = UNSIGNED_DATA_TYPES;
|
||||
const size_t numUnsignedTypes = sizeof(unsignedTypeFlags) / sizeof(sd::LongType);
|
||||
|
||||
for (size_t i = 0; i < numUnsignedTypes; ++i) {
|
||||
if (hasPropertyBitSetForFlags(property, unsignedTypeFlags[i])) {
|
||||
return unsignedDataTypes[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < numTypes; ++i) {
|
||||
if (hasPropertyBitSetForFlags(property, dataTypeFlags[i])) {
|
||||
return dataTypes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sd::DataType::UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SD_HOST SD_INLINE void validateFlags(sd::LongType property, const sd::LongType flags[], size_t numFlags) {
|
||||
LongType *flagIndices = new LongType[numFlags];
|
||||
int numFlagsSet = 0;
|
||||
for (size_t i = 0; i < numFlags; ++i) {
|
||||
if (hasPropertyBitSetForFlags(property, flags[i])) {
|
||||
flagIndices[i] = 1;
|
||||
numFlagsSet++;
|
||||
} else {
|
||||
flagIndices[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (numFlagsSet > 1) {
|
||||
std::ostringstream errorMsg;
|
||||
errorMsg << "Multiple data types are set for the given property: ";
|
||||
for (size_t i = 0; i < numFlags; i++) {
|
||||
if(flagIndices[i] == 1) {
|
||||
errorMsg << "Flag index " << i << " (flag value: " << flags[i] << "), ";
|
||||
}
|
||||
}
|
||||
errorMsg << "Total: " << numFlagsSet << " data types set.";
|
||||
THROW_EXCEPTION(errorMsg.str().c_str());
|
||||
}
|
||||
|
||||
delete[] flagIndices;
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::validateSingleDataType(sd::LongType property) {
|
||||
const sd::LongType dataTypeFlags[] = DATA_TYPE_FLAGS;
|
||||
const size_t numDataTypeFlags = sizeof(dataTypeFlags) / sizeof(sd::LongType);
|
||||
validateFlags(property, dataTypeFlags, numDataTypeFlags);
|
||||
|
||||
if (hasPropertyBitSetForFlags(property, ARRAY_UNSIGNED)) {
|
||||
const sd::LongType unsignedTypeFlags[] = ARRAY_UNSIGNED_TYPES;
|
||||
const size_t numUnsignedTypeFlags = sizeof(unsignedTypeFlags) / sizeof(sd::LongType);
|
||||
validateFlags(property, unsignedTypeFlags, numUnsignedTypeFlags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SD_HOST SD_INLINE sd::LongType ArrayOptions::numDataTypesSet(sd::LongType property) {
|
||||
const sd::LongType dataTypeFlags[] = DATA_TYPE_FLAGS;
|
||||
const size_t numDataTypeFlags = sizeof(dataTypeFlags) / sizeof(sd::LongType);
|
||||
|
||||
sd::LongType numFlagsSet = 0;
|
||||
for (size_t i = 0; i < numDataTypeFlags; ++i) {
|
||||
if (hasPropertyBitSetForFlags(property, dataTypeFlags[i])) {
|
||||
numFlagsSet++;
|
||||
}
|
||||
}
|
||||
|
||||
return numFlagsSet;
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE sd::DataType ArrayOptions::dataType(const sd::LongType *shapeInfo) {
|
||||
// Return safe default instead of throwing - prevents SIGABRT crashes
|
||||
if(shapeInfo == nullptr)
|
||||
return DataType::FLOAT32; // Safe default for uninitialized arrays
|
||||
|
||||
auto extra = ArrayOptions::extra(shapeInfo);
|
||||
return ArrayOptions::dataTypeValue(extra);
|
||||
}
|
||||
|
||||
|
||||
|
||||
SD_HOST SD_INLINE SpaceType ArrayOptions::spaceTypeForFlags(const sd::LongType& flagStorage) {
|
||||
if (hasPropertyBitSetForFlags(flagStorage, ARRAY_QUANTIZED)) return SpaceType::QUANTIZED;
|
||||
if (hasPropertyBitSetForFlags(flagStorage, ARRAY_COMPLEX)) return SpaceType::COMPLEX;
|
||||
return SpaceType::CONTINUOUS; // by default we return continuous type here
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE ArrayType ArrayOptions::arrayTypeForFlags(const sd::LongType& flagStorage) {
|
||||
if (hasPropertyBitSetForFlags(flagStorage, ARRAY_SPARSE)) return ArrayType::SPARSE;
|
||||
if (hasPropertyBitSetForFlags(flagStorage, ARRAY_COMPRESSED)) return ArrayType::COMPRESSED;
|
||||
if (hasPropertyBitSetForFlags(flagStorage, ARRAY_EMPTY)) return ArrayType::EMPTY;
|
||||
if (hasPropertyBitSetForFlags(flagStorage, ARRAY_RAGGED)) return ArrayType::RAGGED;
|
||||
return ArrayType::DENSE; // by default we return DENSE type here
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE bool ArrayOptions::togglePropertyBitForFlags(sd::LongType& flagStorage, LongType property) {
|
||||
flagStorage ^= property;
|
||||
return hasPropertyBitSetForFlags(flagStorage, property);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE sd::LongType ArrayOptions::unsetPropertyBitForFlags(sd::LongType& flagStorage, LongType property) {
|
||||
return flagStorage & ~property;
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE SparseType ArrayOptions::sparseTypeForFlags(const sd::LongType& flagStorage) {
|
||||
if (hasPropertyBitSetForFlags(flagStorage, ARRAY_CSC)) return SparseType::CSC;
|
||||
if (hasPropertyBitSetForFlags(flagStorage, ARRAY_CSR)) return SparseType::CSR;
|
||||
if (hasPropertyBitSetForFlags(flagStorage, ARRAY_COO)) return SparseType::COO;
|
||||
return SparseType::LIL;
|
||||
}
|
||||
|
||||
// Existing function that works with shapeInfo:
|
||||
SD_HOST_DEVICE SD_INLINE SpaceType ArrayOptions::spaceType(const sd::LongType *shapeInfo) {
|
||||
return spaceTypeForFlags(shapeInfo[ArrayOptions::extraIndex(shapeInfo)]);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE ArrayType ArrayOptions::arrayType(const sd::LongType *shapeInfo) {
|
||||
return arrayTypeForFlags(shapeInfo[ArrayOptions::extraIndex(shapeInfo)]);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE ArrayType ArrayOptions::arrayType(sd::LongType *shapeInfo) {
|
||||
return arrayTypeForFlags(shapeInfo[ArrayOptions::extraIndex(shapeInfo)]);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE bool ArrayOptions::isEmpty(sd::LongType *shapeInfo) {
|
||||
return hasPropertyBitSet(shapeInfo, EMPTY);
|
||||
}
|
||||
|
||||
|
||||
SD_HOST SD_INLINE bool ArrayOptions::arrayNeedsCopy(LongType *shapeInfo) {
|
||||
return hasPropertyBitSetForFlags(shapeInfo[ArrayOptions::extraIndex(shapeInfo)], ARRAY_NEEDS_COPY);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::toggleArrayNeedsCopy(LongType *shapeInfo) {
|
||||
togglePropertyBit(shapeInfo, ARRAY_NEEDS_COPY);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::toggleIsEmpty(sd::LongType *shapeInfo) {
|
||||
togglePropertyBit(shapeInfo, EMPTY);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE bool ArrayOptions::isView(sd::LongType *shapeInfo) {
|
||||
return hasPropertyBitSet(shapeInfo, ARRAY_IS_VIEW);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::toggleIsView(sd::LongType *shapeInfo) {
|
||||
togglePropertyBit(shapeInfo, ARRAY_IS_VIEW);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE bool ArrayOptions::togglePropertyBit(sd::LongType *shapeInfo, LongType property) {
|
||||
return togglePropertyBitForFlags(shapeInfo[ArrayOptions::extraIndex(shapeInfo)], property);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::setPropertyBit(sd::LongType *shapeInfo, LongType property) {
|
||||
shapeInfo[ArrayOptions::extraIndex(shapeInfo)] = setPropertyBitForFlagsValue(shapeInfo[ArrayOptions::extraIndex(shapeInfo)], property);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::unsetPropertyBit(sd::LongType *shapeInfo, LongType property) {
|
||||
shapeInfo[ArrayOptions::extraIndex(shapeInfo)] = unsetPropertyBitForFlags(shapeInfo[ArrayOptions::extraIndex(shapeInfo)], property);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE SparseType ArrayOptions::sparseType(const sd::LongType *shapeInfo) {
|
||||
return sparseTypeForFlags(shapeInfo[ArrayOptions::extraIndex(shapeInfo)]);
|
||||
}
|
||||
SD_HOST SD_INLINE void ArrayOptions::setPropertyBits(sd::LongType *shapeInfo, std::initializer_list<LongType> properties) {
|
||||
for (auto v : properties) {
|
||||
if (!hasPropertyBitSet(shapeInfo, v)) setPropertyBit(shapeInfo, v);
|
||||
}
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::flagAsPaddedBuffer(sd::LongType *shapeInfo) {
|
||||
if (!isNewFormat(shapeInfo)) return;
|
||||
|
||||
return setPropertyBit(shapeInfo, ARRAY_HAS_PADDED_BUFFER);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE bool ArrayOptions::hasPaddedBuffer(const sd::LongType *shapeInfo) {
|
||||
if (!isNewFormat(shapeInfo)) return false;
|
||||
|
||||
return hasPropertyBitSet(shapeInfo, ARRAY_HAS_PADDED_BUFFER);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE sd::LongType ArrayOptions::propertyWithoutDataTypeValue(sd::LongType extra) {
|
||||
sd::LongType property = extra;
|
||||
property = property & (~ARRAY_BOOL);
|
||||
property = property & (~ARRAY_HALF);
|
||||
property = property & (~ARRAY_BHALF);
|
||||
property = property & (~ARRAY_FLOAT);
|
||||
property = property & (~ARRAY_DOUBLE);
|
||||
property = property & (~ARRAY_INT);
|
||||
property = property & (~ARRAY_LONG);
|
||||
property = property & (~ARRAY_CHAR);
|
||||
property = property & (~ARRAY_SHORT);
|
||||
property = property & (~ARRAY_UNSIGNED);
|
||||
return property;
|
||||
}
|
||||
|
||||
|
||||
SD_HOST SD_INLINE sd::LongType ArrayOptions::propertyWithoutDataType(const sd::LongType *shapeInfo) {
|
||||
auto newCast = const_cast<sd::LongType *>(shapeInfo);
|
||||
sd::LongType property = extra(newCast);
|
||||
return propertyWithoutDataTypeValue(property);
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::resetDataType(sd::LongType *shapeInfo) {
|
||||
setExtra(shapeInfo, propertyWithoutDataType(shapeInfo));
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE LongType ArrayOptions::flagForDataType(const sd::DataType dataType) {
|
||||
switch (dataType) {
|
||||
case sd::DataType::BOOL:
|
||||
return ARRAY_BOOL;
|
||||
case sd::DataType::HALF:
|
||||
return ARRAY_HALF;
|
||||
case sd::DataType::BFLOAT16:
|
||||
return ARRAY_BHALF;
|
||||
case sd::DataType::FLOAT32:
|
||||
return ARRAY_FLOAT;
|
||||
case sd::DataType::DOUBLE:
|
||||
return ARRAY_DOUBLE;
|
||||
case sd::DataType::INT8:
|
||||
return ARRAY_CHAR;
|
||||
case sd::DataType::INT16:
|
||||
return ARRAY_SHORT;
|
||||
case sd::DataType::INT32:
|
||||
return ARRAY_INT;
|
||||
case sd::DataType::INT64:
|
||||
return ARRAY_LONG;
|
||||
case sd::DataType::UINT8:
|
||||
return ARRAY_CHAR | ARRAY_UNSIGNED;
|
||||
case sd::DataType::UINT16:
|
||||
return ARRAY_SHORT | ARRAY_UNSIGNED;
|
||||
case sd::DataType::UINT32 :
|
||||
return ARRAY_INT | ARRAY_UNSIGNED;
|
||||
case sd::DataType::UINT64 :
|
||||
return ARRAY_LONG | ARRAY_UNSIGNED;
|
||||
case sd::DataType::UTF8:
|
||||
return ARRAY_UTF8;
|
||||
case sd::DataType::UTF16:
|
||||
return ARRAY_UTF16;
|
||||
case sd::DataType::UTF32:
|
||||
return ARRAY_UTF32;
|
||||
default:
|
||||
#ifndef __CUDA_ARCH__
|
||||
std::string errorMessage;
|
||||
errorMessage += "Can't set unknown data type ArrayOptions: ";
|
||||
errorMessage += sd::DataTypeUtils::asString(dataType);
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
return 0; // Never reached, but satisfies compiler warning
|
||||
|
||||
#else
|
||||
printf("Can't set unknown data type");
|
||||
return 0; // Return sentinel value for unknown types in CUDA code
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE void ArrayOptions::setDataType(sd::LongType *shapeInfo, const sd::DataType dataType) {
|
||||
switch (dataType) {
|
||||
case sd::DataType::BOOL:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_BOOL);
|
||||
break;
|
||||
case sd::DataType::HALF:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_HALF);
|
||||
break;
|
||||
case sd::DataType::BFLOAT16:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_BHALF);
|
||||
break;
|
||||
case sd::DataType::FLOAT32:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_FLOAT);
|
||||
break;
|
||||
case sd::DataType::DOUBLE:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_DOUBLE);
|
||||
break;
|
||||
case sd::DataType::INT8:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_CHAR);
|
||||
break;
|
||||
case sd::DataType::INT16:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_SHORT);
|
||||
break;
|
||||
case sd::DataType::INT32:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_INT);
|
||||
break;
|
||||
case sd::DataType::INT64:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_LONG);
|
||||
break;
|
||||
case sd::DataType::UINT8:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_CHAR | ARRAY_UNSIGNED);
|
||||
break;
|
||||
case sd::DataType::UINT16:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_SHORT | ARRAY_UNSIGNED);
|
||||
break;
|
||||
case sd::DataType::UINT32:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_INT | ARRAY_UNSIGNED);
|
||||
break;
|
||||
case sd::DataType::UINT64:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_LONG | ARRAY_UNSIGNED);
|
||||
break;
|
||||
case sd::DataType::UTF8:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_UTF8);
|
||||
break;
|
||||
case sd::DataType::UTF16:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_UTF16);
|
||||
break;
|
||||
case sd::DataType::UTF32:
|
||||
ArrayOptions::resetDataType(shapeInfo);
|
||||
setPropertyBit(shapeInfo, ARRAY_UTF32);
|
||||
break;
|
||||
default:
|
||||
#ifndef __CUDA_ARCH__
|
||||
std::string errorMessage;
|
||||
errorMessage += "Can't set unknown data type: ";
|
||||
errorMessage += DataTypeUtils::asString(dataType);
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
#else
|
||||
printf("Can't set unknown data type");
|
||||
#endif
|
||||
|
||||
validateSingleDataType(shapeInfo[ArrayOptions::extraIndex(shapeInfo)]);
|
||||
|
||||
}
|
||||
|
||||
#ifndef __CUDA_ARCH__
|
||||
if(ArrayOptions::dataType(shapeInfo) != dataType) {
|
||||
std::string errorMessage;
|
||||
errorMessage += "setDataType: Data type set was not correct one. Expected ";
|
||||
errorMessage += DataTypeUtils::asString(dataType);
|
||||
errorMessage += " but got ";
|
||||
errorMessage += sd::DataTypeUtils::asString(dataType);
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
}
|
||||
|
||||
#else
|
||||
printf("setDataType: Data type set was incorrect.");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
SD_HOST SD_INLINE sd::LongType ArrayOptions::setDataTypeValue(sd::LongType extraStorage, const sd::DataType dataType) {
|
||||
sd::LongType ret = extraStorage;
|
||||
if (dataType == sd::DataType::UINT8
|
||||
|| dataType == sd::DataType::UINT16
|
||||
|| dataType == sd::DataType::UINT32 ||
|
||||
dataType == sd::DataType::UINT64) {
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_UNSIGNED);
|
||||
extraStorage = ret;
|
||||
return extraStorage;
|
||||
}
|
||||
|
||||
|
||||
switch (dataType) {
|
||||
case sd::DataType::BOOL:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_BOOL);
|
||||
break;
|
||||
case sd::DataType::HALF:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_HALF);
|
||||
break;
|
||||
case sd::DataType::BFLOAT16:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_BHALF);
|
||||
break;
|
||||
case sd::DataType::FLOAT32:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_FLOAT);
|
||||
break;
|
||||
case sd::DataType::DOUBLE:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_DOUBLE);
|
||||
break;
|
||||
case sd::DataType::INT8:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_CHAR);
|
||||
break;
|
||||
case sd::DataType::INT16:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_SHORT);
|
||||
break;
|
||||
case sd::DataType::INT32:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_INT);
|
||||
break;
|
||||
case sd::DataType::INT64:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_LONG);
|
||||
break;
|
||||
case sd::DataType::UINT8:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_CHAR);
|
||||
break;
|
||||
case sd::DataType::UINT16:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_SHORT);
|
||||
break;
|
||||
case sd::DataType::UINT32:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_INT);
|
||||
break;
|
||||
case sd::DataType::UINT64:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_LONG);
|
||||
break;
|
||||
case sd::DataType::UTF8:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_UTF8);
|
||||
break;
|
||||
case sd::DataType::UTF16:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_UTF16);
|
||||
break;
|
||||
case sd::DataType::UTF32:
|
||||
ret = setPropertyBitForFlagsValue(extraStorage, ARRAY_UTF32);
|
||||
break;
|
||||
default:
|
||||
#ifndef __CUDA_ARCH__
|
||||
THROW_EXCEPTION("Can't set unknown data type");
|
||||
#else
|
||||
printf("Can't set unknown data type");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
SD_HOST sd::LongType ArrayOptions::defaultFlag() {
|
||||
return DEFAULT_FLAG;
|
||||
}
|
||||
|
||||
SD_HOST void ArrayOptions::resetFlags(sd::LongType *to) {
|
||||
to[ArrayOptions::extraIndex(to)] = 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
SD_HOST SD_INLINE void ArrayOptions::copyDataType(sd::LongType *to, const sd::LongType *from) {
|
||||
if(to == nullptr)
|
||||
THROW_EXCEPTION("To Shape info was null!");
|
||||
if(from == nullptr)
|
||||
THROW_EXCEPTION("From Shape info was null!");
|
||||
DataType dt = dataType(from);
|
||||
sd::LongType flagForDt = flagForDataType(dt);
|
||||
if(hasPropertyBitSet(to, flagForDt))
|
||||
return;
|
||||
setDataType(to, dt);
|
||||
}
|
||||
SD_HOST sd::LongType ArrayOptions::setPropertyBitForFlagsValue(LongType extraStorage, LongType property) {
|
||||
if(hasPropertyBitSet(extraStorage, property))
|
||||
return extraStorage;
|
||||
return extraStorage | property;
|
||||
}
|
||||
|
||||
// New method implementations to add to ArrayOptions.hXX
|
||||
|
||||
// needsCopy - const overload to check if array needs copy
|
||||
SD_HOST SD_INLINE bool ArrayOptions::needsCopy(const LongType *shapeInfo) {
|
||||
return hasPropertyBitSet(shapeInfo, ARRAY_NEEDS_COPY);
|
||||
}
|
||||
|
||||
// hasCopyOffset - check if specific input index has copy offset flag set
|
||||
SD_HOST SD_INLINE bool ArrayOptions::hasCopyOffset(const LongType *shapeInfo, int inputIndex) {
|
||||
if (inputIndex < 0 || inputIndex > 10) {
|
||||
return false;
|
||||
}
|
||||
LongType flag = copyOffsetFlagForInput(inputIndex);
|
||||
return hasPropertyBitSet(shapeInfo, flag);
|
||||
}
|
||||
|
||||
// toggleCopyOffset - toggle copy offset flag for specific input index
|
||||
SD_HOST SD_INLINE void ArrayOptions::toggleCopyOffset(LongType *shapeInfo, int inputIndex) {
|
||||
if (inputIndex < 0 || inputIndex > 10) {
|
||||
#ifndef __CUDA_ARCH__
|
||||
THROW_EXCEPTION("Input index out of range [0-10]");
|
||||
#else
|
||||
printf("Input index out of range [0-10]\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
LongType flag = copyOffsetFlagForInput(inputIndex);
|
||||
togglePropertyBit(shapeInfo, flag);
|
||||
}
|
||||
|
||||
// copyOffsetFlagForInput - get the flag constant for a specific input index
|
||||
SD_HOST SD_INLINE LongType ArrayOptions::copyOffsetFlagForInput(int inputIndex) {
|
||||
switch (inputIndex) {
|
||||
case 0: return ARRAY_COPY_OFFSET_INPUT_0;
|
||||
case 1: return ARRAY_COPY_OFFSET_INPUT_1;
|
||||
case 2: return ARRAY_COPY_OFFSET_INPUT_2;
|
||||
case 3: return ARRAY_COPY_OFFSET_INPUT_3;
|
||||
case 4: return ARRAY_COPY_OFFSET_INPUT_4;
|
||||
case 5: return ARRAY_COPY_OFFSET_INPUT_5;
|
||||
case 6: return ARRAY_COPY_OFFSET_INPUT_6;
|
||||
case 7: return ARRAY_COPY_OFFSET_INPUT_7;
|
||||
case 8: return ARRAY_COPY_OFFSET_INPUT_8;
|
||||
case 9: return ARRAY_COPY_OFFSET_INPUT_9;
|
||||
case 10: return ARRAY_COPY_OFFSET_INPUT_10;
|
||||
default:
|
||||
#ifndef __CUDA_ARCH__
|
||||
THROW_EXCEPTION("Invalid input index for copy offset flag");
|
||||
#else
|
||||
printf("Invalid input index for copy offset flag\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// clearAllCopyOffsets - clear all 11 copy offset flags at once
|
||||
SD_HOST SD_INLINE void ArrayOptions::clearAllCopyOffsets(LongType *shapeInfo) {
|
||||
for (int i = 0; i <= 10; i++) {
|
||||
LongType flag = copyOffsetFlagForInput(i);
|
||||
if (hasPropertyBitSet(shapeInfo, flag)) {
|
||||
unsetPropertyBit(shapeInfo, flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getActiveCopyOffsets - return count or bitmask of which inputs have offset flags set
|
||||
SD_HOST SD_INLINE int ArrayOptions::getActiveCopyOffsets(const LongType *shapeInfo) {
|
||||
int count = 0;
|
||||
for (int i = 0; i <= 10; i++) {
|
||||
LongType flag = copyOffsetFlagForInput(i);
|
||||
if (hasPropertyBitSet(shapeInfo, flag)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// isView - const overload for consistency
|
||||
SD_HOST SD_INLINE bool ArrayOptions::isView(const LongType *shapeInfo) {
|
||||
return hasPropertyBitSet(shapeInfo, ARRAY_IS_VIEW);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#ifndef ND4J_ARRAY_TYPE_H
|
||||
#define ND4J_ARRAY_TYPE_H
|
||||
|
||||
namespace sd {
|
||||
enum ArrayType {
|
||||
DENSE = 1,
|
||||
SPARSE = 2,
|
||||
COMPRESSED = 3,
|
||||
EMPTY = 4,
|
||||
RAGGED = 5,
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by raver119 on 21.11.17.
|
||||
//
|
||||
|
||||
#ifndef LIBND4J_BYTEORDER_H
|
||||
#define LIBND4J_BYTEORDER_H
|
||||
|
||||
namespace sd {
|
||||
enum ByteOrder {
|
||||
LE = 0,
|
||||
BE = 1,
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LIBND4J_BYTEORDER_H
|
||||
@@ -0,0 +1,36 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by raver119 on 21.11.17.
|
||||
//
|
||||
|
||||
#ifndef LIBND4J_BYTEORDERUTILS_H
|
||||
#define LIBND4J_BYTEORDERUTILS_H
|
||||
#include <array/ByteOrder.h>
|
||||
#include <graph/generated/array_generated.h>
|
||||
#include <system/common.h>
|
||||
|
||||
namespace sd {
|
||||
class SD_LIB_EXPORT ByteOrderUtils {
|
||||
public:
|
||||
static ByteOrder fromFlatByteOrder(graph::ByteOrder order);
|
||||
};
|
||||
} // namespace sd
|
||||
|
||||
#endif // LIBND4J_BYTEORDERUTILS_H
|
||||
@@ -0,0 +1,64 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
|
||||
#ifndef LIBND4J_CONSTANTDATABUFFER_H
|
||||
#define LIBND4J_CONSTANTDATABUFFER_H
|
||||
|
||||
#include <array/DataType.h>
|
||||
#include <array/PointerWrapper.h>
|
||||
#include <system/common.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace sd {
|
||||
class SD_LIB_EXPORT ConstantDataBuffer {
|
||||
private:
|
||||
std::shared_ptr<PointerWrapper> _primaryBuffer;
|
||||
std::shared_ptr<PointerWrapper> _specialBuffer = nullptr;
|
||||
uint64_t _length = 0;
|
||||
uint8_t _sizeOf = 0;
|
||||
|
||||
public:
|
||||
ConstantDataBuffer(const std::shared_ptr<PointerWrapper> &primary, uint64_t numEelements, DataType dype);
|
||||
ConstantDataBuffer(const std::shared_ptr<PointerWrapper> &primary, const std::shared_ptr<PointerWrapper> &special,
|
||||
uint64_t numEelements, DataType dype);
|
||||
ConstantDataBuffer(const ConstantDataBuffer &other);
|
||||
ConstantDataBuffer() = default;
|
||||
~ConstantDataBuffer() = default;
|
||||
|
||||
uint8_t sizeOf() const;
|
||||
uint64_t length() const;
|
||||
|
||||
void *primary() const;
|
||||
void *special() const;
|
||||
|
||||
ConstantDataBuffer &operator=(const ConstantDataBuffer &other) = default;
|
||||
ConstantDataBuffer &operator=(ConstantDataBuffer &&other) noexcept = default;
|
||||
|
||||
template <typename T>
|
||||
T *primaryAsT() const;
|
||||
|
||||
template <typename T>
|
||||
T *specialAsT() const;
|
||||
};
|
||||
} // namespace sd
|
||||
|
||||
#endif // DEV_TESTS_CONSTANTDATABUFFER_H
|
||||
@@ -0,0 +1,77 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#ifndef DEV_TESTS_CONSTANTDESCRIPTOR_H
|
||||
#define DEV_TESTS_CONSTANTDESCRIPTOR_H
|
||||
|
||||
#include <array/ConstantDataBuffer.h>
|
||||
#include <array/DataType.h>
|
||||
#include <system/common.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace sd {
|
||||
class SD_LIB_EXPORT ConstantDescriptor {
|
||||
private:
|
||||
std::vector<LongType> _integerValues;
|
||||
std::vector<double> _floatValues;
|
||||
|
||||
public:
|
||||
ConstantDescriptor(double *values, int length);
|
||||
ConstantDescriptor(LongType const *values, int length);
|
||||
ConstantDescriptor(std::initializer_list<double> values);
|
||||
|
||||
explicit ConstantDescriptor(std::vector<LongType> &values);
|
||||
explicit ConstantDescriptor(std::vector<double> &values);
|
||||
|
||||
~ConstantDescriptor() = default;
|
||||
|
||||
// equal to operator
|
||||
bool operator==(const ConstantDescriptor &other) const;
|
||||
|
||||
// less than operator
|
||||
bool operator<(const ConstantDescriptor &other) const;
|
||||
|
||||
bool isInteger() const;
|
||||
bool isFloat() const;
|
||||
|
||||
LongType length() const;
|
||||
|
||||
const std::vector<LongType> &integerValues() const;
|
||||
const std::vector<double> &floatValues() const;
|
||||
};
|
||||
} // namespace sd
|
||||
|
||||
#ifndef __JAVACPP_HACK__
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
class SD_LIB_EXPORT hash<sd::ConstantDescriptor> {
|
||||
public:
|
||||
size_t operator()(const sd::ConstantDescriptor &k) const;
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
|
||||
#endif // DEV_TESTS_CONSTANTDESCRIPTOR_H
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#ifndef LIBND4J_CONSTANTHOLDER_H
|
||||
#define LIBND4J_CONSTANTHOLDER_H
|
||||
#include <array/ConstantDataBuffer.h>
|
||||
#include <array/ConstantDescriptor.h>
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
namespace sd {
|
||||
class ConstantHolder {
|
||||
private:
|
||||
int _deviceId = 0;
|
||||
std::mutex _mutex;
|
||||
|
||||
std::map<DataType, ConstantDataBuffer> _buffers;
|
||||
|
||||
public:
|
||||
ConstantHolder(const ConstantHolder &other);
|
||||
ConstantHolder() = default;
|
||||
~ConstantHolder() = default;
|
||||
|
||||
ConstantHolder &operator=(const ConstantHolder &other) = delete;
|
||||
ConstantHolder &operator=(ConstantHolder &&other) = delete;
|
||||
|
||||
bool hasBuffer(DataType dataType);
|
||||
|
||||
template <typename T>
|
||||
bool hasBuffer();
|
||||
|
||||
void addBuffer(ConstantDataBuffer &pointer, DataType dataType);
|
||||
|
||||
template <typename T>
|
||||
void addBuffer(ConstantDataBuffer &pointer);
|
||||
|
||||
ConstantDataBuffer *getConstantDataBuffer(DataType dataType);
|
||||
|
||||
template <typename T>
|
||||
ConstantDataBuffer *getConstantDataBuffer();
|
||||
|
||||
std::mutex *mutex();
|
||||
};
|
||||
} // namespace sd
|
||||
|
||||
#endif // DEV_TESTS_CONSTANTHOLDER_H
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#ifndef SD_ARRAY_CONSTANTOFFSETSBUFFER_H_
|
||||
#define SD_ARRAY_CONSTANTOFFSETSBUFFER_H_
|
||||
|
||||
#include <array/PointerWrapper.h>
|
||||
#include <system/common.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace sd {
|
||||
|
||||
class SD_LIB_EXPORT ConstantOffsetsBuffer {
|
||||
private:
|
||||
static constexpr uint32_t MAGIC_VALID = 0xC0FFE575; // "COFFSETS" - magic number for validity check
|
||||
uint32_t _magic = 0; // Validity marker to detect use-after-free
|
||||
std::shared_ptr<PointerWrapper> _primaryOffsets;
|
||||
std::shared_ptr<PointerWrapper> _specialOffsets;
|
||||
|
||||
public:
|
||||
ConstantOffsetsBuffer(const std::shared_ptr<PointerWrapper> &primary);
|
||||
ConstantOffsetsBuffer(const std::shared_ptr<PointerWrapper> &primary, const std::shared_ptr<PointerWrapper> &special);
|
||||
ConstantOffsetsBuffer(); // Default constructor - sets magic number
|
||||
~ConstantOffsetsBuffer(); // Need custom destructor to clear magic
|
||||
|
||||
inline bool isValid() const { return _magic == MAGIC_VALID; }
|
||||
|
||||
LongType *primary();
|
||||
LongType *special();
|
||||
LongType *platform();
|
||||
};
|
||||
|
||||
} // namespace sd
|
||||
|
||||
#endif // SD_ARRAY_CONSTANTOFFSETSBUFFER_H_
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#ifndef SD_ARRAY_CONSTANTSHAPEBUFFER_H_
|
||||
#define SD_ARRAY_CONSTANTSHAPEBUFFER_H_
|
||||
|
||||
#include <array/PointerWrapper.h>
|
||||
#include <system/common.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#ifndef __JAVACPP_HACK__
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
#include <exceptions/backward.hpp>
|
||||
#endif
|
||||
#endif
|
||||
namespace sd {
|
||||
|
||||
class SD_LIB_EXPORT ConstantShapeBuffer {
|
||||
private:
|
||||
static constexpr uint32_t MAGIC_VALID = 0x58A9EB0F; // Magic number for validity check
|
||||
uint32_t _magic; // Validity marker to detect use-after-free/garbage pointers
|
||||
PointerWrapper* _primaryShapeInfo;
|
||||
PointerWrapper* _specialShapeInfo;
|
||||
std::atomic<int> _refCount;
|
||||
|
||||
|
||||
public:
|
||||
ConstantShapeBuffer( PointerWrapper* primary);
|
||||
ConstantShapeBuffer( PointerWrapper* primary, PointerWrapper* special);
|
||||
ConstantShapeBuffer();
|
||||
~ConstantShapeBuffer();
|
||||
|
||||
/**
|
||||
* Check if this buffer is valid (not garbage/use-after-free).
|
||||
* Uses magic number validation.
|
||||
*/
|
||||
inline bool isValid() const { return _magic == MAGIC_VALID; }
|
||||
#ifndef __JAVACPP_HACK__
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
backward::StackTrace st;
|
||||
#endif
|
||||
#endif
|
||||
LongType *primary() ;
|
||||
LongType *special() ;
|
||||
LongType *platform() ;
|
||||
|
||||
/**
|
||||
* Get the stack trace as a formatted string.
|
||||
* Returns empty string if functrace is not enabled.
|
||||
*/
|
||||
std::string getStackTraceAsString() const;
|
||||
|
||||
/**
|
||||
* Manual reference counting for safe cross-JNI ownership.
|
||||
* Increments reference count - call when handing out a pointer.
|
||||
*/
|
||||
void addRef();
|
||||
|
||||
/**
|
||||
* Manual reference counting for safe cross-JNI ownership.
|
||||
* Decrements reference count and deletes when reaching zero.
|
||||
* Call when done with a pointer (e.g., in deleteConstantShapeBuffer).
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Get current reference count (for debugging).
|
||||
*/
|
||||
int getRefCount() const;
|
||||
};
|
||||
|
||||
|
||||
} // namespace sd
|
||||
|
||||
#endif // SD_ARRAY_CONSTANTSHAPEBUFFER_H_
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#ifndef SD_CUDAYPOINTERDEALLOCATOR_H_
|
||||
#define SD_CUDAYPOINTERDEALLOCATOR_H_
|
||||
|
||||
#include <array/PointerDeallocator.h>
|
||||
#include <system/common.h>
|
||||
|
||||
namespace sd {
|
||||
class SD_LIB_EXPORT CudaPointerDeallocator : public PointerDeallocator {
|
||||
public:
|
||||
CudaPointerDeallocator() = default;
|
||||
~CudaPointerDeallocator() = default;
|
||||
|
||||
void release(void *ptr) override;
|
||||
};
|
||||
} // namespace sd
|
||||
|
||||
#endif // SD_CUDAYPOINTERDEALLOCATOR_H_
|
||||
@@ -0,0 +1,226 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#ifndef DEV_TESTS_DATABUFFER_H
|
||||
#define DEV_TESTS_DATABUFFER_H
|
||||
|
||||
#include <array/DataType.h>
|
||||
#include <execution/LaunchContext.h>
|
||||
#include <memory/Workspace.h>
|
||||
#include <system/common.h>
|
||||
#include <system/op_boilerplate.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
namespace sd {
|
||||
|
||||
class SD_LIB_EXPORT DataBuffer {
|
||||
private:
|
||||
// Magic number for validity checking (pattern from DirectShapeTrie validation)
|
||||
// Set in constructor, cleared in destructor, checked before use
|
||||
// Helps detect use-after-free and corrupted pointers
|
||||
static constexpr uint32_t MAGIC_NUMBER = 0xDA7ABF01; // "DA7ABF01" (DataBuffer v01)
|
||||
uint32_t _magicNumber = MAGIC_NUMBER;
|
||||
|
||||
void *_primaryBuffer = nullptr;
|
||||
void *_specialBuffer = nullptr;
|
||||
LongType _lenInBytes = 0;
|
||||
memory::Workspace *_workspace = nullptr;
|
||||
|
||||
std::atomic<int> _deviceId;
|
||||
std::mutex _deleteMutex;
|
||||
#ifndef __JAVACPP_HACK__
|
||||
#if defined(SD_CUDA)
|
||||
mutable std::atomic<LongType> _counter;
|
||||
mutable std::atomic<LongType> _writePrimary;
|
||||
mutable std::atomic<LongType> _writeSpecial;
|
||||
mutable std::atomic<LongType> _readPrimary;
|
||||
mutable std::atomic<LongType> _readSpecial;
|
||||
#endif
|
||||
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
StackTrace *allocationStackTracePrimary = nullptr;
|
||||
StackTrace *allocationStackTraceSpecial = nullptr;
|
||||
StackTrace *creationStackTrace = nullptr;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
bool closed = false;
|
||||
|
||||
// Helper template function for printing host buffer content (implementation in .cpp)
|
||||
template <typename T>
|
||||
void printHostBufferContent(void* buffer, sd::LongType offset, sd::LongType length);
|
||||
|
||||
|
||||
|
||||
void setCountersToZero();
|
||||
void copyCounters(const DataBuffer &other);
|
||||
void deleteSpecial();
|
||||
void deletePrimary();
|
||||
void deleteBuffers();
|
||||
void setAllocFlags(const bool isOwnerPrimary, const bool isOwnerSpecial = false);
|
||||
void allocateBuffers(const bool allocBoth = false);
|
||||
|
||||
void setSpecial(void *special, const bool isOwnerSpecial);
|
||||
|
||||
void copyBufferFromHost(const void *hostBuffer, size_t sizeToCopyinBytes = 0, const LongType offsetThis = 0,
|
||||
const LongType offsetHostBuffer = 0);
|
||||
|
||||
public:
|
||||
|
||||
bool _isOwnerPrimary;
|
||||
bool _isOwnerSpecial;
|
||||
bool isConstant = false;
|
||||
DataType _dataType;
|
||||
|
||||
DataBuffer(void *primary, void *special, const size_t lenInBytes, const DataType dataType,
|
||||
const bool isOwnerPrimary = false, const bool isOwnerSpecial = false,
|
||||
memory::Workspace *workspace = nullptr);
|
||||
|
||||
DataBuffer(void *primary, const size_t lenInBytes, const DataType dataType, const bool isOwnerPrimary = false,
|
||||
memory::Workspace *workspace = nullptr);
|
||||
|
||||
DataBuffer(const void *hostBuffer, // copies data from hostBuffer to own memory buffer
|
||||
const DataType dataType, const size_t lenInBytes, memory::Workspace *workspace = nullptr);
|
||||
|
||||
DataBuffer(const sd::LongType lenInBytes, const DataType dataType, memory::Workspace *workspace = nullptr,
|
||||
const bool allocBoth = false);
|
||||
|
||||
DataBuffer(const DataBuffer &other);
|
||||
DataBuffer(DataBuffer &&other);
|
||||
explicit DataBuffer();
|
||||
~DataBuffer();
|
||||
|
||||
DataBuffer &operator=(const DataBuffer &other);
|
||||
DataBuffer &operator=(DataBuffer &&other) noexcept;
|
||||
|
||||
DataType getDataType();
|
||||
void setDataType(DataType dataType);
|
||||
size_t getLenInBytes() const;
|
||||
|
||||
size_t getNumElements();
|
||||
|
||||
template <typename T>
|
||||
void *primaryAtOffset(const LongType offset);
|
||||
template <typename T>
|
||||
void *specialAtOffset(const LongType offset);
|
||||
|
||||
void *primary();
|
||||
void *special();
|
||||
void printAllocationTrace();
|
||||
|
||||
/**
|
||||
* Validate that this DataBuffer object is in a sane state.
|
||||
* Following DirectShapeTrie validation pattern: check magic number, closed flag, etc.
|
||||
* Throws exception with detailed message if validation fails.
|
||||
* Call this before accessing any member in methods that might be called
|
||||
* on dangling/corrupted pointers (like special(), primary(), etc.)
|
||||
*/
|
||||
void validateIntegrity() const;
|
||||
|
||||
void allocatePrimary();
|
||||
void allocateSpecial();
|
||||
|
||||
void writePrimary() const;
|
||||
void writeSpecial() const;
|
||||
void readPrimary() const;
|
||||
void readSpecial() const;
|
||||
bool isPrimaryActual() const;
|
||||
bool isSpecialActual() const;
|
||||
|
||||
void expand(const uint64_t size);
|
||||
|
||||
int deviceId() const;
|
||||
void setDeviceId(int deviceId);
|
||||
void migrate();
|
||||
|
||||
template <typename T>
|
||||
SD_INLINE T *primaryAsT();
|
||||
template <typename T>
|
||||
SD_INLINE T *specialAsT();
|
||||
|
||||
void markConstant(bool reallyConstant);
|
||||
|
||||
void syncToPrimary(const LaunchContext *context, const bool forceSync = false);
|
||||
void syncToSpecial(const bool forceSync = false);
|
||||
|
||||
void setToZeroBuffers(const bool both = false);
|
||||
|
||||
void copyBufferFrom(const DataBuffer &other, size_t sizeToCopyinBytes = 0, const LongType offsetThis = 0,
|
||||
const LongType offsetOther = 0);
|
||||
|
||||
|
||||
void setPrimaryBuffer(void *buffer, size_t length);
|
||||
void setSpecialBuffer(void *buffer, size_t length);
|
||||
|
||||
|
||||
void showBufferLimited();
|
||||
//for Debug purposes
|
||||
void showCounters(const char* msg1, const char* msg2);
|
||||
|
||||
/**
|
||||
* This method deletes buffers, if we're owners
|
||||
*/
|
||||
void close();
|
||||
bool isClosed() { return closed; }
|
||||
void printPrimaryAllocationStackTraces();
|
||||
void printSpecialAllocationTraces();
|
||||
DataBuffer dup();
|
||||
|
||||
/**
|
||||
* Helper method to format creation stack trace as string for error messages.
|
||||
* Returns formatted stack trace if SD_GCC_FUNCTRACE is enabled, empty string otherwise.
|
||||
*/
|
||||
std::string getCreationTraceAsString() const;
|
||||
void printHostDevice(long offset);
|
||||
static void memcpy(DataBuffer *dst, DataBuffer *src, sd::LongType startingOffset, sd::LongType dstOffset);
|
||||
/**
|
||||
* Print detailed buffer information including host and device content if available
|
||||
* @param msg - Optional message to display
|
||||
* @param offset - Starting offset for printing buffer contents
|
||||
* @param limit - Maximum number of elements to print
|
||||
*/
|
||||
#ifndef __JAVACPP_HACK__
|
||||
void printBufferDebug(const char* msg = nullptr, sd::LongType offset = 0, sd::LongType limit = 10);
|
||||
#endif
|
||||
};
|
||||
///// IMPLEMENTATION OF INLINE METHODS /////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
T *DataBuffer::primaryAsT() {
|
||||
return reinterpret_cast<T *>(_primaryBuffer);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
T *DataBuffer::specialAsT() {
|
||||
return reinterpret_cast<T *>(_specialBuffer);
|
||||
}
|
||||
|
||||
} // namespace sd
|
||||
|
||||
#endif // DEV_TESTS_DATABUFFER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#ifndef ND4J_DATATYPE_H
|
||||
#define ND4J_DATATYPE_H
|
||||
|
||||
namespace sd {
|
||||
enum DataType {
|
||||
INHERIT = 0,
|
||||
BOOL = 1,
|
||||
FLOAT8 = 2,
|
||||
HALF = 3,
|
||||
HALF2 = 4,
|
||||
FLOAT32 = 5,
|
||||
DOUBLE = 6,
|
||||
INT8 = 7,
|
||||
INT16 = 8,
|
||||
INT32 = 9,
|
||||
INT64 = 10,
|
||||
UINT8 = 11,
|
||||
UINT16 = 12,
|
||||
UINT32 = 13,
|
||||
UINT64 = 14,
|
||||
QINT8 = 15,
|
||||
QINT16 = 16,
|
||||
BFLOAT16 = 17,
|
||||
UTF8 = 50,
|
||||
UTF16 = 51,
|
||||
UTF32 = 52,
|
||||
ANY = 100,
|
||||
AUTO = 200,
|
||||
UNKNOWN = 255
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,276 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by raver119 on 21.11.17.
|
||||
//
|
||||
|
||||
#ifndef LIBND4J_DATATYPECONVERSIONS_H
|
||||
#define LIBND4J_DATATYPECONVERSIONS_H
|
||||
|
||||
#include <array/DataType.h>
|
||||
#include <execution/Threads.h>
|
||||
#include <helpers/BitwiseUtils.h>
|
||||
#include <helpers/logger.h>
|
||||
#include <loops/type_conversions.h>
|
||||
#include <system/common.h>
|
||||
#include <system/op_boilerplate.h>
|
||||
#include <types/float16.h>
|
||||
|
||||
namespace sd {
|
||||
template <typename T>
|
||||
class SD_LIB_EXPORT DataTypeConversions {
|
||||
private:
|
||||
|
||||
template <typename T2>
|
||||
static SD_INLINE void rconv(bool isBe, bool canKeep, T *buffer, LongType length, void *src) {
|
||||
if (std::is_same<T, T2>::value && canKeep) {
|
||||
// When the types match and we can keep the data as-is,
|
||||
// copy the data from src to buffer.
|
||||
ops::safe_copy(buffer, static_cast<const T*>(src), static_cast<size_t>(length));
|
||||
} else {
|
||||
// Otherwise, allocate a temporary array of type T2.
|
||||
auto tmp = new T2[length];
|
||||
ops::safe_copy(tmp, static_cast<const T2*>(src), static_cast<size_t>(length));
|
||||
|
||||
// If any conversion from T2 to T is required, perform it here.
|
||||
// For example, if T can be constructed from T2, you might do:
|
||||
// for (LongType i = 0; i < length; ++i) {
|
||||
// buffer[i] = static_cast<T>(tmp[i]);
|
||||
// }
|
||||
|
||||
// Free the temporary storage.
|
||||
delete[] tmp;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// The convertType function, modified to use safe_copy instead of direct memcpy.
|
||||
// (Assumes that T, DataType, ByteOrder, LongType, BitwiseUtils, DataTypeConversions,
|
||||
// TypeCast, PRAGMA_THREADS_FOR, samediff::Threads, sd_printf, THROW_EXCEPTION, etc.
|
||||
// are defined elsewhere in your code base.)
|
||||
static SD_INLINE void convertType(void *vbuffer, void *src, DataType dataType, ByteOrder order, LongType length) {
|
||||
auto buffer = reinterpret_cast<T *>(vbuffer);
|
||||
bool isBe = BitwiseUtils::isBE();
|
||||
bool canKeep = (isBe && order == BE) || (!isBe && order == LE);
|
||||
|
||||
switch (dataType) {
|
||||
#ifdef HAS_BOOL
|
||||
case BOOL: {
|
||||
DataTypeConversions<T>::template rconv<bool>(isBe, canKeep, buffer, length, src);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_UINT8
|
||||
case UINT8: {
|
||||
DataTypeConversions<T>::template rconv<uint8_t>(isBe, canKeep, buffer, length, src);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_INT8
|
||||
case INT8: {
|
||||
DataTypeConversions<T>::template rconv<int8_t>(isBe, canKeep, buffer, length, src);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_INT16
|
||||
case INT16: {
|
||||
DataTypeConversions<T>::template rconv<int16_t>(isBe, canKeep, buffer, length, src);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_INT32
|
||||
case INT32: {
|
||||
DataTypeConversions<T>::template rconv<int>(isBe, canKeep, buffer, length, src);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_LONG
|
||||
case INT64: {
|
||||
DataTypeConversions<T>::template rconv<LongType>(isBe, canKeep, buffer, length, src);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_FLOAT32
|
||||
case FLOAT32: {
|
||||
if (std::is_same<T, float>::value && canKeep) {
|
||||
ops::safe_copy(buffer, static_cast<const float*>(src), static_cast<size_t>(length));
|
||||
} else {
|
||||
auto tmp = new float[length];
|
||||
ops::safe_copy(tmp, static_cast<const float*>(src), static_cast<size_t>(length));
|
||||
|
||||
#if __GNUC__ <= 4
|
||||
if (!canKeep) {
|
||||
for (sd::LongType e = 0; e < length; e++)
|
||||
buffer[e] = BitwiseUtils::swap_bytes<T>(static_cast<T>(tmp[e]));
|
||||
} else {
|
||||
TypeCast::convertGeneric<float, T>(nullptr, tmp, length, buffer);
|
||||
}
|
||||
#else
|
||||
auto func = PRAGMA_THREADS_FOR {
|
||||
for (auto e = start; e < stop; e++)
|
||||
buffer[e] = canKeep
|
||||
? static_cast<T>(tmp[e])
|
||||
: BitwiseUtils::swap_bytes<T>(static_cast<T>(tmp[e]));
|
||||
};
|
||||
samediff::Threads::parallel_for(func, 0, length);
|
||||
#endif
|
||||
delete[] tmp;
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DOUBLE
|
||||
case DOUBLE: {
|
||||
if (std::is_same<T, double>::value && canKeep) {
|
||||
ops::safe_copy(buffer, static_cast<const double*>(src), static_cast<size_t>(length));
|
||||
} else {
|
||||
auto tmp = new double[length];
|
||||
ops::safe_copy(tmp, static_cast<const double*>(src), static_cast<size_t>(length));
|
||||
|
||||
#if __GNUC__ <= 4
|
||||
if (!canKeep) {
|
||||
for (sd::LongType e = 0; e < length; e++)
|
||||
buffer[e] = BitwiseUtils::swap_bytes<T>(static_cast<T>(tmp[e]));
|
||||
} else {
|
||||
TypeCast::convertGeneric<double, T>(nullptr, tmp, length, buffer);
|
||||
}
|
||||
#else
|
||||
auto func = PRAGMA_THREADS_FOR {
|
||||
for (auto e = start; e < stop; e++)
|
||||
buffer[e] = canKeep
|
||||
? static_cast<T>(tmp[e])
|
||||
: BitwiseUtils::swap_bytes<T>(static_cast<T>(tmp[e]));
|
||||
};
|
||||
samediff::Threads::parallel_for(func, 0, length);
|
||||
#endif
|
||||
delete[] tmp;
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_FLOAT16
|
||||
case HALF: {
|
||||
if (std::is_same<T, float16>::value && canKeep) {
|
||||
ops::safe_copy(buffer, static_cast<const float16*>(src), static_cast<size_t>(length));
|
||||
} else {
|
||||
auto tmp = new float16[length];
|
||||
ops::safe_copy(tmp, static_cast<const float16*>(src), static_cast<size_t>(length));
|
||||
|
||||
#if __GNUC__ <= 4
|
||||
if (!canKeep) {
|
||||
for (sd::LongType e = 0; e < length; e++)
|
||||
buffer[e] = BitwiseUtils::swap_bytes<T>(static_cast<T>(tmp[e]));
|
||||
} else {
|
||||
TypeCast::convertGeneric<float16, T>(nullptr, tmp, length, buffer);
|
||||
}
|
||||
#else
|
||||
auto func = PRAGMA_THREADS_FOR {
|
||||
for (auto e = start; e < stop; e++)
|
||||
buffer[e] = canKeep
|
||||
? static_cast<T>(tmp[e])
|
||||
: BitwiseUtils::swap_bytes<T>(static_cast<T>(tmp[e]));
|
||||
};
|
||||
samediff::Threads::parallel_for(func, 0, length);
|
||||
#endif
|
||||
delete[] tmp;
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_BFLOAT16
|
||||
case BFLOAT16: {
|
||||
if (std::is_same<T, bfloat16>::value && canKeep) {
|
||||
ops::safe_copy(buffer, static_cast<const bfloat16*>(src), static_cast<size_t>(length));
|
||||
} else {
|
||||
auto tmp = new bfloat16[length];
|
||||
ops::safe_copy(tmp, static_cast<const bfloat16*>(src), static_cast<size_t>(length));
|
||||
|
||||
#if __GNUC__ <= 4
|
||||
if (!canKeep) {
|
||||
for (sd::LongType e = 0; e < length; e++)
|
||||
buffer[e] = BitwiseUtils::swap_bytes<T>(static_cast<T>(tmp[e]));
|
||||
} else {
|
||||
TypeCast::convertGeneric<bfloat16, T>(nullptr, tmp, length, buffer);
|
||||
}
|
||||
#else
|
||||
auto func = PRAGMA_THREADS_FOR {
|
||||
for (auto e = start; e < stop; e++)
|
||||
buffer[e] = canKeep
|
||||
? static_cast<T>(tmp[e])
|
||||
: BitwiseUtils::swap_bytes<T>(static_cast<T>(tmp[e]));
|
||||
};
|
||||
samediff::Threads::parallel_for(func, 0, length);
|
||||
#endif
|
||||
delete[] tmp;
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_UINT16
|
||||
case UINT16: {
|
||||
DataTypeConversions<T>::template rconv<uint16_t>(isBe, canKeep, buffer, length, src);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_UINT32
|
||||
case UINT32: {
|
||||
DataTypeConversions<T>::template rconv<uint32_t>(isBe, canKeep, buffer, length, src);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_UNSIGNEDLONG
|
||||
case UINT64: {
|
||||
DataTypeConversions<T>::template rconv<uint64_t>(isBe, canKeep, buffer, length, src);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_UTF8
|
||||
case UTF8: {
|
||||
// UTF8 handling would go here if needed
|
||||
sd_print("UTF8 DataType conversion not implemented\n");
|
||||
THROW_EXCEPTION("UTF8 DataType conversion not implemented");
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_UTF16
|
||||
case UTF16: {
|
||||
// UTF16 handling would go here if needed
|
||||
sd_print("UTF16 DataType conversion not implemented\n");
|
||||
THROW_EXCEPTION("UTF16 DataType conversion not implemented");
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_UTF32
|
||||
case UTF32: {
|
||||
// UTF32 handling would go here if needed
|
||||
sd_print("UTF32 DataType conversion not implemented\n");
|
||||
THROW_EXCEPTION("UTF32 DataType conversion not implemented");
|
||||
} break;
|
||||
#endif
|
||||
|
||||
default: {
|
||||
sd_printf("Unsupported DataType requested: [%i]\n", static_cast<int>(dataType));
|
||||
THROW_EXCEPTION("Unsupported DataType");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace sd
|
||||
|
||||
#endif // LIBND4J_DATATYPECONVERSIONS_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,394 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Implementation of robust data type validation and error reporting
|
||||
//
|
||||
|
||||
#include <array/DataType.h>
|
||||
#include <array/DataTypeValidation.h>
|
||||
#include <exceptions/allocation_exception.h>
|
||||
#include <system/op_enums.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "system/op_boilerplate.h"
|
||||
#include <helpers/logger.h>
|
||||
namespace sd {
|
||||
|
||||
// Static member definitions
|
||||
std::unordered_set<DataType> DataTypeValidation::compiledTypes_;
|
||||
std::unordered_map<DataType, std::string> DataTypeValidation::typeNames_;
|
||||
std::unordered_map<int, DataType> DataTypeValidation::enumMapping_;
|
||||
bool DataTypeValidation::initialized_ = false;
|
||||
|
||||
void DataTypeValidation::initialize() {
|
||||
if (initialized_) return;
|
||||
|
||||
populateTypeNames();
|
||||
populateCompiledTypes();
|
||||
|
||||
// Build enum ID to DataType mapping
|
||||
for (const auto& pair : typeNames_) {
|
||||
enumMapping_[static_cast<int>(pair.first)] = pair.first;
|
||||
}
|
||||
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
void DataTypeValidation::initializeIfNeeded() {
|
||||
if (!initialized_) {
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
|
||||
void DataTypeValidation::populateTypeNames() {
|
||||
if (initialized_) return;
|
||||
|
||||
// All possible data types defined in DataType enum
|
||||
typeNames_[DataType::INHERIT] = "INHERIT";
|
||||
typeNames_[DataType::BOOL] = "BOOL";
|
||||
typeNames_[DataType::FLOAT8] = "FLOAT8";
|
||||
typeNames_[DataType::HALF] = "HALF";
|
||||
typeNames_[DataType::HALF2] = "HALF2";
|
||||
typeNames_[DataType::FLOAT32] = "FLOAT32";
|
||||
typeNames_[DataType::DOUBLE] = "DOUBLE";
|
||||
typeNames_[DataType::INT8] = "INT8";
|
||||
typeNames_[DataType::INT16] = "INT16";
|
||||
typeNames_[DataType::INT32] = "INT32";
|
||||
typeNames_[DataType::INT64] = "INT64";
|
||||
typeNames_[DataType::UINT8] = "UINT8";
|
||||
typeNames_[DataType::UINT16] = "UINT16";
|
||||
typeNames_[DataType::UINT32] = "UINT32";
|
||||
typeNames_[DataType::UINT64] = "UINT64";
|
||||
typeNames_[DataType::QINT8] = "QINT8";
|
||||
typeNames_[DataType::QINT16] = "QINT16";
|
||||
typeNames_[DataType::BFLOAT16] = "BFLOAT16";
|
||||
typeNames_[DataType::UTF8] = "UTF8";
|
||||
typeNames_[DataType::UTF16] = "UTF16";
|
||||
typeNames_[DataType::UTF32] = "UTF32";
|
||||
typeNames_[DataType::UNKNOWN] = "UNKNOWN";
|
||||
}
|
||||
void DataTypeValidation::populateCompiledTypes() {
|
||||
if (initialized_) return;
|
||||
|
||||
// Auto-register types based on compile-time flags
|
||||
// This mirrors the logic from the CMake type system
|
||||
|
||||
// Boolean type
|
||||
#if defined(HAS_BOOL)
|
||||
registerCompiledType(DataType::BOOL, "BOOL");
|
||||
#endif
|
||||
|
||||
// Floating point types - check both CMake-generated and alias defines
|
||||
#if defined(HAS_FLOAT) || defined(HAS_FLOAT32)
|
||||
registerCompiledType(DataType::FLOAT32, "FLOAT32");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_DOUBLE) || defined(HAS_FLOAT64)
|
||||
registerCompiledType(DataType::DOUBLE, "DOUBLE");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_FLOAT16) || defined(HAS_HALF)
|
||||
registerCompiledType(DataType::HALF, "HALF");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_BFLOAT16) || defined(HAS_BFLOAT)
|
||||
registerCompiledType(DataType::BFLOAT16, "BFLOAT16");
|
||||
#endif
|
||||
|
||||
// Integer types - check both normalized (_T) and alias forms
|
||||
#if defined(HAS_INT8_T) || defined(HAS_INT8)
|
||||
registerCompiledType(DataType::INT8, "INT8");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_INT16_T) || defined(HAS_INT16)
|
||||
registerCompiledType(DataType::INT16, "INT16");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_INT32_T) || defined(HAS_INT32) || defined(HAS_INT)
|
||||
registerCompiledType(DataType::INT32, "INT32");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_INT64_T) || defined(HAS_INT64) || defined(HAS_LONG)
|
||||
registerCompiledType(DataType::INT64, "INT64");
|
||||
#endif
|
||||
|
||||
// Unsigned integer types
|
||||
#if defined(HAS_UINT8_T) || defined(HAS_UINT8)
|
||||
registerCompiledType(DataType::UINT8, "UINT8");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_UINT16_T) || defined(HAS_UINT16)
|
||||
registerCompiledType(DataType::UINT16, "UINT16");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_UINT32_T) || defined(HAS_UINT32)
|
||||
registerCompiledType(DataType::UINT32, "UINT32");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_UINT64_T) || defined(HAS_UINT64) || defined(HAS_UNSIGNEDLONG)
|
||||
registerCompiledType(DataType::UINT64, "UINT64");
|
||||
#endif
|
||||
|
||||
// String types - only if string operations are enabled
|
||||
#if defined(SD_ENABLE_STRING_OPERATIONS)
|
||||
#if defined(HAS_STD_STRING) || defined(HAS_UTF8)
|
||||
registerCompiledType(DataType::UTF8, "UTF8");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_STD_U16STRING) || defined(HAS_UTF16)
|
||||
registerCompiledType(DataType::UTF16, "UTF16");
|
||||
#endif
|
||||
|
||||
#if defined(HAS_STD_U32STRING) || defined(HAS_UTF32)
|
||||
registerCompiledType(DataType::UTF32, "UTF32");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void DataTypeValidation::registerCompiledType(DataType type, const std::string& name) {
|
||||
compiledTypes_.insert(type);
|
||||
typeNames_[type] = name;
|
||||
}
|
||||
|
||||
bool DataTypeValidation::isValidDataType(DataType dataType) {
|
||||
initializeIfNeeded();
|
||||
return typeNames_.find(dataType) != typeNames_.end();
|
||||
}
|
||||
|
||||
bool DataTypeValidation::isValidDataType(int dataTypeId) {
|
||||
initializeIfNeeded();
|
||||
return enumMapping_.find(dataTypeId) != enumMapping_.end();
|
||||
}
|
||||
|
||||
std::vector<DataType> DataTypeValidation::getAvailableDataTypes() {
|
||||
initializeIfNeeded();
|
||||
std::vector<DataType> result;
|
||||
result.reserve(compiledTypes_.size());
|
||||
for (const auto& type : compiledTypes_) {
|
||||
result.push_back(type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DataTypeValidation::isCompiledDataType(DataType dataType) {
|
||||
initializeIfNeeded();
|
||||
return compiledTypes_.find(dataType) != compiledTypes_.end();
|
||||
}
|
||||
|
||||
std::string DataTypeValidation::getDataTypeErrorMessage(int dataTypeId, const char* context) {
|
||||
initializeIfNeeded();
|
||||
|
||||
std::ostringstream oss;
|
||||
|
||||
if (!isValidDataType(dataTypeId)) {
|
||||
oss << "Invalid data type ID: " << dataTypeId << " (not a valid enum value)";
|
||||
} else {
|
||||
DataType dt = enumMapping_[dataTypeId];
|
||||
const char* typeName = getDataTypeName(dt);
|
||||
|
||||
if (!isCompiledDataType(dt)) {
|
||||
oss << "Data type " << typeName << " (ID: " << dataTypeId
|
||||
<< ") is not available in this build";
|
||||
} else {
|
||||
oss << "Unexpected error with data type " << typeName
|
||||
<< " (ID: " << dataTypeId << ") - type is valid and compiled";
|
||||
}
|
||||
}
|
||||
|
||||
if (context) {
|
||||
oss << "\nContext: " << context;
|
||||
}
|
||||
|
||||
// Add build configuration info with better diagnosis
|
||||
#if defined(SD_SELECTIVE_TYPES)
|
||||
oss << "\nBuild configuration: Selective types enabled";
|
||||
|
||||
// List the define flags that would enable missing types
|
||||
if (isValidDataType(dataTypeId)) {
|
||||
DataType dt = enumMapping_[dataTypeId];
|
||||
if (!isCompiledDataType(dt)) {
|
||||
const char* typeName = getDataTypeName(dt);
|
||||
oss << "\nTo enable this type, rebuild with the type included in SD_TYPES_LIST";
|
||||
oss << "\nExample: cmake -DSD_TYPES_LIST=\"float32;int32;int64;" << typeName << "\" ..";
|
||||
}
|
||||
}
|
||||
#else
|
||||
oss << "\nBuild configuration: All types enabled (SD_SELECTIVE_TYPES not defined)";
|
||||
oss << "\nThis error suggests a build system configuration issue.";
|
||||
#endif
|
||||
|
||||
// Add available types
|
||||
auto availableTypes = getAvailableDataTypes();
|
||||
if (!availableTypes.empty()) {
|
||||
oss << "\nAvailable types in this build (" << availableTypes.size() << "): ";
|
||||
for (size_t i = 0; i < availableTypes.size(); ++i) {
|
||||
if (i > 0) oss << ", ";
|
||||
oss << getDataTypeName(availableTypes[i]);
|
||||
}
|
||||
} else {
|
||||
oss << "\nCRITICAL: No data types are available in this build!";
|
||||
oss << "\nThis indicates a serious build configuration problem.";
|
||||
|
||||
// Debug information to help diagnose the issue
|
||||
oss << "\nDiagnostic information:";
|
||||
oss << "\n Total possible types: " << typeNames_.size();
|
||||
oss << "\n Compiled types: " << compiledTypes_.size();
|
||||
|
||||
// Show which defines are actually set
|
||||
oss << "\n Active defines:";
|
||||
#if defined(HAS_BOOL)
|
||||
oss << " HAS_BOOL";
|
||||
#endif
|
||||
#if defined(HAS_FLOAT)
|
||||
oss << " HAS_FLOAT";
|
||||
#endif
|
||||
#if defined(HAS_FLOAT32)
|
||||
oss << " HAS_FLOAT32";
|
||||
#endif
|
||||
#if defined(HAS_DOUBLE)
|
||||
oss << " HAS_DOUBLE";
|
||||
#endif
|
||||
#if defined(HAS_INT32_T)
|
||||
oss << " HAS_INT32_T";
|
||||
#endif
|
||||
#if defined(HAS_INT32)
|
||||
oss << " HAS_INT32";
|
||||
#endif
|
||||
#if defined(HAS_INT)
|
||||
oss << " HAS_INT";
|
||||
#endif
|
||||
#if defined(HAS_INT64_T)
|
||||
oss << " HAS_INT64_T";
|
||||
#endif
|
||||
#if defined(HAS_LONG)
|
||||
oss << " HAS_LONG";
|
||||
#endif
|
||||
#if defined(SD_SELECTIVE_TYPES)
|
||||
oss << " SD_SELECTIVE_TYPES";
|
||||
#endif
|
||||
|
||||
if (compiledTypes_.empty()) {
|
||||
oss << "\n No type defines matched - check CMake type generation";
|
||||
}
|
||||
}
|
||||
|
||||
// Add suggestions based on the situation
|
||||
if (!isValidDataType(dataTypeId)) {
|
||||
oss << "\nSuggestion: Check NDArray creation and data type initialization";
|
||||
} else if (availableTypes.empty()) {
|
||||
oss << "\nSuggestion: Check CMake build configuration and type define generation";
|
||||
oss << "\nVerify that setup_type_definitions() was called in CMake";
|
||||
} else {
|
||||
oss << "\nSuggestion: Use one of the available types or rebuild with the required type enabled";
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
const char* DataTypeValidation::getDataTypeName(DataType dataType) {
|
||||
initializeIfNeeded();
|
||||
auto it = typeNames_.find(dataType);
|
||||
return (it != typeNames_.end()) ? it->second.c_str() : "UNKNOWN";
|
||||
}
|
||||
|
||||
std::string DataTypeValidation::getBuildInfo() {
|
||||
initializeIfNeeded();
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << "=== DATA TYPE VALIDATION BUILD INFO ===\n";
|
||||
|
||||
#if defined(SD_SELECTIVE_TYPES)
|
||||
oss << "Build type: Selective types (SD_SELECTIVE_TYPES defined)\n";
|
||||
#else
|
||||
oss << "Build type: All types (SD_SELECTIVE_TYPES not defined)\n";
|
||||
#endif
|
||||
|
||||
oss << "Total possible types: " << typeNames_.size() << "\n";
|
||||
oss << "Compiled types: " << compiledTypes_.size() << "\n";
|
||||
|
||||
if (!compiledTypes_.empty()) {
|
||||
oss << "Available types: ";
|
||||
auto types = getAvailableDataTypes();
|
||||
for (size_t i = 0; i < types.size(); ++i) {
|
||||
if (i > 0) oss << ", ";
|
||||
oss << getDataTypeName(types[i]);
|
||||
}
|
||||
oss << "\n";
|
||||
} else {
|
||||
oss << "CRITICAL: No types compiled!\n";
|
||||
oss << "This indicates a build configuration error.\n";
|
||||
|
||||
// Show active defines for debugging
|
||||
oss << "Active defines:";
|
||||
#if defined(HAS_BOOL)
|
||||
oss << " HAS_BOOL";
|
||||
#endif
|
||||
#if defined(HAS_FLOAT)
|
||||
oss << " HAS_FLOAT";
|
||||
#endif
|
||||
#if defined(HAS_FLOAT32)
|
||||
oss << " HAS_FLOAT32";
|
||||
#endif
|
||||
#if defined(HAS_DOUBLE)
|
||||
oss << " HAS_DOUBLE";
|
||||
#endif
|
||||
#if defined(HAS_INT32_T)
|
||||
oss << " HAS_INT32_T";
|
||||
#endif
|
||||
#if defined(HAS_INT32)
|
||||
oss << " HAS_INT32";
|
||||
#endif
|
||||
#if defined(HAS_INT)
|
||||
oss << " HAS_INT";
|
||||
#endif
|
||||
#if defined(HAS_INT64_T)
|
||||
oss << " HAS_INT64_T";
|
||||
#endif
|
||||
#if defined(HAS_LONG)
|
||||
oss << " HAS_LONG";
|
||||
#endif
|
||||
|
||||
if (compiledTypes_.empty()) {
|
||||
oss << "\nNo defines matched - check CMake setup_type_definitions()";
|
||||
}
|
||||
}
|
||||
|
||||
oss << "==========================================\n";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// DataTypeValidator implementation
|
||||
void DataTypeValidator::validateOrThrow() {
|
||||
if (!DataTypeValidation::isValidDataType(dataType_)) {
|
||||
std::string errorMsg = DataTypeValidation::getDataTypeErrorMessage(
|
||||
static_cast<int>(dataType_), context_.c_str());
|
||||
THROW_EXCEPTION(errorMsg.c_str());
|
||||
}
|
||||
|
||||
if (!DataTypeValidation::isCompiledDataType(dataType_)) {
|
||||
std::string errorMsg = DataTypeValidation::getDataTypeErrorMessage(
|
||||
dataType_, context_.c_str());
|
||||
THROW_EXCEPTION(errorMsg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sd
|
||||
@@ -0,0 +1,156 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created for robust data type validation and error reporting
|
||||
//
|
||||
|
||||
#ifndef ND4J_DATATYPE_VALIDATION_H
|
||||
#define ND4J_DATATYPE_VALIDATION_H
|
||||
|
||||
#include <array/DataType.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <system/common.h>
|
||||
|
||||
namespace sd {
|
||||
|
||||
/**
|
||||
* Comprehensive data type validation and error reporting system
|
||||
*
|
||||
* This class provides robust validation for data types, distinguishing between:
|
||||
* - Invalid data type IDs (not in enum)
|
||||
* - Valid but uncompiled data types (selective builds)
|
||||
* - Runtime vs compile-time mismatches
|
||||
*/
|
||||
class SD_LIB_EXPORT DataTypeValidation {
|
||||
private:
|
||||
static std::unordered_set<DataType> compiledTypes_;
|
||||
static std::unordered_map<DataType, std::string> typeNames_;
|
||||
static std::unordered_map<int, DataType> enumMapping_;
|
||||
static bool initialized_;
|
||||
|
||||
static void initializeIfNeeded();
|
||||
static void populateTypeNames();
|
||||
static void populateCompiledTypes();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initialize the validation system (called automatically)
|
||||
*/
|
||||
static void initialize();
|
||||
|
||||
/**
|
||||
* Check if a data type enum value is valid
|
||||
* @param dataType The data type to check
|
||||
* @return true if the data type exists in the enum
|
||||
*/
|
||||
static bool isValidDataType(DataType dataType);
|
||||
|
||||
/**
|
||||
* Check if a numeric data type ID is valid
|
||||
* @param dataTypeId The numeric data type ID to check
|
||||
* @return true if the ID maps to a valid enum value
|
||||
*/
|
||||
static bool isValidDataType(int dataTypeId);
|
||||
|
||||
/**
|
||||
* Check if a data type is compiled into this build
|
||||
* @param dataType The data type to check
|
||||
* @return true if the type is available in this binary
|
||||
*/
|
||||
static bool isCompiledDataType(DataType dataType);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get a descriptive error message for numeric data type ID
|
||||
* @param dataTypeId The problematic data type ID
|
||||
* @param context Context string (function name, etc.)
|
||||
* @return Detailed error message with suggestions
|
||||
*/
|
||||
static std::string getDataTypeErrorMessage(int dataTypeId, const char* context);
|
||||
|
||||
/**
|
||||
* Get list of available data types in this build
|
||||
* @return Vector of compiled data types
|
||||
*/
|
||||
static std::vector<DataType> getAvailableDataTypes();
|
||||
|
||||
/**
|
||||
* Get human-readable name for data type
|
||||
* @param dataType The data type
|
||||
* @return String name (e.g., "FLOAT32", "INT64")
|
||||
*/
|
||||
static const char* getDataTypeName(DataType dataType);
|
||||
|
||||
/**
|
||||
* Get build configuration information
|
||||
* @return String describing the build configuration and available types
|
||||
*/
|
||||
static std::string getBuildInfo();
|
||||
|
||||
/**
|
||||
* Register a compiled data type (used internally by build system)
|
||||
* @param type The data type to register
|
||||
* @param name Human-readable name
|
||||
*/
|
||||
static void registerCompiledType(DataType type, const std::string& name);
|
||||
};
|
||||
|
||||
/**
|
||||
* RAII helper for data type validation in critical paths
|
||||
*
|
||||
* Usage:
|
||||
* DataTypeValidator validator(myDataType, "MyFunction::myMethod()");
|
||||
* // Will throw if data type is invalid or not compiled
|
||||
*/
|
||||
class SD_LIB_EXPORT DataTypeValidator {
|
||||
private:
|
||||
DataType dataType_;
|
||||
std::string context_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor that validates the data type
|
||||
* @param dt Data type to validate
|
||||
* @param context Context for error messages
|
||||
* @throws std::exception if validation fails
|
||||
*/
|
||||
DataTypeValidator(DataType dt, const std::string& context)
|
||||
: dataType_(dt), context_(context) {
|
||||
validateOrThrow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform validation and throw if invalid
|
||||
* @throws std::exception with detailed error message
|
||||
*/
|
||||
void validateOrThrow();
|
||||
|
||||
/**
|
||||
* Get the validated data type
|
||||
* @return The data type (guaranteed to be valid and compiled)
|
||||
*/
|
||||
DataType getDataType() const { return dataType_; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ND4J_DATATYPE_VALIDATION_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user