diff --git a/level_zero/api/core/ze_module.cpp b/level_zero/api/core/ze_module.cpp index 8535e9338e..561effa63f 100644 --- a/level_zero/api/core/ze_module.cpp +++ b/level_zero/api/core/ze_module.cpp @@ -8,6 +8,8 @@ #include "level_zero/core/source/module/module.h" #include +#include "third_party/level_zero/ze_api_ext.h" + extern "C" { __zedllexport ze_result_t __zecall @@ -200,4 +202,19 @@ zeCommandListAppendLaunchMultipleKernelsIndirect( return L0::CommandList::fromHandle(hCommandList)->appendLaunchMultipleKernelsIndirect(numKernels, phKernels, pCountBuffer, pLaunchArgumentsBuffer, hSignalEvent, numWaitEvents, phWaitEvents); } +ZE_APIEXPORT ze_result_t ZE_APICALL +zeKernelGetPropertiesExt( + ze_kernel_handle_t hKernel, + ze_kernel_propertiesExt_t *pKernelProperties) { + return L0::Kernel::fromHandle(hKernel)->getPropertiesExt(pKernelProperties); +} + +ZE_APIEXPORT ze_result_t ZE_APICALL +zeModuleDynamicLinkExt( + uint32_t numModules, + ze_module_handle_t *phModules, + ze_module_build_log_handle_t *phLinkLog) { + return L0::Module::fromHandle(phModules[0])->performDynamicLink(numModules, phModules, phLinkLog); +} + } // extern "C" diff --git a/level_zero/core/source/kernel/kernel.h b/level_zero/core/source/kernel/kernel.h index 95f52dd3d7..d674f48a36 100644 --- a/level_zero/core/source/kernel/kernel.h +++ b/level_zero/core/source/kernel/kernel.h @@ -14,6 +14,8 @@ #include +#include "third_party/level_zero/ze_api_ext.h" + #include #include @@ -93,6 +95,7 @@ struct Kernel : _ze_kernel_handle_t, virtual NEO::DispatchKernelEncoderI { virtual ze_result_t getAttribute(ze_kernel_attribute_t attr, uint32_t *pSize, void *pValue) = 0; virtual ze_result_t setIntermediateCacheConfig(ze_cache_config_t cacheConfig) = 0; virtual ze_result_t getProperties(ze_kernel_properties_t *pKernelProperties) = 0; + virtual ze_result_t getPropertiesExt(ze_kernel_propertiesExt_t *pKernelProperties) = 0; virtual ze_result_t setArgumentValue(uint32_t argIndex, size_t argSize, const void *pArgValue) = 0; virtual void setGroupCount(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) = 0; diff --git a/level_zero/core/source/kernel/kernel_imp.cpp b/level_zero/core/source/kernel/kernel_imp.cpp index 39d6b1e808..bd102271df 100644 --- a/level_zero/core/source/kernel/kernel_imp.cpp +++ b/level_zero/core/source/kernel/kernel_imp.cpp @@ -539,10 +539,10 @@ ze_result_t KernelImp::setArgSampler(uint32_t argIndex, size_t argSize, const vo } ze_result_t KernelImp::getProperties(ze_kernel_properties_t *pKernelProperties) { - size_t kernel_name_size = std::min(this->kernelImmData->getDescriptor().kernelMetadata.kernelName.size(), - static_cast(ZE_MAX_KERNEL_NAME)); + size_t kernelNameSize = std::min(this->kernelImmData->getDescriptor().kernelMetadata.kernelName.size(), + static_cast(ZE_MAX_KERNEL_NAME)); strncpy_s(pKernelProperties->name, ZE_MAX_KERNEL_NAME, - this->kernelImmData->getDescriptor().kernelMetadata.kernelName.c_str(), kernel_name_size); + this->kernelImmData->getDescriptor().kernelMetadata.kernelName.c_str(), kernelNameSize); pKernelProperties->requiredGroupSizeX = this->groupSize[0]; pKernelProperties->requiredGroupSizeY = this->groupSize[1]; @@ -554,6 +554,32 @@ ze_result_t KernelImp::getProperties(ze_kernel_properties_t *pKernelProperties) return ZE_RESULT_SUCCESS; } +ze_result_t KernelImp::getPropertiesExt(ze_kernel_propertiesExt_t *pKernelProperties) { + size_t kernelNameSize = std::min(this->kernelImmData->getDescriptor().kernelMetadata.kernelName.size(), + static_cast(ZE_MAX_KERNEL_NAME)); + strncpy_s(pKernelProperties->name, ZE_MAX_KERNEL_NAME, + this->kernelImmData->getDescriptor().kernelMetadata.kernelName.c_str(), kernelNameSize); + + pKernelProperties->requiredGroupSizeX = this->groupSize[0]; + pKernelProperties->requiredGroupSizeY = this->groupSize[1]; + pKernelProperties->requiredGroupSizeZ = this->groupSize[2]; + + pKernelProperties->numKernelArgs = + static_cast(this->kernelImmData->getDescriptor().payloadMappings.explicitArgs.size()); + + pKernelProperties->requiredNumSubGroups = 0; + pKernelProperties->requiredSubgroupSize = 0; + pKernelProperties->maxSubgroupSize = 0; + pKernelProperties->maxNumSubgroups = 0; + pKernelProperties->localMemSize = 0; + pKernelProperties->privateMemSize = 0; + pKernelProperties->spillMemSize = 0; + memset(pKernelProperties->uuid.kid, 0, ZE_MAX_KERNEL_UUID_SIZE); + memset(pKernelProperties->uuid.mid, 0, ZE_MAX_MODULE_UUID_SIZE); + + return ZE_RESULT_SUCCESS; +} + ze_result_t KernelImp::initialize(const ze_kernel_desc_t *desc) { this->kernelImmData = module->getKernelImmutableData(desc->pKernelName); if (this->kernelImmData == nullptr) { diff --git a/level_zero/core/source/kernel/kernel_imp.h b/level_zero/core/source/kernel/kernel_imp.h index f764f3628a..05b513cc47 100644 --- a/level_zero/core/source/kernel/kernel_imp.h +++ b/level_zero/core/source/kernel/kernel_imp.h @@ -34,6 +34,8 @@ struct KernelImp : Kernel { ze_result_t getProperties(ze_kernel_properties_t *pKernelProperties) override; + ze_result_t getPropertiesExt(ze_kernel_propertiesExt_t *pKernelProperties) override; + ze_result_t setIntermediateCacheConfig(ze_cache_config_t cacheConfig) override { return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; } diff --git a/level_zero/core/source/module/module.h b/level_zero/core/source/module/module.h index e64cade2b8..a878ad7184 100644 --- a/level_zero/core/source/module/module.h +++ b/level_zero/core/source/module/module.h @@ -35,6 +35,9 @@ struct Module : _ze_module_handle_t { virtual ze_result_t getGlobalPointer(const char *pGlobalName, void **pPtr) = 0; virtual ze_result_t getDebugInfo(size_t *pDebugDataSize, uint8_t *pDebugData) = 0; virtual ze_result_t getKernelNames(uint32_t *pCount, const char **pNames) = 0; + virtual ze_result_t performDynamicLink(uint32_t numModules, + ze_module_handle_t *phModules, + ze_module_build_log_handle_t *phLinkLog) = 0; virtual const KernelImmutableData *getKernelImmutableData(const char *functionName) const = 0; virtual const std::vector> &getKernelImmutableDataVector() const = 0; diff --git a/level_zero/core/source/module/module_imp.cpp b/level_zero/core/source/module/module_imp.cpp index 6a1b03b219..23a5257fee 100644 --- a/level_zero/core/source/module/module_imp.cpp +++ b/level_zero/core/source/module/module_imp.cpp @@ -544,6 +544,12 @@ void ModuleImp::verifyDebugCapabilities() { debugEnabled = debugCapabilities; } +ze_result_t ModuleImp::performDynamicLink(uint32_t numModules, + ze_module_handle_t *phModules, + ze_module_build_log_handle_t *phLinkLog) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + bool moveBuildOption(std::string &dstOptionsSet, std::string &srcOptionSet, ConstStringRef dstOptionName, ConstStringRef srcOptionName) { auto optInSrcPos = srcOptionSet.find(srcOptionName.begin()); if (std::string::npos == optInSrcPos) { diff --git a/level_zero/core/source/module/module_imp.h b/level_zero/core/source/module/module_imp.h index 6794846f55..080e247a9a 100644 --- a/level_zero/core/source/module/module_imp.h +++ b/level_zero/core/source/module/module_imp.h @@ -79,6 +79,10 @@ struct ModuleImp : public Module { ze_result_t getKernelNames(uint32_t *pCount, const char **pNames) override; + ze_result_t performDynamicLink(uint32_t numModules, + ze_module_handle_t *phModules, + ze_module_build_log_handle_t *phLinkLog) override; + ze_result_t getDebugInfo(size_t *pDebugDataSize, uint8_t *pDebugData) override; const KernelImmutableData *getKernelImmutableData(const char *functionName) const override; diff --git a/level_zero/core/test/unit_tests/fixtures/module_fixture.h b/level_zero/core/test/unit_tests/fixtures/module_fixture.h index 859db37a1e..3f729b483d 100644 --- a/level_zero/core/test/unit_tests/fixtures/module_fixture.h +++ b/level_zero/core/test/unit_tests/fixtures/module_fixture.h @@ -60,6 +60,7 @@ struct ModuleFixture : public DeviceFixture { const std::string binaryFilename = "test_kernel"; const std::string kernelName = "test"; + const uint32_t numKernelArguments = 6; std::unique_ptr module; std::unique_ptr> kernel; }; diff --git a/level_zero/core/test/unit_tests/mocks/mock_module.h b/level_zero/core/test/unit_tests/mocks/mock_module.h index 09a18ea6f8..ae5d63d04c 100644 --- a/level_zero/core/test/unit_tests/mocks/mock_module.h +++ b/level_zero/core/test/unit_tests/mocks/mock_module.h @@ -39,6 +39,9 @@ struct Mock : public Module { MOCK_METHOD(const L0::KernelImmutableData *, getKernelImmutableData, (const char *functionName), (const, override)); MOCK_METHOD(uint32_t, getMaxGroupSize, (), (const, override)); MOCK_METHOD(ze_result_t, getKernelNames, (uint32_t * pCount, const char **pNames), (override)); + MOCK_METHOD(ze_result_t, performDynamicLink, + (uint32_t numModules, ze_module_handle_t *phModules, ze_module_build_log_handle_t *phLinkLog), + (override)); MOCK_METHOD(ze_result_t, getGlobalPointer, (const char *pGlobalName, void **pPtr), (override)); MOCK_METHOD(bool, isDebugEnabled, (), (const, override)); }; diff --git a/level_zero/core/test/unit_tests/sources/kernel/test_kernel.cpp b/level_zero/core/test/unit_tests/sources/kernel/test_kernel.cpp index 6038b90038..0d924538a5 100644 --- a/level_zero/core/test/unit_tests/sources/kernel/test_kernel.cpp +++ b/level_zero/core/test/unit_tests/sources/kernel/test_kernel.cpp @@ -175,5 +175,64 @@ HWTEST2_F(SetKernelArg, givenBufferArgumentWhichHasNotBeenAllocatedByRuntimeThen EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, res); } +using KernelPropertiesTest = Test; + +HWTEST_F(KernelPropertiesTest, givenKernelThenPropertiesAreRetrieved) { + ze_kernel_handle_t kernelHandle; + + ze_kernel_desc_t kernelDesc = {}; + kernelDesc.version = ZE_KERNEL_DESC_VERSION_CURRENT; + kernelDesc.flags = ZE_KERNEL_FLAG_NONE; + kernelDesc.pKernelName = kernelName.c_str(); + + ze_result_t res = module->createKernel(&kernelDesc, &kernelHandle); + EXPECT_EQ(ZE_RESULT_SUCCESS, res); + + auto kernel = L0::Kernel::fromHandle(kernelHandle); + + ze_kernel_propertiesExt_t kernelProperties = {}; + + kernelProperties.requiredNumSubGroups = std::numeric_limits::max(); + kernelProperties.requiredSubgroupSize = std::numeric_limits::max(); + kernelProperties.maxSubgroupSize = std::numeric_limits::max(); + kernelProperties.maxNumSubgroups = std::numeric_limits::max(); + kernelProperties.localMemSize = std::numeric_limits::max(); + kernelProperties.privateMemSize = std::numeric_limits::max(); + kernelProperties.spillMemSize = std::numeric_limits::max(); + kernelProperties.numKernelArgs = std::numeric_limits::max(); + memset(&kernelProperties.uuid.kid, std::numeric_limits::max(), + sizeof(kernelProperties.uuid.kid)); + memset(&kernelProperties.uuid.mid, std::numeric_limits::max(), + sizeof(kernelProperties.uuid.mid)); + + ze_kernel_propertiesExt_t kernelPropertiesBefore = {}; + kernelPropertiesBefore = kernelProperties; + + kernel->getPropertiesExt(&kernelProperties); + + EXPECT_EQ(0, strncmp(kernelName.c_str(), kernelProperties.name, + sizeof(kernelProperties.name))); + EXPECT_EQ(numKernelArguments, kernelProperties.numKernelArgs); + + EXPECT_EQ(0u, kernelProperties.requiredNumSubGroups); + EXPECT_EQ(0u, kernelProperties.requiredSubgroupSize); + EXPECT_EQ(0u, kernelProperties.maxSubgroupSize); + EXPECT_EQ(0u, kernelProperties.maxNumSubgroups); + EXPECT_EQ(0u, kernelProperties.localMemSize); + EXPECT_EQ(0u, kernelProperties.privateMemSize); + EXPECT_EQ(0u, kernelProperties.spillMemSize); + + uint8_t zeroKid[ZE_MAX_KERNEL_UUID_SIZE]; + uint8_t zeroMid[ZE_MAX_MODULE_UUID_SIZE]; + memset(&zeroKid, 0, ZE_MAX_KERNEL_UUID_SIZE); + memset(&zeroMid, 0, ZE_MAX_MODULE_UUID_SIZE); + EXPECT_EQ(0, memcmp(&kernelProperties.uuid.kid, &zeroKid, + sizeof(kernelProperties.uuid.kid))); + EXPECT_EQ(0, memcmp(&kernelProperties.uuid.mid, &zeroMid, + sizeof(kernelProperties.uuid.mid))); + + Kernel::fromHandle(kernelHandle)->destroy(); +} + } // namespace ult } // namespace L0 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 c4d2a19240..acc0993faf 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 @@ -114,5 +114,19 @@ HWTEST_F(ModuleSpecConstantsTests, givenSpecializationConstantsSetInDescriptorTh module->destroy(); } +using ModuleDynamicLinkTests = Test; + +HWTEST_F(ModuleDynamicLinkTests, givenCallToDynamicLinkThenUnsupportedFeatureIsReturned) { + auto module0 = new Module(device, nullptr); + auto module1 = new Module(device, nullptr); + + std::vector hModules = {module0->toHandle(), module1->toHandle()}; + ze_result_t res = module0->performDynamicLink(2, hModules.data(), nullptr); + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, res); + + delete module0; + delete module1; +} + } // namespace ult } // namespace L0 diff --git a/third_party/level_zero/ze_api_ext.h b/third_party/level_zero/ze_api_ext.h new file mode 100644 index 0000000000..fb33ef76ec --- /dev/null +++ b/third_party/level_zero/ze_api_ext.h @@ -0,0 +1,180 @@ +/* + * + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + * + */ +#ifndef _ZE_API_EXT_H +#define _ZE_API_EXT_H +#if defined(__cplusplus) +#pragma once +#endif + +// standard headers +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +// Intel 'oneAPI' Level-Zero API common types +/////////////////////////////////////////////////////////////////////////////// +#ifndef ZE_APICALL +#if defined(_WIN32) +/// @brief Calling convention for all API functions +#define ZE_APICALL __cdecl +#else +#define ZE_APICALL +#endif // defined(_WIN32) +#endif // ZE_APICALL + +/////////////////////////////////////////////////////////////////////////////// +#ifndef ZE_APIEXPORT +#if defined(_WIN32) +/// @brief Microsoft-specific dllexport storage-class attribute +#define ZE_APIEXPORT __declspec(dllexport) +#else +#define ZE_APIEXPORT +#endif // defined(_WIN32) +#endif // ZE_APIEXPORT + +/////////////////////////////////////////////////////////////////////////////// +#ifndef ZE_DLLEXPORT +#if defined(_WIN32) +/// @brief Microsoft-specific dllexport storage-class attribute +#define ZE_DLLEXPORT __declspec(dllexport) +#endif // defined(_WIN32) +#endif // ZE_DLLEXPORT + +/////////////////////////////////////////////////////////////////////////////// +#ifndef ZE_DLLEXPORT +#if __GNUC__ >= 4 +/// @brief GCC-specific dllexport storage-class attribute +#define ZE_DLLEXPORT __attribute__((visibility("default"))) +#else +#define ZE_DLLEXPORT +#endif // __GNUC__ >= 4 +#endif // ZE_DLLEXPORT + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Forward-declare ze_kernel_uuid_t +typedef struct _ze_kernel_uuid_t ze_kernel_uuid_t; + +/////////////////////////////////////////////////////////////////////////////// +#ifndef ZE_MAX_KERNEL_UUID_SIZE +/// @brief Maximum kernel universal unique id (UUID) size in bytes +#define ZE_MAX_KERNEL_UUID_SIZE 16 +#endif // ZE_MAX_KERNEL_UUID_SIZE + +/////////////////////////////////////////////////////////////////////////////// +#ifndef ZE_MAX_MODULE_UUID_SIZE +/// @brief Maximum module universal unique id (UUID) size in bytes +#define ZE_MAX_MODULE_UUID_SIZE 16 +#endif // ZE_MAX_MODULE_UUID_SIZE + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Kernel universal unique id (UUID) +typedef struct _ze_kernel_uuid_t { + uint8_t kid[ZE_MAX_KERNEL_UUID_SIZE]; ///< [out] opaque data representing a kernel UUID + uint8_t mid[ZE_MAX_MODULE_UUID_SIZE]; ///< [out] opaque data representing the kernel's module UUID + +} ze_kernel_uuid_t; + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Kernel properties +typedef struct _ze_kernel_propertiesExt_t { + uint32_t numKernelArgs; ///< [out] number of kernel arguments. + uint32_t requiredGroupSizeX; ///< [out] required group size in the X dimension, + ///< or zero if there is no required group size + uint32_t requiredGroupSizeY; ///< [out] required group size in the Y dimension, + ///< or zero if there is no required group size + uint32_t requiredGroupSizeZ; ///< [out] required group size in the Z dimension, + ///< or zero if there is no required group size + uint32_t requiredNumSubGroups; ///< [out] required number of subgroups per thread group, + ///< or zero if there is no required number of subgroups + uint32_t requiredSubgroupSize; ///< [out] required subgroup size, + ///< or zero if there is no required subgroup size + uint32_t maxSubgroupSize; ///< [out] maximum subgroup size + uint32_t maxNumSubgroups; ///< [out] maximum number of subgroups per thread group + uint32_t localMemSize; ///< [out] local memory size used by each thread group + uint32_t privateMemSize; ///< [out] private memory size allocated by compiler used by each thread + uint32_t spillMemSize; ///< [out] spill memory size allocated by compiler + ze_kernel_uuid_t uuid; ///< [out] universal unique identifier. + char name[ZE_MAX_KERNEL_NAME]; ///< [out] kernel name + +} ze_kernel_propertiesExt_t; + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Retrieve kernel properties. +/// +/// @details +/// - The application may call this function from simultaneous threads. +/// - The implementation of this function should be lock-free. +/// +/// @returns +/// - ::ZE_RESULT_SUCCESS +/// - ::ZE_RESULT_ERROR_UNINITIALIZED +/// - ::ZE_RESULT_ERROR_DEVICE_LOST +/// - ::ZE_RESULT_ERROR_INVALID_NULL_HANDLE +/// + `nullptr == hKernel` +/// - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER +/// + `nullptr == pKernelProperties` +ZE_APIEXPORT ze_result_t ZE_APICALL +zeKernelGetPropertiesExt( + ze_kernel_handle_t hKernel, ///< [in] handle of the kernel object + ze_kernel_propertiesExt_t *pKernelProperties ///< [in,out] query result for kernel properties. +); + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Dynamically link modules together that share import/export linkage +/// dependencies. +/// +/// @details +/// - Modules support import and export linkage for functions and global +/// variables. +/// - Modules that have imports can be dynamically linked to export modules +/// that satisfy those import requirements. +/// - Modules can have both import and export linkages. +/// - Modules that do not have any imports or exports do not need to be +/// linked. +/// - Modules cannot be partially linked. All modules needed to satisfy all +/// import dependencies for a module must be passed in or +/// ::ZE_RESULT_ERROR_MODULE_LINK_FAILURE will returned. +/// - Modules with imports need to be linked before kernel objects can be +/// created from them. +/// - Modules will only be linked once. A module can be used in multiple +/// link calls if it has exports but it's imports will not be re-linked. +/// - Ambiguous dependencies, where multiple modules satisfy the import +/// dependencies for another module, is not allowed. +/// - ModuleGetNativeBinary can be called on any module regardless of +/// whether it is linked or not. +/// - A link log can optionally be returned to the caller. The caller is +/// responsible for destroying build log using ::zeModuleBuildLogDestroy. +/// - See SPIR-V specification for linkage details. +/// - The application may call this function from simultaneous threads as +/// long as the import modules being linked are not the same. +/// - The implementation of this function should be lock-free. +/// +/// @returns +/// - ::ZE_RESULT_SUCCESS +/// - ::ZE_RESULT_ERROR_UNINITIALIZED +/// - ::ZE_RESULT_ERROR_DEVICE_LOST +/// - ::ZE_RESULT_ERROR_INVALID_NULL_POINTER +/// + `nullptr == phModules` +/// - ::ZE_RESULT_ERROR_MODULE_LINK_FAILURE +ZE_APIEXPORT ze_result_t ZE_APICALL +zeModuleDynamicLinkExt( + uint32_t numModules, ///< [in] number of modules to be linked pointed to by phModules. + ze_module_handle_t *phModules, ///< [in][range(0, numModules)] pointer to an array of modules to + ///< dynamically link together. + ze_module_build_log_handle_t *phLinkLog ///< [out][optional] pointer to handle of dynamic link log. +); + +} //extern C + +#endif // _ZE_API_EXT_H