From e2132de30efa7be0a91fa3f7174b895f6dee4c83 Mon Sep 17 00:00:00 2001 From: Neil R Spruit Date: Sat, 28 May 2022 00:18:38 +0000 Subject: [PATCH] L0 Function Pointer Handling for kernels & correct error - Enable Support for L0 Function Pointers for Kernels and Exported Functions - Return ZE_RESULT_ERROR_INVALID_FUNCTION_NAME given no function of that name is a kernel or exported function Signed-off-by: Neil R Spruit --- level_zero/core/source/module/module_imp.cpp | 24 +++- .../unit_tests/sources/module/test_module.cpp | 110 ++++++++++++++++++ 2 files changed, 131 insertions(+), 3 deletions(-) diff --git a/level_zero/core/source/module/module_imp.cpp b/level_zero/core/source/module/module_imp.cpp index 28066d264b..3c711ef8c2 100644 --- a/level_zero/core/source/module/module_imp.cpp +++ b/level_zero/core/source/module/module_imp.cpp @@ -845,12 +845,30 @@ bool ModuleImp::linkBinary() { } ze_result_t ModuleImp::getFunctionPointer(const char *pFunctionName, void **pfnFunction) { + // Check if the function is in the exported symbol table auto symbolIt = symbols.find(pFunctionName); - if ((symbolIt == symbols.end()) || (symbolIt->second.symbol.segment != NEO::SegmentType::Instructions)) { - return ZE_RESULT_ERROR_INVALID_ARGUMENT; + if ((symbolIt != symbols.end()) && (symbolIt->second.symbol.segment == NEO::SegmentType::Instructions)) { + *pfnFunction = reinterpret_cast(symbolIt->second.gpuAddress); + } + // If the Function Pointer is not in the exported symbol table, then this function might be a kernel. + // Check if the function name matches a kernel and return the gpu address to that function + if (*pfnFunction == nullptr) { + auto kernelImmData = this->getKernelImmutableData(pFunctionName); + if (kernelImmData != nullptr) { + auto isaAllocation = kernelImmData->getIsaGraphicsAllocation(); + *pfnFunction = reinterpret_cast(isaAllocation->getGpuAddress()); + // Ensure that any kernel in this module which uses this kernel module function pointer has access to the memory. + for (auto &data : this->getKernelImmutableDataVector()) { + if (data.get() != kernelImmData) { + data.get()->getResidencyContainer().insert(data.get()->getResidencyContainer().end(), isaAllocation); + } + } + } } - *pfnFunction = reinterpret_cast(symbolIt->second.gpuAddress); + if (*pfnFunction == nullptr) { + return ZE_RESULT_ERROR_INVALID_FUNCTION_NAME; + } return ZE_RESULT_SUCCESS; } diff --git a/level_zero/core/test/unit_tests/sources/module/test_module.cpp b/level_zero/core/test/unit_tests/sources/module/test_module.cpp index 6b8a13891d..913089846a 100644 --- a/level_zero/core/test/unit_tests/sources/module/test_module.cpp +++ b/level_zero/core/test/unit_tests/sources/module/test_module.cpp @@ -1144,6 +1144,18 @@ TEST_F(ModulePropertyTest, givenCallToGetPropertiesWithUnresolvedSymbolsThenFlag EXPECT_EQ(expectedFlags, moduleProperties.flags); } +struct ModuleFunctionPointerTests : public Test { + void SetUp() override { + Test::SetUp(); + module0 = std::make_unique>(device, nullptr, ModuleType::User); + } + void TearDown() override { + module0.reset(nullptr); + Test::TearDown(); + } + std::unique_ptr> module0; +}; + struct ModuleDynamicLinkTests : public Test { void SetUp() override { Test::SetUp(); @@ -1726,6 +1738,104 @@ TEST_F(ModuleDynamicLinkTests, givenModuleWithFunctionDependenciesWhenOtherModul EXPECT_EQ(ZE_RESULT_ERROR_MODULE_LINK_FAILURE, res); } +TEST_F(ModuleFunctionPointerTests, givenModuleWithExportedSymbolThenGetFunctionPointerReturnsGpuAddressToFunction) { + + uint64_t gpuAddress = 0x12345; + + NEO::SymbolInfo symbolInfo{}; + symbolInfo.segment = NEO::SegmentType::Instructions; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + + char kernelHeap[MemoryConstants::pageSize] = {}; + + auto kernelInfo = std::make_unique(); + kernelInfo->heapInfo.pKernelHeap = kernelHeap; + kernelInfo->heapInfo.KernelHeapSize = MemoryConstants::pageSize; + module0->getTranslationUnit()->programInfo.kernelInfos.push_back(kernelInfo.release()); + + auto kernelImmData = std::make_unique>(device); + kernelImmData->isaGraphicsAllocation.reset(neoDevice->getMemoryManager()->allocateGraphicsMemoryWithProperties( + {device->getRootDeviceIndex(), MemoryConstants::pageSize, NEO::AllocationType::KERNEL_ISA, neoDevice->getDeviceBitfield()})); + + module0->kernelImmDatas.push_back(std::move(kernelImmData)); + + module0->symbols["externalFunction"] = relocatedSymbol; + + void *functionPointer = nullptr; + ze_result_t res = module0->getFunctionPointer("externalFunction", &functionPointer); + EXPECT_EQ(ZE_RESULT_SUCCESS, res); + + EXPECT_EQ(reinterpret_cast(functionPointer), gpuAddress); +} + +TEST_F(ModuleFunctionPointerTests, givenInvalidFunctionNameAndModuleWithExportedSymbolThenGetFunctionPointerReturnsFailure) { + + uint64_t gpuAddress = 0x12345; + + NEO::SymbolInfo symbolInfo{}; + symbolInfo.segment = NEO::SegmentType::Instructions; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + + char kernelHeap[MemoryConstants::pageSize] = {}; + + auto kernelInfo = std::make_unique(); + kernelInfo->heapInfo.pKernelHeap = kernelHeap; + kernelInfo->heapInfo.KernelHeapSize = MemoryConstants::pageSize; + kernelInfo->kernelDescriptor.kernelMetadata.kernelName = "kernelFunction"; + module0->getTranslationUnit()->programInfo.kernelInfos.push_back(kernelInfo.release()); + NEO::KernelDescriptor kernelDescriptor; + kernelDescriptor.kernelMetadata.kernelName = "kernelFunction"; + + auto kernelImmData = std::make_unique>(device); + kernelImmData->isaGraphicsAllocation.reset(neoDevice->getMemoryManager()->allocateGraphicsMemoryWithProperties( + {device->getRootDeviceIndex(), MemoryConstants::pageSize, NEO::AllocationType::KERNEL_ISA, neoDevice->getDeviceBitfield()})); + + kernelImmData->kernelDescriptor = &kernelDescriptor; + printf("kern %p\n", kernelImmData->kernelDescriptor); + module0->kernelImmDatas.push_back(std::move(kernelImmData)); + + module0->symbols["externalFunction"] = relocatedSymbol; + + void *functionPointer = nullptr; + ze_result_t res = module0->getFunctionPointer("Invalid", &functionPointer); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_FUNCTION_NAME, res); +} + +TEST_F(ModuleFunctionPointerTests, givenModuleWithExportedSymbolThenGetFunctionPointerReturnsGpuAddressToKernelFunction) { + + uint64_t gpuAddress = 0x12345; + + NEO::SymbolInfo symbolInfo{}; + symbolInfo.segment = NEO::SegmentType::Instructions; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + + char kernelHeap[MemoryConstants::pageSize] = {}; + + auto kernelInfo = std::make_unique(); + kernelInfo->heapInfo.pKernelHeap = kernelHeap; + kernelInfo->heapInfo.KernelHeapSize = MemoryConstants::pageSize; + kernelInfo->kernelDescriptor.kernelMetadata.kernelName = "kernelFunction"; + module0->getTranslationUnit()->programInfo.kernelInfos.push_back(kernelInfo.release()); + NEO::KernelDescriptor kernelDescriptor; + kernelDescriptor.kernelMetadata.kernelName = "kernelFunction"; + + auto kernelImmData = std::make_unique>(device); + kernelImmData->isaGraphicsAllocation.reset(neoDevice->getMemoryManager()->allocateGraphicsMemoryWithProperties( + {device->getRootDeviceIndex(), MemoryConstants::pageSize, NEO::AllocationType::KERNEL_ISA, neoDevice->getDeviceBitfield()})); + + kernelImmData->kernelDescriptor = &kernelDescriptor; + printf("kern %p\n", kernelImmData->kernelDescriptor); + module0->kernelImmDatas.push_back(std::move(kernelImmData)); + + module0->symbols["externalFunction"] = relocatedSymbol; + + void *functionPointer = nullptr; + ze_result_t res = module0->getFunctionPointer("kernelFunction", &functionPointer); + EXPECT_EQ(ZE_RESULT_SUCCESS, res); + + EXPECT_EQ(reinterpret_cast(functionPointer), module0->kernelImmDatas[0]->getIsaGraphicsAllocation()->getGpuAddress()); +} + class DeviceModuleSetArgBufferTest : public ModuleFixture, public ::testing::Test { public: void SetUp() override {