[Offload] add 'olIterateSymbols' runtime function (#213036)
Summary: This provides users with a way to check all symbols present in a given program. This is useful for many cases where a power user wants to do something dynamic with the objects present.
This commit is contained in:
parent
7ef0ca2b13
commit
14ec3c42ce
16 changed files with 350 additions and 29 deletions
|
|
@ -32,6 +32,37 @@ def olGetSymbol : Function {
|
|||
let returns = [];
|
||||
}
|
||||
|
||||
def ol_symbol_iterate_cb_t : FptrTypedef {
|
||||
let desc = "User-provided function to be used with `olIterateSymbols`";
|
||||
let params = [
|
||||
Param<"ol_symbol_handle_t", "Symbol", "the symbol handle of the current iteration", PARAM_IN>,
|
||||
Param<"void*", "UserData", "optional user data", PARAM_IN_OPTIONAL>
|
||||
];
|
||||
let return = "bool";
|
||||
}
|
||||
|
||||
def olIterateSymbols : Function {
|
||||
let desc = "Iterates over all symbols of the given kind in the program, calling the callback for each symbol.";
|
||||
let details = [
|
||||
"If the user-provided callback returns `false`, the iteration is stopped.",
|
||||
"Symbol handles are owned by the program and do not need to be manually destroyed."
|
||||
];
|
||||
let params = [
|
||||
Param<"ol_program_handle_t", "Program", "handle of the program", PARAM_IN>,
|
||||
Param<"ol_symbol_kind_t", "Kind", "symbol kind to iterate over", PARAM_IN>,
|
||||
Param<"ol_symbol_iterate_cb_t", "Callback", "User-provided function called for each symbol", PARAM_IN>,
|
||||
Param<"void*", "UserData", "Optional user data to pass to the callback", PARAM_IN_OPTIONAL>
|
||||
];
|
||||
let returns = [
|
||||
Return<"OL_ERRC_UNSUPPORTED", [
|
||||
"The platform could not enumerate symbols of the given kind."
|
||||
]>,
|
||||
Return<"OL_ERRC_INVALID_BINARY", [
|
||||
"The program's image could not be parsed to enumerate its symbols."
|
||||
]>
|
||||
];
|
||||
}
|
||||
|
||||
def ol_symbol_info_t : Enum {
|
||||
let desc = "Supported symbol info.";
|
||||
let is_typed = 1;
|
||||
|
|
@ -39,6 +70,7 @@ def ol_symbol_info_t : Enum {
|
|||
TaggedEtor<"KIND", "ol_symbol_kind_t", "The kind of this symbol.">,
|
||||
TaggedEtor<"GLOBAL_VARIABLE_ADDRESS", "void *", "The address in memory for this global variable.">,
|
||||
TaggedEtor<"GLOBAL_VARIABLE_SIZE", "size_t", "The size in bytes for this global variable.">,
|
||||
TaggedEtor<"NAME", "char[]", "The name of this symbol.">,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -199,10 +199,12 @@ struct ol_program_impl_t {
|
|||
};
|
||||
|
||||
struct ol_symbol_impl_t {
|
||||
ol_symbol_impl_t(const char *Name, GenericKernelTy *Kernel)
|
||||
: PluginImpl(Kernel), Kind(OL_SYMBOL_KIND_KERNEL), Name(Name) {}
|
||||
ol_symbol_impl_t(const char *Name, GlobalTy &&Global)
|
||||
: PluginImpl(Global), Kind(OL_SYMBOL_KIND_GLOBAL_VARIABLE), Name(Name) {}
|
||||
ol_symbol_impl_t(GenericKernelTy *Kernel)
|
||||
: PluginImpl(Kernel), Kind(OL_SYMBOL_KIND_KERNEL),
|
||||
Name(Kernel->getName()) {}
|
||||
ol_symbol_impl_t(GlobalTy &&Global)
|
||||
: PluginImpl(std::move(Global)), Kind(OL_SYMBOL_KIND_GLOBAL_VARIABLE),
|
||||
Name(std::get<GlobalTy>(PluginImpl).getName()) {}
|
||||
std::variant<GenericKernelTy *, GlobalTy> PluginImpl;
|
||||
ol_symbol_kind_t Kind;
|
||||
llvm::StringRef Name;
|
||||
|
|
@ -1281,12 +1283,11 @@ Error olLaunchKernel_impl(ol_queue_handle_t Queue, ol_device_handle_t Device,
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
Error olGetSymbol_impl(ol_program_handle_t Program, const char *Name,
|
||||
ol_symbol_kind_t Kind, ol_symbol_handle_t *Symbol) {
|
||||
Expected<ol_symbol_handle_t> getSymbolImplDetail(ol_program_handle_t Program,
|
||||
StringRef Name,
|
||||
ol_symbol_kind_t Kind) {
|
||||
auto &Device = Program->Image->getDevice();
|
||||
|
||||
std::lock_guard<std::mutex> Lock(Program->SymbolListMutex);
|
||||
|
||||
switch (Kind) {
|
||||
case OL_SYMBOL_KIND_KERNEL: {
|
||||
auto &Kernel = Program->KernelSymbols[Name];
|
||||
|
|
@ -1298,12 +1299,10 @@ Error olGetSymbol_impl(ol_program_handle_t Program, const char *Name,
|
|||
if (auto Err = KernelImpl->init(Device, *Program->Image))
|
||||
return Err;
|
||||
|
||||
Kernel = std::make_unique<ol_symbol_impl_t>(KernelImpl->getName(),
|
||||
&*KernelImpl);
|
||||
Kernel = std::make_unique<ol_symbol_impl_t>(&*KernelImpl);
|
||||
}
|
||||
|
||||
*Symbol = Kernel.get();
|
||||
return Error::success();
|
||||
return Kernel.get();
|
||||
}
|
||||
case OL_SYMBOL_KIND_GLOBAL_VARIABLE: {
|
||||
auto &Global = Program->GlobalSymbols[Name];
|
||||
|
|
@ -1314,12 +1313,10 @@ Error olGetSymbol_impl(ol_program_handle_t Program, const char *Name,
|
|||
Device, *Program->Image, GlobalObj))
|
||||
return Res;
|
||||
|
||||
Global = std::make_unique<ol_symbol_impl_t>(GlobalObj.getName().c_str(),
|
||||
std::move(GlobalObj));
|
||||
Global = std::make_unique<ol_symbol_impl_t>(std::move(GlobalObj));
|
||||
}
|
||||
|
||||
*Symbol = Global.get();
|
||||
return Error::success();
|
||||
return Global.get();
|
||||
}
|
||||
default:
|
||||
return createOffloadError(ErrorCode::INVALID_ENUMERATION,
|
||||
|
|
@ -1327,6 +1324,50 @@ Error olGetSymbol_impl(ol_program_handle_t Program, const char *Name,
|
|||
}
|
||||
}
|
||||
|
||||
Error olGetSymbol_impl(ol_program_handle_t Program, const char *Name,
|
||||
ol_symbol_kind_t Kind, ol_symbol_handle_t *Symbol) {
|
||||
std::lock_guard<std::mutex> Lock(Program->SymbolListMutex);
|
||||
|
||||
auto SymbolOrErr = getSymbolImplDetail(Program, Name, Kind);
|
||||
if (!SymbolOrErr)
|
||||
return SymbolOrErr.takeError();
|
||||
|
||||
*Symbol = *SymbolOrErr;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error olIterateSymbols_impl(ol_program_handle_t Program, ol_symbol_kind_t Kind,
|
||||
ol_symbol_iterate_cb_t Callback, void *UserData) {
|
||||
SymbolKindTy PluginKind;
|
||||
switch (Kind) {
|
||||
case OL_SYMBOL_KIND_KERNEL:
|
||||
PluginKind = SymbolKindTy::Kernel;
|
||||
break;
|
||||
case OL_SYMBOL_KIND_GLOBAL_VARIABLE:
|
||||
PluginKind = SymbolKindTy::GlobalVariable;
|
||||
break;
|
||||
default:
|
||||
return createOffloadError(ErrorCode::INVALID_ENUMERATION,
|
||||
"iterateSymbols kind enum '%i' is invalid", Kind);
|
||||
}
|
||||
|
||||
auto &Device = Program->Image->getDevice();
|
||||
std::lock_guard<std::mutex> Lock(Program->SymbolListMutex);
|
||||
|
||||
Error SymbolErr = Error::success();
|
||||
Error IterateErr = Device.Plugin.getGlobalHandler().iterateSymbols(
|
||||
*Program->Image, PluginKind, [&](StringRef Name) {
|
||||
auto SymbolOrErr = getSymbolImplDetail(Program, Name, Kind);
|
||||
if (!SymbolOrErr) {
|
||||
SymbolErr = SymbolOrErr.takeError();
|
||||
return false;
|
||||
}
|
||||
return Callback(*SymbolOrErr, UserData);
|
||||
});
|
||||
|
||||
return joinErrors(std::move(IterateErr), std::move(SymbolErr));
|
||||
}
|
||||
|
||||
Error olGetSymbolInfoImplDetail(ol_symbol_handle_t Symbol,
|
||||
ol_symbol_info_t PropName, size_t PropSize,
|
||||
void *PropValue, size_t *PropSizeRet) {
|
||||
|
|
@ -1346,6 +1387,8 @@ Error olGetSymbolInfoImplDetail(ol_symbol_handle_t Symbol,
|
|||
switch (PropName) {
|
||||
case OL_SYMBOL_INFO_KIND:
|
||||
return Info.write<ol_symbol_kind_t>(Symbol->Kind);
|
||||
case OL_SYMBOL_INFO_NAME:
|
||||
return Info.writeString(Symbol->Name);
|
||||
case OL_SYMBOL_INFO_GLOBAL_VARIABLE_ADDRESS:
|
||||
if (auto Err = CheckKind(OL_SYMBOL_KIND_GLOBAL_VARIABLE))
|
||||
return Err;
|
||||
|
|
|
|||
|
|
@ -586,7 +586,7 @@ private:
|
|||
/// generic kernel class.
|
||||
struct AMDGPUKernelTy : public GenericKernelTy {
|
||||
/// Create an AMDGPU kernel with a name and an execution mode.
|
||||
AMDGPUKernelTy(const char *Name) : GenericKernelTy(Name) {}
|
||||
AMDGPUKernelTy(StringRef Name) : GenericKernelTy(Name) {}
|
||||
|
||||
/// Initialize the AMDGPU kernel.
|
||||
Error initImpl(GenericDeviceTy &Device, DeviceImageTy &Image) override {
|
||||
|
|
@ -2636,7 +2636,7 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
|
|||
}
|
||||
|
||||
/// Allocate and construct an AMDGPU kernel.
|
||||
Expected<GenericKernelTy &> constructKernel(const char *Name) override {
|
||||
Expected<GenericKernelTy &> constructKernel(StringRef Name) override {
|
||||
// Allocate and construct the AMDGPU kernel.
|
||||
AMDGPUKernelTy *AMDGPUKernel = Plugin.allocate<AMDGPUKernelTy>();
|
||||
if (!AMDGPUKernel)
|
||||
|
|
@ -3920,6 +3920,35 @@ struct AMDGPUGlobalHandlerTy final : public GenericGlobalHandlerTy {
|
|||
|
||||
return Plugin::success();
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Kernels are represented by a kernel descriptor, which is an object named
|
||||
/// after the function it describes with a '.kd' suffix.
|
||||
std::optional<StringRef> matchSymbol(const ELFSymbolRef &Symbol,
|
||||
StringRef Name,
|
||||
SymbolKindTy Kind) override {
|
||||
if (Symbol.getELFType() != ELF::STT_OBJECT)
|
||||
return std::nullopt;
|
||||
|
||||
StringRef Function = Name;
|
||||
bool IsDescriptor =
|
||||
Function.consume_back(".kd") && isFunction(Symbol, Function);
|
||||
if (IsDescriptor != (Kind == SymbolKindTy::Kernel))
|
||||
return std::nullopt;
|
||||
|
||||
return IsDescriptor ? Function : Name;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Returns whether \p Name is a function in the image containing \p Symbol.
|
||||
static bool isFunction(const ELFSymbolRef &Symbol, StringRef Name) {
|
||||
auto SymbolOrErr = utils::elf::getSymbol(*Symbol.getObject(), Name);
|
||||
if (!SymbolOrErr) {
|
||||
consumeError(SymbolOrErr.takeError());
|
||||
return false;
|
||||
}
|
||||
return *SymbolOrErr && (*SymbolOrErr)->getELFType() == ELF::STT_FUNC;
|
||||
}
|
||||
};
|
||||
|
||||
/// Class implementing the AMDGPU-specific functionalities of the plugin.
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@
|
|||
#ifndef LLVM_OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_GLOBALHANDLER_H
|
||||
#define LLVM_OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_GLOBALHANDLER_H
|
||||
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/STLFunctionalExtras.h"
|
||||
#include "llvm/Object/ELFObjectFile.h"
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
|
@ -35,6 +37,9 @@ struct GenericDeviceTy;
|
|||
|
||||
using namespace llvm::object;
|
||||
|
||||
/// The kinds of symbols that can be enumerated in a device image.
|
||||
enum class SymbolKindTy { Kernel, GlobalVariable };
|
||||
|
||||
/// Common abstraction for globals that live on the host and device.
|
||||
/// It simply encapsulates the symbol name, symbol size, and symbol address
|
||||
/// (which might be host or device depending on the context).
|
||||
|
|
@ -48,7 +53,7 @@ class GlobalTy {
|
|||
void *Ptr;
|
||||
|
||||
public:
|
||||
GlobalTy(const std::string &Name, uint32_t Size = 0, void *Ptr = nullptr)
|
||||
GlobalTy(StringRef Name, uint32_t Size = 0, void *Ptr = nullptr)
|
||||
: Name(Name), Size(Size), Ptr(Ptr) {}
|
||||
|
||||
const std::string &getName() const { return Name; }
|
||||
|
|
@ -216,6 +221,21 @@ public:
|
|||
/// with profiling prefixes.
|
||||
Expected<GPUProfGlobals> readProfilingGlobals(GenericDeviceTy &Device,
|
||||
DeviceImageTy &Image);
|
||||
|
||||
/// Enumerate the names of the symbols of the given \p Kind in \p Image,
|
||||
/// stopping early if \p Callback returns false.
|
||||
virtual Error iterateSymbols(DeviceImageTy &Image, SymbolKindTy Kind,
|
||||
function_ref<bool(StringRef)> Callback);
|
||||
|
||||
protected:
|
||||
/// Returns whether a symbol with the given \p Flags is defined by and
|
||||
/// exported from the image, and therefore usable by the runtime.
|
||||
virtual bool isExportedSymbol(uint32_t Flags);
|
||||
|
||||
/// Returns the name \p Symbol is known by if it identifies a symbol of the
|
||||
/// given \p Kind, otherwise std::nullopt.
|
||||
virtual std::optional<StringRef>
|
||||
matchSymbol(const ELFSymbolRef &Symbol, StringRef Name, SymbolKindTy Kind);
|
||||
};
|
||||
|
||||
} // namespace plugin
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ public:
|
|||
/// implement the necessary virtual function members.
|
||||
struct GenericKernelTy {
|
||||
/// Construct a kernel with a name and a execution mode.
|
||||
GenericKernelTy(const char *Name)
|
||||
GenericKernelTy(StringRef Name)
|
||||
: Name(Name), PreferredNumThreads(0), MaxNumThreads(0) {}
|
||||
|
||||
virtual ~GenericKernelTy() {}
|
||||
|
|
@ -1266,7 +1266,7 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
|
|||
}
|
||||
|
||||
/// Allocate and construct a kernel object.
|
||||
virtual Expected<GenericKernelTy &> constructKernel(const char *Name) = 0;
|
||||
virtual Expected<GenericKernelTy &> constructKernel(StringRef Name) = 0;
|
||||
|
||||
/// Reference to the underlying plugin that created this device.
|
||||
GenericPluginTy &Plugin;
|
||||
|
|
|
|||
|
|
@ -193,6 +193,55 @@ Error GenericGlobalHandlerTy::readGlobalFromImage(GenericDeviceTy &Device,
|
|||
return Plugin::success();
|
||||
}
|
||||
|
||||
bool GenericGlobalHandlerTy::isExportedSymbol(uint32_t Flags) {
|
||||
uint32_t Ignored = SymbolRef::SF_Undefined | SymbolRef::SF_Hidden |
|
||||
SymbolRef::SF_FormatSpecific;
|
||||
return (Flags & SymbolRef::SF_Global) && !(Flags & Ignored);
|
||||
}
|
||||
|
||||
std::optional<StringRef>
|
||||
GenericGlobalHandlerTy::matchSymbol(const ELFSymbolRef &Symbol, StringRef Name,
|
||||
SymbolKindTy Kind) {
|
||||
uint8_t Type = Kind == SymbolKindTy::Kernel ? ELF::STT_FUNC : ELF::STT_OBJECT;
|
||||
if (Symbol.getELFType() != Type)
|
||||
return std::nullopt;
|
||||
return Name;
|
||||
}
|
||||
|
||||
Error GenericGlobalHandlerTy::iterateSymbols(
|
||||
DeviceImageTy &Image, SymbolKindTy Kind,
|
||||
function_ref<bool(StringRef)> Callback) {
|
||||
auto ELFObjOrErr = getELFObjectFile(Image);
|
||||
if (!ELFObjOrErr)
|
||||
return ELFObjOrErr.takeError();
|
||||
|
||||
auto &ELFObj = cast<ELFObjectFileBase>(**ELFObjOrErr);
|
||||
auto Symbols = ELFObj.symbols();
|
||||
if (Symbols.empty())
|
||||
Symbols = ELFObj.getDynamicSymbolIterators();
|
||||
|
||||
for (ELFSymbolRef Symbol : Symbols) {
|
||||
auto FlagsOrErr = Symbol.getFlags();
|
||||
if (!FlagsOrErr)
|
||||
return Plugin::error(ErrorCode::INVALID_BINARY, FlagsOrErr.takeError(),
|
||||
"error reading ELF symbol");
|
||||
|
||||
if (!isExportedSymbol(*FlagsOrErr))
|
||||
continue;
|
||||
|
||||
auto NameOrErr = Symbol.getName();
|
||||
if (!NameOrErr)
|
||||
return Plugin::error(ErrorCode::INVALID_BINARY, NameOrErr.takeError(),
|
||||
"error reading ELF symbol name");
|
||||
|
||||
if (auto Name = matchSymbol(Symbol, *NameOrErr, Kind))
|
||||
if (!Callback(*Name))
|
||||
break;
|
||||
}
|
||||
|
||||
return Plugin::success();
|
||||
}
|
||||
|
||||
Expected<GPUProfGlobals>
|
||||
GenericGlobalHandlerTy::readProfilingGlobals(GenericDeviceTy &Device,
|
||||
DeviceImageTy &Image) {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ private:
|
|||
/// generic kernel class.
|
||||
struct CUDAKernelTy : public GenericKernelTy {
|
||||
/// Create a CUDA kernel with a name and an execution mode.
|
||||
CUDAKernelTy(const char *Name) : GenericKernelTy(Name), Func(nullptr) {}
|
||||
CUDAKernelTy(StringRef Name) : GenericKernelTy(Name), Func(nullptr) {}
|
||||
|
||||
/// Initialize the CUDA kernel.
|
||||
Error initImpl(GenericDeviceTy &GenericDevice,
|
||||
|
|
@ -512,7 +512,7 @@ struct CUDADeviceTy : public GenericDeviceTy {
|
|||
}
|
||||
|
||||
/// Allocate and construct a CUDA kernel.
|
||||
Expected<GenericKernelTy &> constructKernel(const char *Name) override {
|
||||
Expected<GenericKernelTy &> constructKernel(StringRef Name) override {
|
||||
// Allocate and construct the CUDA kernel.
|
||||
CUDAKernelTy *CUDAKernel = Plugin.allocate<CUDAKernelTy>();
|
||||
if (!CUDAKernel)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ using namespace error;
|
|||
/// Class implementing kernel functionalities for GenELF64.
|
||||
struct GenELF64KernelTy : public GenericKernelTy {
|
||||
/// Construct the kernel with a name and an execution mode.
|
||||
GenELF64KernelTy(const char *Name) : GenericKernelTy(Name), Func(nullptr) {}
|
||||
GenELF64KernelTy(StringRef Name) : GenericKernelTy(Name), Func(nullptr) {}
|
||||
|
||||
/// Initialize the kernel.
|
||||
Error initImpl(GenericDeviceTy &Device, DeviceImageTy &Image) override {
|
||||
|
|
@ -165,7 +165,7 @@ struct GenELF64DeviceTy : public GenericDeviceTy {
|
|||
std::string getComputeUnitKind() const override { return "generic-64bit"; }
|
||||
|
||||
/// Construct the kernel for a specific image on the device.
|
||||
Expected<GenericKernelTy &> constructKernel(const char *Name) override {
|
||||
Expected<GenericKernelTy &> constructKernel(StringRef Name) override {
|
||||
// Allocate and construct the kernel.
|
||||
GenELF64KernelTy *GenELF64Kernel = Plugin.allocate<GenELF64KernelTy>();
|
||||
if (!GenELF64Kernel)
|
||||
|
|
|
|||
|
|
@ -576,7 +576,7 @@ public:
|
|||
V = 0;
|
||||
return Plugin::success();
|
||||
}
|
||||
Expected<GenericKernelTy &> constructKernel(const char *Name) override;
|
||||
Expected<GenericKernelTy &> constructKernel(StringRef Name) override;
|
||||
|
||||
Error callGlobalConstructors(GenericPluginTy &Plugin,
|
||||
DeviceImageTy &Image) override;
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class L0KernelTy : public GenericKernelTy {
|
|||
|
||||
public:
|
||||
/// Create a L0 kernel with a name and an execution mode.
|
||||
L0KernelTy(const char *Name) : GenericKernelTy(Name), zeKernel(nullptr) {}
|
||||
L0KernelTy(StringRef Name) : GenericKernelTy(Name), zeKernel(nullptr) {}
|
||||
~L0KernelTy() = default;
|
||||
L0KernelTy(const L0KernelTy &) = delete;
|
||||
L0KernelTy(L0KernelTy &&) = delete;
|
||||
|
|
|
|||
|
|
@ -126,6 +126,9 @@ struct L0GlobalHandlerTy final : public GenericGlobalHandlerTy {
|
|||
Error getGlobalMetadataFromDevice(GenericDeviceTy &Device,
|
||||
DeviceImageTy &Image,
|
||||
GlobalTy &DeviceGlobal) override;
|
||||
|
||||
protected:
|
||||
bool isExportedSymbol(uint32_t Flags) override;
|
||||
};
|
||||
|
||||
bool isValidOneOmpImage(StringRef Image, uint64_t &MajorVer,
|
||||
|
|
|
|||
|
|
@ -554,7 +554,7 @@ Expected<InfoTreeNode> L0DeviceTy::obtainInfoImpl() {
|
|||
return Info;
|
||||
}
|
||||
|
||||
Expected<GenericKernelTy &> L0DeviceTy::constructKernel(const char *Name) {
|
||||
Expected<GenericKernelTy &> L0DeviceTy::constructKernel(StringRef Name) {
|
||||
// Allocate and construct the L0 kernel.
|
||||
L0KernelTy *L0Kernel = getPlugin().allocate<L0KernelTy>();
|
||||
if (!L0Kernel)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,14 @@ Error L0GlobalHandlerTy::getGlobalMetadataFromDevice(GenericDeviceTy &Device,
|
|||
return Plugin::success();
|
||||
}
|
||||
|
||||
bool L0GlobalHandlerTy::isExportedSymbol(uint32_t Flags) {
|
||||
// Images returned by the Level Zero runtime do not correctly expose kernel
|
||||
// functions as global symbols. Bypass the normal ELF handling.here.
|
||||
uint32_t Ignored = SymbolRef::SF_Undefined | SymbolRef::SF_Hidden |
|
||||
SymbolRef::SF_FormatSpecific;
|
||||
return !(Flags & Ignored);
|
||||
}
|
||||
|
||||
inline L0DeviceTy &L0ProgramTy::getL0Device() const {
|
||||
return L0DeviceTy::makeL0Device(getDevice());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,4 +65,5 @@ add_offload_unittest("queue"
|
|||
add_offload_unittest("symbol"
|
||||
symbol/olGetSymbol.cpp
|
||||
symbol/olGetSymbolInfo.cpp
|
||||
symbol/olGetSymbolInfoSize.cpp)
|
||||
symbol/olGetSymbolInfoSize.cpp
|
||||
symbol/olIterateSymbols.cpp)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,24 @@ TEST_P(olGetSymbolInfoGlobalTest, SuccessKind) {
|
|||
ASSERT_EQ(RetrievedKind, OL_SYMBOL_KIND_GLOBAL_VARIABLE);
|
||||
}
|
||||
|
||||
TEST_P(olGetSymbolInfoKernelTest, SuccessName) {
|
||||
size_t Size = 0;
|
||||
ASSERT_SUCCESS(olGetSymbolInfoSize(Kernel, OL_SYMBOL_INFO_NAME, &Size));
|
||||
std::vector<char> Name(Size);
|
||||
ASSERT_SUCCESS(
|
||||
olGetSymbolInfo(Kernel, OL_SYMBOL_INFO_NAME, Size, Name.data()));
|
||||
ASSERT_STREQ(Name.data(), "foo");
|
||||
}
|
||||
|
||||
TEST_P(olGetSymbolInfoGlobalTest, SuccessName) {
|
||||
size_t Size = 0;
|
||||
ASSERT_SUCCESS(olGetSymbolInfoSize(Global, OL_SYMBOL_INFO_NAME, &Size));
|
||||
std::vector<char> Name(Size);
|
||||
ASSERT_SUCCESS(
|
||||
olGetSymbolInfo(Global, OL_SYMBOL_INFO_NAME, Size, Name.data()));
|
||||
ASSERT_STREQ(Name.data(), "global");
|
||||
}
|
||||
|
||||
TEST_P(olGetSymbolInfoKernelTest, InvalidAddress) {
|
||||
void *RetrievedAddr;
|
||||
ASSERT_ERROR(OL_ERRC_SYMBOL_KIND,
|
||||
|
|
|
|||
118
offload/unittests/OffloadAPI/symbol/olIterateSymbols.cpp
Normal file
118
offload/unittests/OffloadAPI/symbol/olIterateSymbols.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
//===------- Offload API tests - olIterateSymbols -------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "../common/Fixtures.hpp"
|
||||
#include <OffloadAPI.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// The 'global' program contains the 'read' and 'write' kernels as well as the
|
||||
// 'global' global variable.
|
||||
struct olIterateSymbolsTest : OffloadProgramTest {
|
||||
void SetUp() override { SetUpWith("global"); }
|
||||
};
|
||||
OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(olIterateSymbolsTest);
|
||||
|
||||
using SymbolVecT = std::vector<ol_symbol_handle_t>;
|
||||
|
||||
static bool collectSymbol(ol_symbol_handle_t Symbol, void *Data) {
|
||||
static_cast<SymbolVecT *>(Data)->push_back(Symbol);
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string getName(ol_symbol_handle_t Symbol) {
|
||||
size_t Size = 0;
|
||||
if (olGetSymbolInfoSize(Symbol, OL_SYMBOL_INFO_NAME, &Size))
|
||||
return {};
|
||||
std::vector<char> Name(Size);
|
||||
if (olGetSymbolInfo(Symbol, OL_SYMBOL_INFO_NAME, Size, Name.data()))
|
||||
return {};
|
||||
return std::string{Name.data()};
|
||||
}
|
||||
|
||||
static std::vector<std::string> getNames(const SymbolVecT &Symbols,
|
||||
ol_symbol_kind_t Expected) {
|
||||
std::vector<std::string> Names;
|
||||
for (auto *Symbol : Symbols) {
|
||||
ol_symbol_kind_t Kind;
|
||||
if (olGetSymbolInfo(Symbol, OL_SYMBOL_INFO_KIND, sizeof(Kind), &Kind))
|
||||
return {};
|
||||
EXPECT_EQ(Kind, Expected);
|
||||
Names.push_back(getName(Symbol));
|
||||
}
|
||||
return Names;
|
||||
}
|
||||
|
||||
static bool contains(const std::vector<std::string> &Names,
|
||||
const std::string &Name) {
|
||||
return std::find(Names.begin(), Names.end(), Name) != Names.end();
|
||||
}
|
||||
|
||||
TEST_P(olIterateSymbolsTest, SuccessKernels) {
|
||||
SymbolVecT Symbols;
|
||||
ASSERT_SUCCESS(olIterateSymbols(Program, OL_SYMBOL_KIND_KERNEL, collectSymbol,
|
||||
&Symbols));
|
||||
|
||||
auto Names = getNames(Symbols, OL_SYMBOL_KIND_KERNEL);
|
||||
ASSERT_TRUE(contains(Names, "read"));
|
||||
ASSERT_TRUE(contains(Names, "write"));
|
||||
}
|
||||
|
||||
TEST_P(olIterateSymbolsTest, SuccessGlobals) {
|
||||
SymbolVecT Symbols;
|
||||
ASSERT_SUCCESS_OR_UNSUPPORTED(olIterateSymbols(
|
||||
Program, OL_SYMBOL_KIND_GLOBAL_VARIABLE, collectSymbol, &Symbols));
|
||||
|
||||
auto Names = getNames(Symbols, OL_SYMBOL_KIND_GLOBAL_VARIABLE);
|
||||
ASSERT_TRUE(contains(Names, "global"));
|
||||
}
|
||||
|
||||
TEST_P(olIterateSymbolsTest, SuccessSameSymbol) {
|
||||
SymbolVecT Symbols;
|
||||
ASSERT_SUCCESS(olIterateSymbols(Program, OL_SYMBOL_KIND_KERNEL, collectSymbol,
|
||||
&Symbols));
|
||||
ASSERT_FALSE(Symbols.empty());
|
||||
|
||||
for (auto *Symbol : Symbols) {
|
||||
ol_symbol_handle_t Looked = nullptr;
|
||||
ASSERT_SUCCESS(olGetSymbol(Program, getName(Symbol).c_str(),
|
||||
OL_SYMBOL_KIND_KERNEL, &Looked));
|
||||
ASSERT_EQ(Symbol, Looked);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(olIterateSymbolsTest, SuccessStopIteration) {
|
||||
size_t Count = 0;
|
||||
ASSERT_SUCCESS(olIterateSymbols(
|
||||
Program, OL_SYMBOL_KIND_KERNEL,
|
||||
[](ol_symbol_handle_t, void *Data) {
|
||||
(*static_cast<size_t *>(Data))++;
|
||||
return false;
|
||||
},
|
||||
&Count));
|
||||
ASSERT_EQ(Count, 1u);
|
||||
}
|
||||
|
||||
TEST_P(olIterateSymbolsTest, InvalidNullProgram) {
|
||||
SymbolVecT Symbols;
|
||||
ASSERT_ERROR(OL_ERRC_INVALID_NULL_HANDLE,
|
||||
olIterateSymbols(nullptr, OL_SYMBOL_KIND_KERNEL, collectSymbol,
|
||||
&Symbols));
|
||||
}
|
||||
|
||||
TEST_P(olIterateSymbolsTest, InvalidNullCallback) {
|
||||
ASSERT_ERROR(
|
||||
OL_ERRC_INVALID_NULL_POINTER,
|
||||
olIterateSymbols(Program, OL_SYMBOL_KIND_KERNEL, nullptr, nullptr));
|
||||
}
|
||||
|
||||
TEST_P(olIterateSymbolsTest, InvalidKind) {
|
||||
SymbolVecT Symbols;
|
||||
ASSERT_ERROR(OL_ERRC_INVALID_ENUMERATION,
|
||||
olIterateSymbols(Program, OL_SYMBOL_KIND_FORCE_UINT32,
|
||||
collectSymbol, &Symbols));
|
||||
}
|
||||
Loading…
Reference in a new issue