ispcrt: outline from ispcrt CPU and GPU specific parts

Some dependencies, e.g., threading (OpenMP or TBB) or Level Zero are
optional for some use cases. Make them happen on-demand only when call
to corresponding API part happens.

This change let GPU users do not install threading libraries and CPU only
customers do not install level zero runtime.

Not ispcrt constist of 3 libraries:
- ispcrt
- ispcrt_device_cpu
- ispcrt_device_gpu

ispcrt_device_gpu explicitly depends on Level Zero loader.
ispcrt_device_cpu explicitly depends on threading libraries (ELF NEEDED
field).

ispcrt library dlopen on demand specific ispcrt_device library that
allows avoid explicit dependency for ispcrt from threading and level
zero shared libraries.
This commit is contained in:
Aleksei Nurmukhametov authored and aneshlya committed 2023-04-17 10:55:43 -07:00
1 parent 06ff7c4b5a
commit e4ea6d7e28
12 files changed
+741 -171

No files matched your search

+101 -141
View File
@@ -1,4 +1,4 @@
## Copyright 2020-2022 Intel Corporation
## Copyright 2020-2023 Intel Corporation
## SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.1)
@@ -31,6 +31,7 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
## Add library and executable targets #########################################
option(ISPCRT_BUILD_STATIC "Build ispcrt static library" ON)
option(ISPCRT_BUILD_CPU "Enable CPU support in ispcrt" ON)
option(ISPCRT_BUILD_TASKING "Enable CPU tasking targets in ispcrt" ON)
@@ -52,156 +53,115 @@ if (ISPCRT_BUILD_GPU)
endif()
endif()
option(ISPCRT_BUILD_STATIC "Build ispcrt static library" ON)
if (NOT ISPCRT_BUILD_CPU AND NOT ISPCRT_BUILD_GPU)
message(FATAL_ERROR "You must enable either CPU or GPU support!")
endif()
if (ISPCRT_BUILD_GPU)
find_package(level_zero REQUIRED)
message(STATUS "ISPC Runtime will be built with GPU support")
endif()
set(ISPCRT_BUILD_TASK_MODELS "OpenMP;TBB;Threads")
if (ISPCRT_BUILD_TASKING)
# Set default value for ISPCRT_BUILD_TASK_MODEL if it is not set externally
if (NOT ISPCRT_BUILD_TASK_MODEL)
if (WIN32 OR APPLE)
set (ISPCRT_BUILD_TASK_MODEL "Threads")
else()
set (ISPCRT_BUILD_TASK_MODEL "OpenMP")
endif()
endif()
# Report error if unsupported thread model is requested.
string(FIND "${ISPCRT_BUILD_TASK_MODELS}" "${ISPCRT_BUILD_TASK_MODEL}" MATCHED_TASK_MODEL)
if (${MATCHED_TASK_MODEL} EQUAL -1)
message(FATAL_ERROR "ISPCRT_BUILD_TASK_MODEL (${ISPCRT_BUILD_TASK_MODEL}) allows only the following values: ${ISPCRT_BUILD_TASK_MODELS}")
endif()
message(STATUS "ISPC Runtime will be built with support of " ${ISPCRT_BUILD_TASK_MODEL} " tasking model on CPU")
add_library(ispcrt_tasking INTERFACE)
if (ISPCRT_BUILD_TASK_MODEL STREQUAL "OpenMP")
find_package(OpenMP REQUIRED)
if (OpenMP_FOUND)
target_link_libraries(ispcrt_tasking INTERFACE OpenMP::OpenMP_CXX)
target_compile_definitions(ispcrt_tasking INTERFACE ISPC_USE_OMP)
endif()
elseif (ISPCRT_BUILD_TASK_MODEL STREQUAL "TBB")
find_package(TBB REQUIRED COMPONENTS tbb)
if (TBB_FOUND)
# TBB package does not produce any info when found, so print it here.
message(STATUS "Found TBB: ${TBB_VERSION} at ${TBB_DIR}")
target_link_libraries(ispcrt_tasking INTERFACE TBB::tbb)
target_compile_definitions(ispcrt_tasking INTERFACE ISPC_USE_TBB_PARALLEL_FOR)
endif()
else()
find_package(Threads REQUIRED)
if (Threads_FOUND)
# Use default compile definitions from ispc_tasking.cpp
target_link_libraries(ispcrt_tasking INTERFACE Threads::Threads)
endif()
endif()
endif()
## Define a macro to build both static and shared versions of ispcrt
macro(build_ispcrt SHARED_OR_STATIC TARGET_NAME)
## Build library ##
add_library(${TARGET_NAME} ${SHARED_OR_STATIC}
$<$<BOOL:${ISPCRT_BUILD_TASKING}>:ispc_tasking.cpp>
ispcrt.cpp
${CMAKE_CURRENT_LIST_DIR}/../common/version.rc
$<$<BOOL:${ISPCRT_BUILD_CPU}>:detail/cpu/CPUDevice.cpp>
$<$<BOOL:${ISPCRT_BUILD_GPU}>:detail/gpu/GPUDevice.cpp>
)
set_target_properties(${TARGET_NAME} PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
)
if (ISPCRT_BUILD_GPU)
target_compile_definitions(${TARGET_NAME} PRIVATE ISPCRT_BUILD_GPU)
endif()
if (ISPCRT_BUILD_CPU)
target_compile_definitions(${TARGET_NAME} PRIVATE ISPCRT_BUILD_CPU)
endif()
target_include_directories(${TARGET_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/../common>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
$<BUILD_INTERFACE:${LEVEL_ZERO_INCLUDE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/ispcrt>
)
target_link_libraries(${TARGET_NAME}
PRIVATE
$<$<BOOL:${ISPCRT_BUILD_GPU}>:${LEVEL_ZERO_LIB_LOADER}>
${CMAKE_DL_LIBS}
$<$<BOOL:${ISPCRT_BUILD_TASKING}>:ispcrt_tasking>
)
# Security options
if (MSVC)
# Stack canaries
target_compile_options(${TARGET_NAME} PRIVATE /GS)
# Control flow guard
target_link_options(${TARGET_NAME} PRIVATE /GUARD:CF)
elseif (APPLE)
else()
# Enable stack protector
# NOT to assume that null pointer deference does not exist
# Assume that signed overflow always wraps
target_compile_options(${TARGET_NAME} PRIVATE -fstack-protector-strong -fno-delete-null-pointer-checks -fwrapv)
endif()
## Install targets + exports ##
set_target_properties(${TARGET_NAME}
PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR})
install(TARGETS ${TARGET_NAME}
EXPORT ${PROJECT_NAME}_Exports
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
NAMELINK_SKIP
# on Windows put the dlls into bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
# ... and the import lib into the devel package
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(EXPORT ${PROJECT_NAME}_Exports
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_VERSION}
NAMESPACE ${PROJECT_NAME}::
)
install(TARGETS ${TARGET_NAME}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
NAMELINK_ONLY
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
endmacro()
if (WIN32)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
build_ispcrt(SHARED ${PROJECT_NAME})
if (WIN32)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)
add_subdirectory(detail)
# RPATH to find devices libraries when run mock tests from the build directory.
list(APPEND CMAKE_BUILD_RPATH ${CMAKE_BINARY_DIR}/ispcrt/detail/cpu ${CMAKE_BINARY_DIR}/ispcrt/detail/gpu)
# RPATH for ispcrt library to find devices libraries.
set(CMAKE_INSTALL_RPATH $ORIGIN)
# Shared library target.
list(APPEND LIB_LIST ${PROJECT_NAME})
add_library(${PROJECT_NAME} SHARED
ispcrt.cpp
${CMAKE_CURRENT_LIST_DIR}/../common/version.rc
)
target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_DL_LIBS})
# Static library target.
if (ISPCRT_BUILD_STATIC)
list(APPEND LIB_LIST ${PROJECT_NAME}_static)
add_library(${PROJECT_NAME}_static STATIC
ispcrt.cpp
$<$<BOOL:${ISPCRT_BUILD_CPU}>:detail/cpu/CPUDevice.cpp>
$<$<BOOL:${ISPCRT_BUILD_GPU}>:detail/gpu/GPUDevice.cpp>
$<$<BOOL:${ISPCRT_BUILD_TASKING}>:detail/cpu/ispc_tasking.cpp>
${CMAKE_CURRENT_LIST_DIR}/../common/version.rc
)
target_compile_definitions(${PROJECT_NAME}_static PRIVATE ISPCRT_BUILD_STATIC)
target_include_directories(${PROJECT_NAME}_static PUBLIC
$<BUILD_INTERFACE:${LEVEL_ZERO_INCLUDE_DIR}>
)
endif()
if (ISPCRT_BUILD_STATIC)
build_ispcrt(STATIC ${PROJECT_NAME}_static)
foreach(PRNAME ${LIB_LIST})
set_target_properties(${PRNAME} PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
)
target_include_directories(${PRNAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/../common>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/ispcrt>
)
if (ISPCRT_BUILD_GPU)
target_compile_definitions(${PRNAME} PRIVATE ISPCRT_BUILD_GPU)
endif()
if (ISPCRT_BUILD_CPU)
target_compile_definitions(${PRNAME} PRIVATE ISPCRT_BUILD_CPU)
endif()
if (ISPCRT_BUILD_TASKING)
target_compile_definitions(${PRNAME} PRIVATE ISPCRT_BUILD_TASKING)
endif()
target_compile_definitions(${PRNAME} PRIVATE ISPCRT_VERSION_MAJOR="${PROJECT_VERSION_MAJOR}")
target_compile_definitions(${PRNAME} PRIVATE ISPCRT_VERSION_FULL="${PROJECT_VERSION}")
# Security options
if (MSVC)
# Stack canaries
target_compile_options(${PRNAME} PRIVATE /GS)
# Control flow guard
target_link_options(${PRNAME} PRIVATE /GUARD:CF)
elseif (APPLE)
else()
# Enable stack protector
# NOT to assume that null pointer deference does not exist
# Assume that signed overflow always wraps
target_compile_options(${PRNAME} PRIVATE -fstack-protector-strong -fno-delete-null-pointer-checks -fwrapv)
endif()
## Install targets + exports ##
install(TARGETS ${PRNAME}
EXPORT ${PROJECT_NAME}_Exports
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
NAMELINK_SKIP
# on Windows put the dlls into bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
# ... and the import lib into the devel package
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(TARGETS ${PRNAME}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
NAMELINK_ONLY
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
endforeach()
install(EXPORT ${PROJECT_NAME}_Exports
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_VERSION}
NAMESPACE ${PROJECT_NAME}::
)
if (WIN32)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)
endif()
## Build tests ############################################################
+10
View File
@@ -0,0 +1,10 @@
## Copyright 2023 Intel Corporation
## SPDX-License-Identifier: BSD-3-Clause
if (ISPCRT_BUILD_CPU)
add_subdirectory(cpu)
endif()
if (ISPCRT_BUILD_GPU)
add_subdirectory(gpu)
endif()
+87
View File
@@ -0,0 +1,87 @@
## Copyright 2023 Intel Corporation
## SPDX-License-Identifier: BSD-3-Clause
set(ISPCRT_BUILD_TASK_MODELS "OpenMP;TBB;Threads")
if (ISPCRT_BUILD_TASKING)
# Set default value for ISPCRT_BUILD_TASK_MODEL if it is not set externally
if (NOT ISPCRT_BUILD_TASK_MODEL)
if (WIN32 OR APPLE)
set (ISPCRT_BUILD_TASK_MODEL "Threads")
else()
set (ISPCRT_BUILD_TASK_MODEL "OpenMP")
endif()
endif()
# Report error if unsupported thread model is requested.
string(FIND "${ISPCRT_BUILD_TASK_MODELS}" "${ISPCRT_BUILD_TASK_MODEL}" MATCHED_TASK_MODEL)
if (${MATCHED_TASK_MODEL} EQUAL -1)
message(FATAL_ERROR "ISPCRT_BUILD_TASK_MODEL (${ISPCRT_BUILD_TASK_MODEL}) allows only the following values: ${ISPCRT_BUILD_TASK_MODELS}")
endif()
message(STATUS "ISPC Runtime will be built with support of " ${ISPCRT_BUILD_TASK_MODEL} " tasking model on CPU")
add_library(ispcrt_tasking INTERFACE)
if (ISPCRT_BUILD_TASK_MODEL STREQUAL "OpenMP")
find_package(OpenMP REQUIRED)
if (OpenMP_FOUND)
target_link_libraries(ispcrt_tasking INTERFACE OpenMP::OpenMP_CXX)
target_compile_definitions(ispcrt_tasking INTERFACE ISPC_USE_OMP)
endif()
elseif (ISPCRT_BUILD_TASK_MODEL STREQUAL "TBB")
find_package(TBB REQUIRED COMPONENTS tbb)
if (TBB_FOUND)
# TBB package does not produce any info when found, so print it here.
message(STATUS "Found TBB: ${TBB_VERSION} at ${TBB_DIR}")
target_link_libraries(ispcrt_tasking INTERFACE TBB::tbb)
target_compile_definitions(ispcrt_tasking INTERFACE ISPC_USE_TBB_PARALLEL_FOR)
endif()
else()
find_package(Threads REQUIRED)
if (Threads_FOUND)
# Use default compile definitions from ispc_tasking.cpp
target_link_libraries(ispcrt_tasking INTERFACE Threads::Threads)
endif()
endif()
else()
message(STATUS "ISPC Runtime will be built without support of tasking model on CPU")
endif()
set(TARGET ${PROJECT_NAME}_device_cpu)
add_library(${TARGET} SHARED
CPUDevice.cpp
$<$<BOOL:${ISPCRT_BUILD_TASKING}>:ispc_tasking.cpp>
)
target_link_libraries(${TARGET} PRIVATE
$<$<BOOL:${ISPCRT_BUILD_TASKING}>:ispcrt_tasking>
)
target_compile_definitions(${TARGET} PRIVATE ISPCRT_BUILD_CPU)
set_target_properties(${TARGET} PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
)
target_include_directories(${TARGET} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>/../../
)
set_target_properties(${TARGET} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
install(TARGETS ${TARGET}
EXPORT ${TARGET}_Exports
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
NAMELINK_SKIP
# on Windows put the dlls into bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
# ... and the import lib into the devel package
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(TARGETS ${TARGET}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
NAMELINK_ONLY
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
+6 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2022 Intel Corporation
// Copyright 2022-2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
@@ -16,3 +16,8 @@ struct CPUContext : public base::Context {
};
} // namespace ispcrt
// Expose API of CPU device solib for dlsym.
extern "C" {
ispcrt::base::Context *load_cpu_context();
}
+15
View File
@@ -18,6 +18,21 @@
#include <string>
#include <vector>
extern "C" {
ispcrt::base::Device *load_cpu_device() {
return new ispcrt::CPUDevice;
}
uint32_t cpu_device_count() {
return ispcrt::cpu::deviceCount();
}
ISPCRTDeviceInfo cpu_device_info(uint32_t idx) {
return ispcrt::cpu::deviceInfo(idx);
}
ispcrt::base::Context *load_cpu_context() {
return new ispcrt::CPUContext;
}
}
namespace ispcrt {
namespace cpu {
+8 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2020-2022 Intel Corporation
// Copyright 2020-2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
@@ -37,3 +37,10 @@ struct CPUDevice : public base::Device {
};
} // namespace ispcrt
// Expose API of CPU device solib for dlsym.
extern "C" {
ispcrt::base::Device *load_cpu_device();
uint32_t cpu_device_count();
ISPCRTDeviceInfo cpu_device_info(uint32_t idx);
}
@@ -161,9 +161,9 @@ struct TaskInfo {
// ispc expects these functions to have C linkage / not be mangled
extern "C" {
void ISPCLaunch(void **handlePtr, void *f, void *data, int countx, int county, int countz);
void *ISPCAlloc(void **handlePtr, int64_t size, int32_t alignment);
void ISPCSync(void *handle);
void ISPCLaunch_cpu(void **handlePtr, void *f, void *data, int countx, int county, int countz);
void *ISPCAlloc_cpu(void **handlePtr, int64_t size, int32_t alignment);
void ISPCSync_cpu(void *handle);
}
///////////////////////////////////////////////////////////////////////////
@@ -207,7 +207,7 @@ class TaskGroupBase {
*/
TaskInfo *taskInfo[MAX_TASK_QUEUE_CHUNKS];
/* We also allocate chunks of memory to service ISPCAlloc() calls. The
/* We also allocate chunks of memory to service ISPCAlloc_cpu() calls. The
memBuffers[] array holds pointers to this memory. The first element
of this array is initialized to point to mem and then any subsequent
elements required are initialized with dynamic allocation.
@@ -972,7 +972,7 @@ static inline void FreeTaskGroup(TaskGroup *tg) {
///////////////////////////////////////////////////////////////////////////
void ISPCLaunch(void **taskGroupPtr, void *func, void *data, int count0, int count1, int count2) {
void ISPCLaunch_cpu(void **taskGroupPtr, void *func, void *data, int count0, int count1, int count2) {
const int count = count0 * count1 * count2;
TaskGroup *taskGroup;
if (*taskGroupPtr == nullptr) {
@@ -995,7 +995,7 @@ void ISPCLaunch(void **taskGroupPtr, void *func, void *data, int count0, int cou
taskGroup->Launch(baseIndex, count);
}
void ISPCSync(void *h) {
void ISPCSync_cpu(void *h) {
TaskGroup *taskGroup = (TaskGroup *)h;
if (taskGroup != nullptr) {
taskGroup->Sync();
@@ -1003,7 +1003,7 @@ void ISPCSync(void *h) {
}
}
void *ISPCAlloc(void **taskGroupPtr, int64_t size, int32_t alignment) {
void *ISPCAlloc_cpu(void **taskGroupPtr, int64_t size, int32_t alignment) {
TaskGroup *taskGroup;
if (*taskGroupPtr == nullptr) {
InitTaskSystem();
@@ -1217,7 +1217,7 @@ int TaskSys::numThreadsRunning = 0;
///////////////////////////////////////////////////////////////////////////
void ISPCLaunch(void **taskGroupPtr, void *func, void *data, int count) {
void ISPCLaunch_cpu(void **taskGroupPtr, void *func, void *data, int count) {
Task *ti = *(Task **)taskGroupPtr;
ti->func = (TaskFuncType)func;
ti->data = data;
@@ -1226,13 +1226,13 @@ void ISPCLaunch(void **taskGroupPtr, void *func, void *data, int count) {
TaskSys::global->schedule(ti);
}
void ISPCSync(void *h) {
void ISPCSync_cpu(void *h) {
Task *task = (Task *)h;
assert(task);
TaskSys::global->sync(task);
}
void *ISPCAlloc(void **taskGroupPtr, int64_t size, int32_t alignment) {
void *ISPCAlloc_cpu(void **taskGroupPtr, int64_t size, int32_t alignment) {
TaskSys::init();
Task *task = TaskSys::global->allocOne();
*taskGroupPtr = task;
+40
View File
@@ -0,0 +1,40 @@
## Copyright 2023 Intel Corporation
## SPDX-License-Identifier: BSD-3-Clause
set(TARGET ${PROJECT_NAME}_device_gpu)
find_package(level_zero REQUIRED)
message(STATUS "${TARGET} LEVEL_ZERO_INCLUDE_DIR is ${LEVEL_ZERO_INCLUDE_DIR}")
message(STATUS "${TARGET} LEVEL_ZERO_LIB_LOADER is ${LEVEL_ZERO_LIB_LOADER}")
add_library(${TARGET} SHARED GPUDevice.cpp)
target_compile_definitions(${TARGET} PRIVATE ISPCRT_BUILD_GPU)
set_target_properties(${TARGET} PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
)
target_include_directories(${TARGET} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>/../../
${LEVEL_ZERO_INCLUDE_DIR}
)
target_link_libraries(${TARGET} PRIVATE ${LEVEL_ZERO_LIB_LOADER})
set_target_properties(${TARGET} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
install(TARGETS ${TARGET}
EXPORT ${TARGET}_Exports
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
NAMELINK_SKIP
# on Windows put the dlls into bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
# ... and the import lib into the devel package
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(TARGETS ${TARGET}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
NAMELINK_ONLY
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
+7 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2022 Intel Corporation
// Copyright 2022-2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
@@ -26,3 +26,9 @@ private:
std::unique_ptr<gpu::ChunkedPool> m_memPoolHRDW;
};
}
// Expose API of GPU device solib for dlsym.
extern "C" {
ispcrt::base::Context *load_gpu_context();
ispcrt::base::Context *load_gpu_context_ctx(void *ctx);
}
+21
View File
@@ -34,6 +34,27 @@
// level0
#include <level_zero/ze_api.h>
extern "C" {
ispcrt::base::Device *load_gpu_device() {
return new ispcrt::GPUDevice;
}
ispcrt::base::Device *load_gpu_device_ctx(void* ctx, void* dev, uint32_t idx) {
return new ispcrt::GPUDevice(ctx, dev, idx);
}
uint32_t gpu_device_count() {
return ispcrt::gpu::deviceCount();
}
ISPCRTDeviceInfo gpu_device_info(uint32_t idx) {
return ispcrt::gpu::deviceInfo(idx);
}
ispcrt::base::Context *load_gpu_context() {
return new ispcrt::GPUContext;
}
ispcrt::base::Context *load_gpu_context_ctx(void *ctx) {
return new ispcrt::GPUContext(ctx);
}
}
#define DECLARE_ENV(NAME) const char *NAME = #NAME;
DECLARE_ENV(ISPCRT_VERBOSE)
DECLARE_ENV(ISPCRT_MAX_KERNEL_LAUNCHES)
+9 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2020-2022 Intel Corporation
// Copyright 2020-2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
@@ -53,3 +53,11 @@ struct GPUDevice : public base::Device {
};
} // namespace ispcrt
// Expose API of GPU device solib for dlsym.
extern "C" {
ispcrt::base::Device *load_gpu_device();
ispcrt::base::Device *load_gpu_device_ctx(void* ctx, void* dev, uint32_t idx);
uint32_t gpu_device_count();
ISPCRTDeviceInfo gpu_device_info(uint32_t idx);
}
+427 -16
View File
@@ -1,10 +1,19 @@
// Copyright 2020-2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#endif
#include "ispcrt.h"
// std
#include <exception>
#include <iostream>
#include <string>
// ispcrt
#include "detail/Exception.h"
#include "detail/Module.h"
@@ -78,6 +87,408 @@ static OBJECT_T &referenceFromHandle(HANDLE_T handle) {
return a; \
}
// Define names of devices libraries.
#if defined(_WIN32) || defined(_WIN64)
#define ISPCRT_SO_LIB_PREFIX ""
#define ISPCRT_SO_LIB_SUFFIX "dll"
#elif defined(__APPLE__)
#define ISPCRT_SO_LIB_PREFIX "lib"
#define ISPCRT_SO_LIB_SUFFIX "dylib"
#else
#define ISPCRT_SO_LIB_PREFIX "lib"
#define ISPCRT_SO_LIB_SUFFIX "so"
#endif
#define ISPCRT_DEVICE_CPU_SOLIB_PREFIX ISPCRT_SO_LIB_PREFIX "ispcrt_device_cpu."
#define ISPCRT_DEVICE_GPU_SOLIB_PREFIX ISPCRT_SO_LIB_PREFIX "ispcrt_device_gpu."
#define ISPCRT_DEVICE_CPU_SOLIB_NAME ISPCRT_DEVICE_CPU_SOLIB_PREFIX ISPCRT_SO_LIB_SUFFIX
#define ISPCRT_DEVICE_GPU_SOLIB_NAME ISPCRT_DEVICE_GPU_SOLIB_PREFIX ISPCRT_SO_LIB_SUFFIX
#if defined(_WIN32) || defined(_WIN64)
#define ISPCRT_DEVICE_CPU_SOLIB_MAJOR_VERSION_NAME nullptr
#define ISPCRT_DEVICE_GPU_SOLIB_MAJOR_VERSION_NAME nullptr
#define ISPCRT_DEVICE_CPU_SOLIB_FULL_VERSION_NAME nullptr
#define ISPCRT_DEVICE_GPU_SOLIB_FULL_VERSION_NAME nullptr
#elif defined(__APPLE__)
#define ISPCRT_DEVICE_CPU_SOLIB_MAJOR_VERSION_NAME \
ISPCRT_DEVICE_CPU_SOLIB_PREFIX "." ISPCRT_VERSION_MAJOR "." ISPCRT_SO_LIB_SUFFIX
#define ISPCRT_DEVICE_GPU_SOLIB_MAJOR_VERSION_NAME \
ISPCRT_DEVICE_GPU_SOLIB_PREFIX "." ISPCRT_VERSION_MAJOR "." ISPCRT_SO_LIB_SUFFIX
#define ISPCRT_DEVICE_CPU_SOLIB_FULL_VERSION_NAME \
ISPCRT_DEVICE_CPU_SOLIB_PREFIX "." ISPCRT_VERSION_FULL "." ISPCRT_SO_LIB_SUFFIX
#define ISPCRT_DEVICE_GPU_SOLIB_FULL_VERSION_NAME \
ISPCRT_DEVICE_GPU_SOLIB_PREFIX "." ISPCRT_VERSION_FULL "." ISPCRT_SO_LIB_SUFFIX
#else
#define ISPCRT_DEVICE_CPU_SOLIB_MAJOR_VERSION_NAME ISPCRT_DEVICE_CPU_SOLIB_NAME "." ISPCRT_VERSION_MAJOR
#define ISPCRT_DEVICE_GPU_SOLIB_MAJOR_VERSION_NAME ISPCRT_DEVICE_GPU_SOLIB_NAME "." ISPCRT_VERSION_MAJOR
#define ISPCRT_DEVICE_CPU_SOLIB_FULL_VERSION_NAME ISPCRT_DEVICE_CPU_SOLIB_NAME "." ISPCRT_VERSION_FULL
#define ISPCRT_DEVICE_GPU_SOLIB_FULL_VERSION_NAME ISPCRT_DEVICE_GPU_SOLIB_NAME "." ISPCRT_VERSION_FULL
#endif
// OS agnostic function to dynamically load a shared library.
void *dyn_load_lib(const char *name, const char *name_major_version, const char *name_full_version) {
#if defined(_WIN32) || defined(_WIN64)
return LoadLibrary(name);
#else
// Try to load a device library starting from the most specific name down to more general one.
void *handle = dlopen(name_full_version, RTLD_NOW | RTLD_LOCAL);
if (handle) {
return handle;
}
handle = dlopen(name_major_version, RTLD_NOW | RTLD_LOCAL);
if (handle) {
return handle;
}
// This is the most general name, e.g., libispcrt_device_cpu.so. Under some
// circumstances, it may points to older or newer version. This is probably
// not a big deal until incompatible changes are encountered between versions.
return dlopen(name, RTLD_NOW | RTLD_LOCAL);
#endif
}
// OS agnostic function to get an address of symbol from the previously loaded shared library.
void *dyn_load_sym(void *handle, const char *symbol) {
#if defined(_WIN32) || defined(_WIN64)
return (void*) GetProcAddress((HMODULE)handle, symbol);
#else
return dlsym(handle, symbol);
#endif
}
// CPU device API.
typedef void (*ISPCLaunchF)(void**, void*, void*, int, int, int);
typedef void* (*ISPCAllocF)(void**, int64_t, int32_t);
typedef void (*ISPCSyncF)(void*);
static ISPCLaunchF ispc_launch_fptr = nullptr;
static ISPCAllocF ispc_alloc_fptr = nullptr;
static ISPCSyncF ispc_sync_fptr = nullptr;
#ifndef ISPCRT_BUILD_STATIC
// During static linking this API is delivered by linking the real implementation.
// ispc expects these functions to have C linkage / not be mangled
// Stubs to load and call actual implementations (*_cpu) from detail/cpu/ispc_tasking.cpp.
extern "C" {
void ISPCLaunch(void **handlePtr, void *f, void *data, int countx, int county, int countz) {
if (ispc_launch_fptr) {
return ispc_launch_fptr(handlePtr, f, data, countx, county, countz);
}
// TODO: this code can be called directly from ISPC code. Not sure how to exit error safely.
throw std::runtime_error("Missing ISPCLaunch symbol");
}
void *ISPCAlloc(void **handlePtr, int64_t size, int32_t alignment) {
if (ispc_alloc_fptr) {
return ispc_alloc_fptr(handlePtr, size, alignment);
}
// TODO: this code can be called directly from ISPC code. Not sure how to exit error safely.
throw std::runtime_error("Missing ISPCAlloc symbol");
}
void ISPCSync(void *handle) {
if (ispc_sync_fptr) {
return ispc_sync_fptr(handle);
}
// TODO: this code can be called directly from ISPC code. Not sure how to exit error safely.
throw std::runtime_error("Missing ISPCSync symbol");
}
}
#endif
// Auxiliary function to load device CPU solib and initialize tasking API pointers if build with tasking support.
void *handleCPUDeviceLib() {
static void *handle = nullptr;
if (handle) {
return handle;
}
handle = dyn_load_lib(
ISPCRT_DEVICE_CPU_SOLIB_NAME,
ISPCRT_DEVICE_CPU_SOLIB_MAJOR_VERSION_NAME,
ISPCRT_DEVICE_CPU_SOLIB_FULL_VERSION_NAME);
if (!handle) {
throw std::runtime_error("Fail to load " ISPCRT_DEVICE_CPU_SOLIB_NAME " library");
}
#ifdef ISPCRT_BUILD_TASKING
ispc_launch_fptr = (ISPCLaunchF) dyn_load_sym(handle, "ISPCLaunch_cpu");
if (!ispc_launch_fptr) {
throw std::runtime_error("Missing ISPCLaunch_cpu symbol");
}
ispc_alloc_fptr = (ISPCAllocF) dyn_load_sym(handle, "ISPCAlloc_cpu");
if (!ispc_alloc_fptr) {
throw std::runtime_error("Missing ISPCAlloc_cpu symbol");
}
ispc_sync_fptr = (ISPCSyncF) dyn_load_sym(handle, "ISPCSync_cpu");
if (!ispc_sync_fptr) {
throw std::runtime_error("Missing ISPCSync_cpu symbol");
}
#endif
return handle;
}
// Auxiliary function to load device GPU solib.
void *handleGPUDeviceLib() {
static void *handle = nullptr;
if (handle) {
return handle;
}
handle = dyn_load_lib(
ISPCRT_DEVICE_GPU_SOLIB_NAME,
ISPCRT_DEVICE_GPU_SOLIB_MAJOR_VERSION_NAME,
ISPCRT_DEVICE_GPU_SOLIB_FULL_VERSION_NAME);
if (!handle) {
throw std::runtime_error("Fail to load " ISPCRT_DEVICE_GPU_SOLIB_NAME " library");
}
return handle;
}
// Stubs around CPU device solibs API.
uint32_t cpuDeviceCount();
ISPCRTDeviceInfo cpuDeviceInfo(uint32_t idx);
ispcrt::base::Device *loadCPUDevice();
ispcrt::base::Context *loadCPUContext();
// Stubs around GPU device solibs API.
uint32_t gpuDeviceCount();
ISPCRTDeviceInfo gpuDeviceInfo(uint32_t idx);
ispcrt::base::Device *loadGPUDevice();
ispcrt::base::Device *loadGPUDevice(void *ctx, void *dev, uint32_t idx);
ispcrt::base::Context *loadGPUContext();
ispcrt::base::Context *loadGPUContext(void *ctx);
// Function pointer types declarations.
typedef uint32_t (*DeviceCountF)();
typedef ISPCRTDeviceInfo (*DeviceInfoF)(uint32_t);
typedef ispcrt::base::Device* (*LoadDeviceF)();
typedef ispcrt::base::Device* (*LoadDeviceCtxF)(void*, void*, uint32_t);
typedef ispcrt::base::Context* (*LoadContextF)();
typedef ispcrt::base::Context* (*LoadContextCtxF)(void *);
// CPU stubs
uint32_t cpuDeviceCount() {
#ifdef ISPCRT_BUILD_STATIC
#ifdef ISPCRT_BUILD_CPU
return ispcrt::cpu::deviceCount();
#else
throw std::runtime_error("CPU support not enabled");
#endif
#else
static DeviceCountF device_count = nullptr;
if (device_count) {
return device_count();
}
device_count = (DeviceCountF) dyn_load_sym(handleCPUDeviceLib(), "cpu_device_count");
if (!device_count) {
throw std::runtime_error("Missing cpu_device_count symbol");
}
return device_count();
#endif
}
ISPCRTDeviceInfo cpuDeviceInfo(uint32_t idx) {
#ifdef ISPCRT_BUILD_STATIC
#ifdef ISPCRT_BUILD_CPU
return ispcrt::cpu::deviceInfo(idx);
#else
throw std::runtime_error("CPU support not enabled");
#endif
#else
static DeviceInfoF device_info = nullptr;
if (device_info) {
return device_info(idx);
}
device_info = (DeviceInfoF) dyn_load_sym(handleCPUDeviceLib(), "cpu_device_info");
if (!device_info) {
throw std::runtime_error("Missing cpu_device_info symbol");
}
return device_info(idx);
#endif
}
ispcrt::base::Device *loadCPUDevice() {
#ifdef ISPCRT_BUILD_STATIC
#ifdef ISPCRT_BUILD_CPU
return new ispcrt::CPUDevice;
#else
throw std::runtime_error("CPU support not enabled");
#endif
#else
static LoadDeviceF load_device = nullptr;
if (load_device) {
return load_device();
}
load_device = (LoadDeviceF) dyn_load_sym(handleCPUDeviceLib(), "load_cpu_device");
if (!load_device) {
throw std::runtime_error("Missing load_cpu_device symbol");
}
return load_device();
#endif
}
ispcrt::base::Context *loadCPUContext() {
#ifdef ISPCRT_BUILD_STATIC
#ifdef ISPCRT_BUILD_CPU
return new ispcrt::CPUContext;
#else
throw std::runtime_error("CPU support not enabled");
#endif
#else
static LoadContextF load_context = nullptr;
if (load_context) {
return load_context();
}
load_context = (LoadContextF) dyn_load_sym(handleCPUDeviceLib(), "load_cpu_context");
if (!load_context) {
throw std::runtime_error("Missing load_cpu_context symbol");
}
return load_context();
#endif
}
// GPU stubs.
uint32_t gpuDeviceCount() {
#ifdef ISPCRT_BUILD_STATIC
#ifdef ISPCRT_BUILD_GPU
return ispcrt::gpu::deviceCount();
#else
throw std::runtime_error("GPU support not enabled");
#endif
#else
static DeviceCountF device_count = nullptr;
if (device_count) {
return device_count();
}
device_count = (DeviceCountF) dyn_load_sym(handleGPUDeviceLib(), "gpu_device_count");
if (!device_count) {
throw std::runtime_error("Missing gpu_device_count symbol");
}
return device_count();
#endif
}
ISPCRTDeviceInfo gpuDeviceInfo(uint32_t idx) {
#ifdef ISPCRT_BUILD_STATIC
#ifdef ISPCRT_BUILD_GPU
return ispcrt::gpu::deviceInfo(idx);
#else
throw std::runtime_error("GPU support not enabled");
#endif
#else
static DeviceInfoF device_info = nullptr;
if (device_info) {
return device_info(idx);
}
device_info = (DeviceInfoF) dyn_load_sym(handleGPUDeviceLib(), "gpu_device_info");
if (!device_info) {
throw std::runtime_error("Missing gpu_device_info symbol");
}
return device_info(idx);
#endif
}
ispcrt::base::Device *loadGPUDevice() {
#ifdef ISPCRT_BUILD_STATIC
#ifdef ISPCRT_BUILD_GPU
return new ispcrt::GPUDevice;
#else
throw std::runtime_error("GPU support not enabled");
#endif
#else
static LoadDeviceF load_device = nullptr;
if (load_device) {
return load_device();
}
load_device = (LoadDeviceF) dyn_load_sym(handleGPUDeviceLib(), "load_gpu_device");
if (!load_device) {
throw std::runtime_error("Missing load_gpu_device symbol");
}
return load_device();
#endif
}
ispcrt::base::Device *loadGPUDevice(void *ctx, void *dev, uint32_t idx) {
#ifdef ISPCRT_BUILD_STATIC
#ifdef ISPCRT_BUILD_GPU
return new ispcrt::GPUDevice(ctx, dev, idx);
#else
throw std::runtime_error("GPU support not enabled");
#endif
#else
static LoadDeviceCtxF load_device = nullptr;
if (load_device) {
return load_device(ctx, dev, idx);
}
load_device = (LoadDeviceCtxF) dyn_load_sym(handleGPUDeviceLib(), "load_gpu_device_ctx");
if (!load_device) {
throw std::runtime_error("Missing load_gpu_device_ctx symbol");
}
return load_device(ctx, dev, idx);
#endif
}
ispcrt::base::Context *loadGPUContext() {
#ifdef ISPCRT_BUILD_STATIC
#ifdef ISPCRT_BUILD_GPU
return new ispcrt::GPUContext;
#else
throw std::runtime_error("GPU support not enabled");
#endif
#else
static LoadContextF load_context = nullptr;
if (load_context) {
return load_context();
}
load_context = (LoadContextF) dyn_load_sym(handleGPUDeviceLib(), "load_gpu_context");
if (!load_context) {
throw std::runtime_error("Missing load_gpu_context symbol");
}
return load_context();
#endif
}
ispcrt::base::Context *loadGPUContext(void *ctx) {
#ifdef ISPCRT_BUILD_STATIC
#ifdef ISPCRT_BUILD_GPU
return new ispcrt::GPUContext(ctx);
#else
throw std::runtime_error("GPU support not enabled");
#endif
#else
static LoadContextCtxF load_context = nullptr;
if (load_context) {
return load_context(ctx);
}
load_context = (LoadContextCtxF) dyn_load_sym(handleGPUDeviceLib(), "load_gpu_context_ctx");
if (!load_context) {
throw std::runtime_error("Missing load_gpu_context_ctx symbol");
}
return load_context(ctx);
#endif
}
///////////////////////////////////////////////////////////////////////////////
////////////////////////// API DEFINITIONS ////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@@ -123,29 +534,29 @@ static ISPCRTDevice getISPCRTDevice(ISPCRTDeviceType type, ISPCRTContext context
case ISPCRT_DEVICE_TYPE_AUTO: {
#if defined(ISPCRT_BUILD_GPU) && defined(ISPCRT_BUILD_CPU)
try {
device = new ispcrt::GPUDevice;
device = loadGPUDevice();
} catch (...) {
if (device)
delete device;
device = new ispcrt::CPUDevice;
device = loadCPUDevice();
}
#elif defined(ISPCRT_BUILD_CPU)
device = new ispcrt::CPUDevice;
device = loadCPUDevice();
#elif defined(ISPCRT_BUILD_GPU)
device = new ispcrt::GPUDevice;
device = loadGPUDevice();
#endif
break;
}
case ISPCRT_DEVICE_TYPE_GPU:
#ifdef ISPCRT_BUILD_GPU
device = new ispcrt::GPUDevice(nativeContext, d, deviceIdx);
device = loadGPUDevice(nativeContext, d, deviceIdx);
#else
throw std::runtime_error("GPU support not enabled");
#endif
break;
case ISPCRT_DEVICE_TYPE_CPU:
#ifdef ISPCRT_BUILD_CPU
device = new ispcrt::CPUDevice;
device = loadCPUDevice();
#else
throw std::runtime_error("CPU support not enabled");
#endif
@@ -181,14 +592,14 @@ uint32_t ispcrtGetDeviceCount(ISPCRTDeviceType type) ISPCRT_CATCH_BEGIN {
break;
case ISPCRT_DEVICE_TYPE_GPU:
#ifdef ISPCRT_BUILD_GPU
devices = ispcrt::gpu::deviceCount();
devices = gpuDeviceCount();
#else
throw std::runtime_error("GPU support not enabled");
#endif
break;
case ISPCRT_DEVICE_TYPE_CPU:
#ifdef ISPCRT_BUILD_CPU
devices = ispcrt::cpu::deviceCount();
devices = cpuDeviceCount();
#else
throw std::runtime_error("CPU support not enabled");
#endif
@@ -211,14 +622,14 @@ void ispcrtGetDeviceInfo(ISPCRTDeviceType type, uint32_t deviceIdx, ISPCRTDevice
break;
case ISPCRT_DEVICE_TYPE_GPU:
#ifdef ISPCRT_BUILD_GPU
*info = ispcrt::gpu::deviceInfo(deviceIdx);
*info = gpuDeviceInfo(deviceIdx);
#else
throw std::runtime_error("GPU support not enabled");
#endif
break;
case ISPCRT_DEVICE_TYPE_CPU:
#ifdef ISPCRT_BUILD_CPU
*info = ispcrt::cpu::deviceInfo(deviceIdx);
*info = cpuDeviceInfo(deviceIdx);
#else
throw std::runtime_error("CPU support not enabled");
#endif
@@ -239,29 +650,29 @@ static ISPCRTContext getISPCRTContext(ISPCRTDeviceType type, ISPCRTGenericHandle
case ISPCRT_DEVICE_TYPE_AUTO: {
#if defined(ISPCRT_BUILD_GPU) && defined(ISPCRT_BUILD_CPU)
try {
context = new ispcrt::GPUContext;
context = loadGPUContext();
} catch (...) {
if (context)
delete context;
context = new ispcrt::CPUContext;
context = loadCPUContext();
}
#elif defined(ISPCRT_BUILD_CPU)
context = new ispcrt::CPUContext;
context = loadCPUContext();
#elif defined(ISPCRT_BUILD_GPU)
context = new ispcrt::GPUContext;
context = loadGPUContext();
#endif
break;
}
case ISPCRT_DEVICE_TYPE_GPU:
#ifdef ISPCRT_BUILD_GPU
context = new ispcrt::GPUContext(c);
context = loadGPUContext();
#else
throw std::runtime_error("GPU support not enabled");
#endif
break;
case ISPCRT_DEVICE_TYPE_CPU:
#ifdef ISPCRT_BUILD_CPU
context = new ispcrt::CPUContext;
context = loadCPUContext();
#else
throw std::runtime_error("CPU support not enabled");
#endif