diff --git a/sycl/cmake/modules/BuildUnifiedRuntime.cmake b/sycl/cmake/modules/BuildUnifiedRuntime.cmake index c1a942c9de9e2..0822da8d4da0b 100644 --- a/sycl/cmake/modules/BuildUnifiedRuntime.cmake +++ b/sycl/cmake/modules/BuildUnifiedRuntime.cmake @@ -92,6 +92,15 @@ add_subdirectory(${UNIFIED_RUNTIME_SOURCE_DIR} ${UR_INTREE_BINARY_DIR}) # Restore original flags set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_BAK}") +if(WIN32 AND UR_STATIC_LOADER) + foreach(_ur_static_target ur_loader ur_common) + if(TARGET ${_ur_static_target}) + set_target_properties(${_ur_static_target} PROPERTIES + MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") + endif() + endforeach() +endif() + set(UNIFIED_RUNTIME_INCLUDE_DIR "${UNIFIED_RUNTIME_SOURCE_DIR}/include") set(UNIFIED_RUNTIME_SRC_INCLUDE_DIR "${UNIFIED_RUNTIME_SOURCE_DIR}/source") set(UNIFIED_RUNTIME_COMMON_INCLUDE_DIR "${UNIFIED_RUNTIME_SOURCE_DIR}/source/common") @@ -223,6 +232,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL Windows) -DUR_BUILD_ADAPTER_CUDA:BOOL=${UR_BUILD_ADAPTER_CUDA} -DUR_BUILD_ADAPTER_HIP:BOOL=${UR_BUILD_ADAPTER_HIP} -DUR_BUILD_ADAPTER_NATIVE_CPU:BOOL=${UR_BUILD_ADAPTER_NATIVE_CPU} + -DUR_STATIC_LOADER:BOOL=${UR_STATIC_LOADER} -DUMF_BUILD_EXAMPLES:BOOL=${UMF_BUILD_EXAMPLES} -DUMF_BUILD_SHARED_LIBRARY:BOOL=${UMF_BUILD_SHARED_LIBRARY} -DUMF_LINK_HWLOC_STATICALLY:BOOL=${UMF_LINK_HWLOC_STATICALLY} @@ -261,6 +271,9 @@ if(CMAKE_SYSTEM_NAME STREQUAL Windows) endmacro() urd_copy_library_to_build(ur_loaderd "NOT;${UR_STATIC_LOADER}") + if(UR_STATIC_LOADER) + urd_copy_library_to_build(ur_commond FALSE) + endif() foreach(adatper ${SYCL_ENABLE_BACKENDS}) if(adapter MATCHES "level_zero") set(shared "NOT;${UR_STATIC_ADAPTER_L0}") @@ -276,9 +289,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL Windows) add_dependencies(unified-runtimed-build unified-runtimed) # Add the debug UR runtime libraries to the parent install. - install( - FILES ${URD_INSTALL_DIR}/bin/ur_loaderd.dll - DESTINATION "bin" COMPONENT unified-runtime-loader) + if(NOT UR_STATIC_LOADER) + install( + FILES ${URD_INSTALL_DIR}/bin/ur_loaderd.dll + DESTINATION "bin" COMPONENT unified-runtime-loader) + endif() foreach(adapter ${SYCL_ENABLE_BACKENDS}) install( FILES ${URD_INSTALL_DIR}/bin/ur_adapter_${adapter}d.dll diff --git a/sycl/include/sycl/detail/ur.hpp b/sycl/include/sycl/detail/ur.hpp index 9f4473d95f89d..4ca93327f943d 100644 --- a/sycl/include/sycl/detail/ur.hpp +++ b/sycl/include/sycl/detail/ur.hpp @@ -60,7 +60,7 @@ struct UrFuncPtrMapT { template struct UrFuncInfo {}; -#ifdef _WIN32 +#if defined(_WIN32) && !defined(SYCL_UR_STATIC_LOADER) void *GetWinProcAddress(void *module, const char *funcName); inline void PopulateUrFuncPtrTable(UrFuncPtrMapT *funcs, void *module) { #define _UR_API(api) \ diff --git a/sycl/source/CMakeLists.txt b/sycl/source/CMakeLists.txt index d197381a1a307..34cc74b8cf65d 100644 --- a/sycl/source/CMakeLists.txt +++ b/sycl/source/CMakeLists.txt @@ -67,6 +67,7 @@ function(add_sycl_rt_library LIB_NAME LIB_OBJ_NAME) SYCL2020_DISABLE_DEPRECATION_WARNINGS __SYCL_DISABLE_DEPRECATION_WARNINGS $<$:__SYCL_BUILD_SYCL_DLL> + $<$:SYCL_UR_STATIC_LOADER> ) target_include_directories( @@ -97,11 +98,24 @@ function(add_sycl_rt_library LIB_NAME LIB_OBJ_NAME) find_package(Threads REQUIRED) + if(WIN32 AND UR_STATIC_LOADER AND WIN_DUPE) + # sycld is /MDd; link against the debug static UR libs produced by the + # unified-runtimed subbuild instead of the release UnifiedRuntimeLoader. + set(_sycl_ur_loader_lib + ${LLVM_BINARY_DIR}/lib/ur_loaderd.lib + ${LLVM_BINARY_DIR}/lib/ur_commond.lib + dbghelp) + elseif(NOT WIN32 OR UR_STATIC_LOADER) + set(_sycl_ur_loader_lib UnifiedRuntimeLoader) + else() + set(_sycl_ur_loader_lib "") + endif() + target_link_libraries(${LIB_NAME} PRIVATE ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} - $<$>:UnifiedRuntimeLoader> + ${_sycl_ur_loader_lib} $<$:shlwapi> ) diff --git a/sycl/source/detail/adapter_impl.hpp b/sycl/source/detail/adapter_impl.hpp index f5bc9fff098bf..293d17574d483 100644 --- a/sycl/source/detail/adapter_impl.hpp +++ b/sycl/source/detail/adapter_impl.hpp @@ -54,7 +54,7 @@ class adapter_impl { : MAdapter(adapter), MBackend(UseBackend), MAdapterMutex(std::make_shared()) { -#ifdef _WIN32 +#if defined(_WIN32) && !defined(SYCL_UR_STATIC_LOADER) UrLoaderHandle = ur::getURLoaderLibrary(); PopulateUrFuncPtrTable(&UrFuncPtrs, UrLoaderHandle); #endif diff --git a/sycl/source/detail/global_handler.cpp b/sycl/source/detail/global_handler.cpp index 25b96c80e41d7..ce26d8b5ee3e7 100644 --- a/sycl/source/detail/global_handler.cpp +++ b/sycl/source/detail/global_handler.cpp @@ -278,10 +278,14 @@ void GlobalHandler::unloadAdapters() { } } +#ifdef SYCL_UR_STATIC_LOADER + urLoaderTearDown(); +#else UrFuncInfo loaderTearDownInfo; auto loaderTearDown = loaderTearDownInfo.getFuncPtrFromModule(ur::getURLoaderLibrary()); loaderTearDown(); +#endif // urLoaderTearDown(); // Clear after unload to avoid uses after unload. diff --git a/sycl/source/detail/ur.cpp b/sycl/source/detail/ur.cpp index 6b3ce7c5c945c..329e5179cb581 100644 --- a/sycl/source/detail/ur.cpp +++ b/sycl/source/detail/ur.cpp @@ -133,6 +133,17 @@ static void initializeAdapters(std::vector &Adapters, } #endif +#ifdef SYCL_UR_STATIC_LOADER + auto loaderConfigCreate = &urLoaderConfigCreate; + auto loaderConfigEnableLayer = &urLoaderConfigEnableLayer; + auto loaderConfigRelease = &urLoaderConfigRelease; + auto loaderConfigSetCodeLocationCallback = + &urLoaderConfigSetCodeLocationCallback; + auto loaderInit = &urLoaderInit; + auto adapterGet = &urAdapterGet; + auto adapterGetInfo = &urAdapterGetInfo; + auto adapterSetLoggerCallback = &urAdapterSetLoggerCallback; +#else UrFuncInfo loaderConfigCreateInfo; auto loaderConfigCreate = loaderConfigCreateInfo.getFuncPtrFromModule(ur::getURLoaderLibrary()); @@ -162,6 +173,7 @@ static void initializeAdapters(std::vector &Adapters, auto adapterSetLoggerCallback = adapterSetLoggerCallbackInfo.getFuncPtrFromModule( ur::getURLoaderLibrary()); +#endif bool OwnLoaderConfig = false; // If we weren't provided with a custom config handle create our own. diff --git a/unified-runtime/CMakeLists.txt b/unified-runtime/CMakeLists.txt index 00e73e9d26ed2..d2cb05fc3f5ee 100644 --- a/unified-runtime/CMakeLists.txt +++ b/unified-runtime/CMakeLists.txt @@ -52,7 +52,8 @@ option(UR_BUILD_EXAMPLE_CODEGEN "Build the codegen example." OFF) option(VAL_USE_LIBBACKTRACE_BACKTRACE "enable libbacktrace validation backtrace for linux" OFF) option(UR_ENABLE_ASSERTIONS "Enable assertions for all build types" OFF) option(UR_BUILD_XPTI_LIBS "Build the XPTI libraries when tracing is enabled" ON) -option(UR_STATIC_LOADER "Build loader as a static library" OFF) +option(UR_STATIC_LOADER "Build loader as a static library" ON) +option(UR_ADAPTER_SEARCH_LOADER_DIR_FIRST "Prefer loader library directory over OS search paths when discovering adapters" ON) option(UR_FORCE_LIBSTDCXX "Force use of libstdc++ in a build using libc++ on Linux" OFF) option(UR_ENABLE_LATENCY_HISTOGRAM "Enable latncy histogram" OFF) option(UR_FORCE_FETCH_LEVEL_ZERO "Force fetching Level Zero even if preinstalled loader is found" OFF) diff --git a/unified-runtime/source/common/CMakeLists.txt b/unified-runtime/source/common/CMakeLists.txt index 7a11da6fc4da5..93e3562ef12b2 100644 --- a/unified-runtime/source/common/CMakeLists.txt +++ b/unified-runtime/source/common/CMakeLists.txt @@ -139,6 +139,7 @@ if (UNIX) endif() install(TARGETS ur_common + COMPONENT unified-runtime EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} diff --git a/unified-runtime/source/loader/CMakeLists.txt b/unified-runtime/source/loader/CMakeLists.txt index 1b7244714edc2..d4324ca231d21 100644 --- a/unified-runtime/source/loader/CMakeLists.txt +++ b/unified-runtime/source/loader/CMakeLists.txt @@ -22,8 +22,19 @@ install_ur_library(ur_loader) target_compile_definitions(ur_loader PRIVATE UR_USE_DEBUG_POSTFIX=$ + UR_ADAPTER_SEARCH_LOADER_DIR_FIRST=$ + UR_STATIC_LOADER=$ ) +if(UR_STATIC_LOADER AND WIN32) + # When the loader is linked statically into SYCL, + # the UR API symbols must not be re-exported from that DLL. + target_compile_definitions(ur_loader PUBLIC + UR_APIEXPORT= + UR_DLLEXPORT= + ) +endif() + if (MSVC) set(TARGET_LIBNAME ur_loader) string(TOUPPER ${TARGET_LIBNAME} TARGET_LIBNAME) @@ -207,6 +218,7 @@ if(UR_ENABLE_SANITIZER) ) target_include_directories(ur_loader PRIVATE ${LLVM_INCLUDE_DIRS}) target_link_libraries(ur_loader PRIVATE LLVMSupport LLVMSymbolize) + target_compile_definitions(ur_loader PRIVATE UR_HAVE_SYMBOLIZER) # In in-tree build, if LLVM is built with libc++, we also need to build # symbolizer.cpp with libc++ abi and link libc++ in. if(NOT UR_STANDALONE_BUILD AND LLVM_LIBCXX_USED) diff --git a/unified-runtime/source/loader/layers/sanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/unified-runtime/source/loader/layers/sanitizer/sanitizer_common/sanitizer_stacktrace.cpp index 0f5b1fdf43609..5fd10e86a30ea 100644 --- a/unified-runtime/source/loader/layers/sanitizer/sanitizer_common/sanitizer_stacktrace.cpp +++ b/unified-runtime/source/loader/layers/sanitizer/sanitizer_common/sanitizer_stacktrace.cpp @@ -13,13 +13,11 @@ #include "sanitizer_stacktrace.hpp" #include "ur_sanitizer_layer.hpp" -extern "C" { - -__attribute__((weak)) void SymbolizeCode(const char *ModuleName, - uint64_t ModuleOffset, - char *ResultString, size_t ResultSize, - size_t *RetSize); -} +#ifdef UR_HAVE_SYMBOLIZER +extern "C" void SymbolizeCode(const char *ModuleName, uint64_t ModuleOffset, + char *ResultString, size_t ResultSize, + size_t *RetSize); +#endif namespace ur_sanitizer_layer { @@ -29,6 +27,7 @@ bool Contains(const std::string &s, const char *p) { return s.find(p) != std::string::npos; } +#ifdef UR_HAVE_SYMBOLIZER // Parse back trace information in the following formats: // ([function_name]+function_offset) [offset] void ParseBacktraceInfo(const BacktraceInfo &BI, std::string &ModuleName, @@ -76,6 +75,7 @@ SourceInfo ParseSymbolizerOutput(const std::string &Output) { return Info; } +#endif } // namespace @@ -99,7 +99,8 @@ void StackTrace::print() const { continue; } - if (&SymbolizeCode != nullptr) { +#ifdef UR_HAVE_SYMBOLIZER + { std::string Result; std::string ModuleName; uptr Offset; @@ -121,9 +122,10 @@ void StackTrace::print() const { SrcInfo.function, ModuleName, (void *)Offset); } } - } else { - UR_LOG_L(getContext()->logger, QUIET, " #{} {}", index, BI); } +#else + UR_LOG_L(getContext()->logger, QUIET, " #{} {}", index, BI); +#endif ++index; } UR_LOG_L(getContext()->logger, QUIET, ""); diff --git a/unified-runtime/source/loader/layers/tracing/ur_tracing_layer.cpp b/unified-runtime/source/loader/layers/tracing/ur_tracing_layer.cpp index 582fc126ba9e0..38c132c30ab87 100644 --- a/unified-runtime/source/loader/layers/tracing/ur_tracing_layer.cpp +++ b/unified-runtime/source/loader/layers/tracing/ur_tracing_layer.cpp @@ -31,9 +31,20 @@ constexpr auto STREAM_VER_MINOR = UR_MINOR_VERSION(UR_API_VERSION_CURRENT); // Unfortunately this doesn't match the semantics of XPTI, which can be // initialized and finalized exactly once. To workaround this, XPTI is globally // initialized on first use and finalized in the destructor. +// +// If the loader is linked statically, it's the SYCL's responsibility to +// initialize and teardown XPTI. struct XptiContextManager { - XptiContextManager() { xptiFrameworkInitialize(); } - ~XptiContextManager() { xptiFrameworkFinalize(); } + XptiContextManager() { +#if !UR_STATIC_LOADER + xptiFrameworkInitialize(); +#endif + } + ~XptiContextManager() { +#if !UR_STATIC_LOADER + xptiFrameworkFinalize(); +#endif + } }; static std::shared_ptr xptiContextManagerGet() { diff --git a/unified-runtime/source/loader/linux/adapter_search.cpp b/unified-runtime/source/loader/linux/adapter_search.cpp index 783013f0ca1ce..ace9a6a3cae13 100644 --- a/unified-runtime/source/loader/linux/adapter_search.cpp +++ b/unified-runtime/source/loader/linux/adapter_search.cpp @@ -9,6 +9,7 @@ */ #include +#include #include #include "ur_filesystem_resolved.hpp" @@ -23,7 +24,7 @@ std::optional getLoaderLibPath() { if (dladdr((void *)getLoaderLibPath, &info)) { auto libPath = fs::path(info.dli_fname); if (fs::exists(libPath)) { - return fs::absolute(libPath).parent_path(); + return fs::canonical(libPath).parent_path(); } } diff --git a/unified-runtime/source/loader/ur_adapter_registry.hpp b/unified-runtime/source/loader/ur_adapter_registry.hpp index 32d3588830a72..f17d1aa3c0cc7 100644 --- a/unified-runtime/source/loader/ur_adapter_registry.hpp +++ b/unified-runtime/source/loader/ur_adapter_registry.hpp @@ -360,22 +360,34 @@ class AdapterRegistry { // 1. Every path from UR_ADAPTERS_SEARCH_PATH. // 2. OS search paths. // 3. Loader library directory. + // If UR_ADAPTER_SEARCH_LOADER_DIR_FIRST is set, + // then the order of 2 and 3 is switched. if (searchPathsEnvOpt.has_value()) { for (const auto &p : searchPathsEnvOpt.value()) { loadPaths.emplace_back(p / adapterName); } } - auto adapterNamePathOpt = getAdapterNameAsPath(adapterName); - if (adapterNamePathOpt.has_value()) { - const auto &adapterNamePath = adapterNamePathOpt.value(); - loadPaths.emplace_back(adapterNamePath); - } + auto AddOsSearchPath = [&] { + auto AdapterNamePathOpt = getAdapterNameAsPath(adapterName); + if (AdapterNamePathOpt.has_value()) { + loadPaths.emplace_back(AdapterNamePathOpt.value()); + } + }; - if (loaderLibPathOpt.has_value()) { - const auto &loaderLibPath = loaderLibPathOpt.value(); - loadPaths.emplace_back(loaderLibPath / adapterName); - } + auto AddLoaderLibPath = [&] { + if (loaderLibPathOpt.has_value()) { + loadPaths.emplace_back(loaderLibPathOpt.value() / adapterName); + } + }; + +#if UR_ADAPTER_SEARCH_LOADER_DIR_FIRST + AddLoaderLibPath(); + AddOsSearchPath(); +#else + AddOsSearchPath(); + AddLoaderLibPath(); +#endif adaptersLoadPaths.emplace_back(loadPaths); } diff --git a/unified-runtime/source/loader/windows/adapter_search.cpp b/unified-runtime/source/loader/windows/adapter_search.cpp index cad218376a273..3f802cdd65beb 100644 --- a/unified-runtime/source/loader/windows/adapter_search.cpp +++ b/unified-runtime/source/loader/windows/adapter_search.cpp @@ -9,6 +9,7 @@ */ /* This include needs to be before Libloaderapi.h */ +#include #include #include @@ -33,7 +34,7 @@ std::optional getLoaderLibPath() { GetModuleFileNameA(hModule, pathStr, MAX_PATH_LEN_WIN)) { auto libPath = fs::path(pathStr); if (fs::exists(libPath)) { - return fs::absolute(libPath).parent_path(); + return fs::canonical(libPath).parent_path(); } }