Summary: This patch rewrites the `llvm-gpu-loader` utility to use the LLVMOffload interface. This heavily simplifies it while re-using the already existing support. Another benefit is that I can now easily do this dynamically so we can always build this utility without needing to find non-standard packages. One issue is mentioned in https://github.com/llvm/llvm-project/issues/159636 where this will now take extra time if you have both installed on the same machine. This is just slightly annoying since most people don't have both CUDA and ROCm at the same time so I don't consider it a blocker. I will work later to address it. Slightly unfortunate environment variable usage, I will also expose that better in the future. Fixes: https://github.com/llvm/llvm-project/issues/132890
197 lines
6.8 KiB
C++
197 lines
6.8 KiB
C++
//===-- Dynamically loaded offload API ------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Dynamically loads the API provided by the LLVMOffload library. We need to do
|
|
// this dynamically because this tool is used before it is actually built and
|
|
// should be provided even when the user did not specify the offload runtime.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_TOOLS_LLVM_GPU_LOADER_LLVM_GPU_LOADER_H
|
|
#define LLVM_TOOLS_LLVM_GPU_LOADER_LLVM_GPU_LOADER_H
|
|
|
|
#include "llvm/Support/DynamicLibrary.h"
|
|
#include "llvm/Support/Error.h"
|
|
|
|
typedef enum ol_alloc_type_t {
|
|
OL_ALLOC_TYPE_HOST = 0,
|
|
OL_ALLOC_TYPE_DEVICE = 1,
|
|
OL_ALLOC_TYPE_FORCE_UINT32 = 0x7fffffff
|
|
} ol_alloc_type_t;
|
|
|
|
typedef enum ol_device_info_t {
|
|
OL_DEVICE_INFO_TYPE = 0,
|
|
OL_DEVICE_INFO_PLATFORM = 1,
|
|
OL_DEVICE_INFO_FORCE_UINT32 = 0x7fffffff
|
|
} ol_device_info_t;
|
|
|
|
typedef enum ol_platform_info_t {
|
|
OL_PLATFORM_INFO_NAME = 0,
|
|
OL_PLATFORM_INFO_BACKEND = 3,
|
|
OL_PLATFORM_INFO_FORCE_UINT32 = 0x7fffffff
|
|
} ol_platform_info_t;
|
|
|
|
typedef enum ol_symbol_kind_t {
|
|
OL_SYMBOL_KIND_KERNEL = 0,
|
|
OL_SYMBOL_KIND_GLOBAL_VARIABLE = 1,
|
|
OL_SYMBOL_KIND_FORCE_UINT32 = 0x7fffffff
|
|
} ol_symbol_kind_t;
|
|
|
|
typedef enum ol_errc_t {
|
|
OL_ERRC_SUCCESS = 0,
|
|
OL_ERRC_FORCE_UINT32 = 0x7fffffff
|
|
} ol_errc_t;
|
|
|
|
typedef struct ol_error_struct_t {
|
|
ol_errc_t Code;
|
|
const char *Details;
|
|
} ol_error_struct_t;
|
|
|
|
typedef struct ol_dimensions_t {
|
|
uint32_t x;
|
|
uint32_t y;
|
|
uint32_t z;
|
|
} ol_dimensions_t;
|
|
|
|
typedef struct ol_kernel_launch_size_args_t {
|
|
size_t Dimensions;
|
|
struct ol_dimensions_t NumGroups;
|
|
struct ol_dimensions_t GroupSize;
|
|
size_t DynSharedMemory;
|
|
} ol_kernel_launch_size_args_t;
|
|
|
|
typedef enum ol_platform_backend_t {
|
|
OL_PLATFORM_BACKEND_UNKNOWN = 0,
|
|
OL_PLATFORM_BACKEND_CUDA = 1,
|
|
OL_PLATFORM_BACKEND_AMDGPU = 2,
|
|
OL_PLATFORM_BACKEND_LEVEL_ZERO = 3,
|
|
OL_PLATFORM_BACKEND_HOST = 4,
|
|
OL_PLATFORM_BACKEND_LAST = 5,
|
|
OL_PLATFORM_BACKEND_FORCE_UINT32 = 0x7fffffff
|
|
} ol_platform_backend_t;
|
|
|
|
typedef enum ol_device_type_t {
|
|
OL_DEVICE_TYPE_DEFAULT = 0,
|
|
OL_DEVICE_TYPE_ALL = 1,
|
|
OL_DEVICE_TYPE_GPU = 2,
|
|
OL_DEVICE_TYPE_CPU = 3,
|
|
OL_DEVICE_TYPE_HOST = 4,
|
|
OL_DEVICE_TYPE_LAST = 5,
|
|
OL_DEVICE_TYPE_FORCE_UINT32 = 0x7fffffff
|
|
} ol_device_type_t;
|
|
|
|
typedef struct ol_init_args_t {
|
|
size_t Size;
|
|
uint32_t NumPlatforms;
|
|
const ol_platform_backend_t *Platforms;
|
|
} ol_init_args_t;
|
|
|
|
#define OL_INIT_ARGS_INIT {sizeof(ol_init_args_t), 0, NULL}
|
|
|
|
typedef struct ol_device_impl_t *ol_device_handle_t;
|
|
typedef struct ol_platform_impl_t *ol_platform_handle_t;
|
|
typedef struct ol_program_impl_t *ol_program_handle_t;
|
|
typedef struct ol_queue_impl_t *ol_queue_handle_t;
|
|
typedef struct ol_symbol_impl_t *ol_symbol_handle_t;
|
|
typedef const struct ol_error_struct_t *ol_result_t;
|
|
|
|
typedef bool (*ol_device_iterate_cb_t)(ol_device_handle_t Device,
|
|
void *UserData);
|
|
|
|
ol_result_t (*olInit)(const ol_init_args_t *);
|
|
ol_result_t (*olShutDown)();
|
|
|
|
ol_result_t (*olIterateDevices)(ol_device_iterate_cb_t Callback,
|
|
void *UserData);
|
|
|
|
ol_result_t (*olIsValidBinary)(ol_device_handle_t Device, const void *ProgData,
|
|
size_t ProgDataSize, bool *Valid);
|
|
|
|
ol_result_t (*olCreateProgram)(ol_device_handle_t Device, const void *ProgData,
|
|
size_t ProgDataSize,
|
|
ol_program_handle_t *Program);
|
|
|
|
ol_result_t (*olDestroyProgram)(ol_program_handle_t Program);
|
|
|
|
ol_result_t (*olGetSymbol)(ol_program_handle_t Program, const char *Name,
|
|
ol_symbol_kind_t Kind, ol_symbol_handle_t *Symbol);
|
|
|
|
ol_result_t (*olLaunchKernel)(
|
|
ol_queue_handle_t Queue, ol_device_handle_t Device,
|
|
ol_symbol_handle_t Kernel, const void *ArgumentsData, size_t ArgumentsSize,
|
|
const ol_kernel_launch_size_args_t *LaunchSizeArgs);
|
|
|
|
ol_result_t (*olCreateQueue)(ol_device_handle_t Device,
|
|
ol_queue_handle_t *Queue);
|
|
|
|
ol_result_t (*olDestroyQueue)(ol_queue_handle_t Queue);
|
|
|
|
ol_result_t (*olSyncQueue)(ol_queue_handle_t Queue);
|
|
|
|
ol_result_t (*olMemAlloc)(ol_device_handle_t Device, ol_alloc_type_t Type,
|
|
size_t Size, void **AllocationOut);
|
|
|
|
ol_result_t (*olMemFree)(void *Address);
|
|
|
|
ol_result_t (*olMemcpy)(ol_queue_handle_t Queue, void *DstPtr,
|
|
ol_device_handle_t DstDevice, const void *SrcPtr,
|
|
ol_device_handle_t SrcDevice, size_t Size);
|
|
|
|
ol_result_t (*olGetDeviceInfo)(ol_device_handle_t Device,
|
|
ol_device_info_t PropName, size_t PropSize,
|
|
void *PropValue);
|
|
|
|
ol_result_t (*olGetPlatformInfo)(ol_platform_handle_t Platform,
|
|
ol_platform_info_t PropName, size_t PropSize,
|
|
void *PropValue);
|
|
|
|
llvm::Error loadLLVMOffload() {
|
|
constexpr const char *OffloadLibrary = "libLLVMOffload.so";
|
|
|
|
std::string ErrMsg;
|
|
auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>(
|
|
llvm::sys::DynamicLibrary::getPermanentLibrary(OffloadLibrary, &ErrMsg));
|
|
|
|
if (!DynlibHandle->isValid())
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
"Failed to dlopen %s: %s", OffloadLibrary,
|
|
ErrMsg.c_str());
|
|
|
|
#define DYNAMIC_INIT(SYM) \
|
|
do { \
|
|
void *Ptr = DynlibHandle->getAddressOfSymbol(#SYM); \
|
|
if (!Ptr) \
|
|
return llvm::createStringError( \
|
|
llvm::inconvertibleErrorCode(), "Missing symbol '%s' in %s", \
|
|
reinterpret_cast<const char *>(#SYM), OffloadLibrary); \
|
|
SYM = reinterpret_cast<decltype(SYM)>(Ptr); \
|
|
} while (0)
|
|
|
|
DYNAMIC_INIT(olInit);
|
|
DYNAMIC_INIT(olShutDown);
|
|
DYNAMIC_INIT(olIterateDevices);
|
|
DYNAMIC_INIT(olIsValidBinary);
|
|
DYNAMIC_INIT(olCreateProgram);
|
|
DYNAMIC_INIT(olDestroyProgram);
|
|
DYNAMIC_INIT(olGetSymbol);
|
|
DYNAMIC_INIT(olLaunchKernel);
|
|
DYNAMIC_INIT(olCreateQueue);
|
|
DYNAMIC_INIT(olDestroyQueue);
|
|
DYNAMIC_INIT(olSyncQueue);
|
|
DYNAMIC_INIT(olMemAlloc);
|
|
DYNAMIC_INIT(olMemFree);
|
|
DYNAMIC_INIT(olMemcpy);
|
|
DYNAMIC_INIT(olGetDeviceInfo);
|
|
DYNAMIC_INIT(olGetPlatformInfo);
|
|
#undef DYNAMIC_INIT
|
|
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
#endif // LLVM_TOOLS_LLVM_GPU_LOADER_LLVM_GPU_LOADER_H
|