feature: add L0 API to translate between device handle and 32-bit identifier

- zerDeviceTranslateToIdentifier to translate from device handle to
32-bit unsigned integer identifier
- zerIdentifierTranslateToDeviceHandle to translate from identifier to
device handle associated to default driver handle

Related-To: NEO-14560
Signed-off-by: Mateusz Jablonski <mateusz.jablonski@intel.com>
This commit is contained in:
Mateusz Jablonski
2025-04-30 14:15:19 +00:00
committed by Compute-Runtime-Automation
parent 2577c9c628
commit 07f13fc319
10 changed files with 165 additions and 3 deletions

View File

@@ -9,6 +9,7 @@ target_sources(${L0_STATIC_LIB_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
${CMAKE_CURRENT_SOURCE_DIR}/zex_cmdlist.cpp
${CMAKE_CURRENT_SOURCE_DIR}/zex_context.cpp
${CMAKE_CURRENT_SOURCE_DIR}/zex_device.cpp
${CMAKE_CURRENT_SOURCE_DIR}/zex_driver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/zex_event.cpp
${CMAKE_CURRENT_SOURCE_DIR}/zex_memory.cpp

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "level_zero/core/source/device/device.h"
#include "level_zero/core/source/driver/driver.h"
#include "level_zero/core/source/driver/driver_handle_imp.h"
#include "level_zero/ze_intel_gpu.h"
uint32_t ZE_APICALL zerDeviceTranslateToIdentifier(ze_device_handle_t device) {
if (!device) {
auto driverHandle = static_cast<L0::DriverHandleImp *>(L0::globalDriverHandles->front());
driverHandle->setErrorDescription("Invalid device handle");
return std::numeric_limits<uint32_t>::max();
}
return L0::Device::fromHandle(device)->getIdentifier();
}
ze_device_handle_t ZE_APICALL zerIdentifierTranslateToDeviceHandle(uint32_t identifier) {
auto driverHandle = static_cast<L0::DriverHandleImp *>(L0::globalDriverHandles->front());
if (identifier >= driverHandle->devicesToExpose.size()) {
driverHandle->setErrorDescription("Invalid device identifier");
return nullptr;
}
return driverHandle->devicesToExpose[identifier];
}

View File

@@ -155,6 +155,8 @@ struct Device : _ze_device_handle_t {
NEO::GraphicsAllocation *getSyncDispatchTokenAllocation() const { return syncDispatchTokenAllocation; }
uint32_t getNextSyncDispatchQueueId();
void ensureSyncDispatchTokenAllocation();
void setIdentifier(uint32_t id) { identifier = id; }
uint32_t getIdentifier() const { return identifier; }
protected:
NEO::Device *neoDevice = nullptr;
@@ -165,6 +167,7 @@ struct Device : _ze_device_handle_t {
std::mutex inOrderAllocatorMutex;
std::mutex syncDispatchTokenMutex;
std::atomic<uint32_t> syncDispatchQueueIdAllocator = 0;
uint32_t identifier = 0;
bool implicitScalingCapable = false;
};

View File

@@ -328,7 +328,15 @@ ze_result_t DriverHandleImp::initialize(std::vector<std::unique_ptr<NEO::Device>
}
}
createContext(&DefaultDescriptors::contextDesc, 0u, nullptr, &defaultContext);
uint32_t numDevicesToExpose = 0u;
this->getDevice(&numDevicesToExpose, nullptr);
this->devicesToExpose.resize(numDevicesToExpose);
this->getDevice(&numDevicesToExpose, this->devicesToExpose.data());
uint32_t deviceIdentifier = 0u;
for (auto &deviceToExpose : this->devicesToExpose) {
Device::fromHandle(deviceToExpose)->setIdentifier(deviceIdentifier++);
}
createContext(&DefaultDescriptors::contextDesc, numDevicesToExpose, this->devicesToExpose.data(), &defaultContext);
return ZE_RESULT_SUCCESS;
}

View File

@@ -132,6 +132,7 @@ struct DriverHandleImp : public DriverHandle {
std::map<void *, NEO::GraphicsAllocation *> sharedMakeResidentAllocations;
std::vector<Device *> devices;
std::vector<ze_device_handle_t> devicesToExpose;
std::vector<FabricVertex *> fabricVertices;
std::vector<FabricEdge *> fabricEdges;
std::vector<FabricEdge *> fabricIndirectEdges;

View File

@@ -32,6 +32,9 @@ void *ExtensionFunctionAddressHelper::getExtensionFunctionAddress(const std::str
RETURN_FUNC_PTR_IF_EXIST(zeDriverGetDefaultContext);
RETURN_FUNC_PTR_IF_EXIST(zerDriverGetDefaultContext);
RETURN_FUNC_PTR_IF_EXIST(zerDeviceTranslateToIdentifier);
RETURN_FUNC_PTR_IF_EXIST(zerIdentifierTranslateToDeviceHandle);
RETURN_FUNC_PTR_IF_EXIST(zexKernelGetBaseAddress);
RETURN_FUNC_PTR_IF_EXIST(zexKernelGetArgumentSize);
RETURN_FUNC_PTR_IF_EXIST(zexKernelGetArgumentType);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2023 Intel Corporation
* Copyright (C) 2020-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -38,7 +38,10 @@ ze_result_t Mock<DriverHandle>::getDevice(uint32_t *pCount, ze_device_handle_t *
if (phDevices == nullptr) // User is expected to allocate space
return ZE_RESULT_ERROR_INVALID_ARGUMENT;
phDevices[0] = this->devices.front();
auto numDevices = std::min(pCount ? *pCount : 1u, static_cast<uint32_t>(this->devices.size()));
for (auto i = 0u; i < numDevices; i++) {
phDevices[i] = this->devices[i];
}
return ZE_RESULT_SUCCESS;
}

View File

@@ -42,6 +42,7 @@
#include "level_zero/core/source/cache/cache_reservation.h"
#include "level_zero/core/source/cmdqueue/cmdqueue_imp.h"
#include "level_zero/core/source/context/context_imp.h"
#include "level_zero/core/source/driver/driver.h"
#include "level_zero/core/source/driver/driver_handle_imp.h"
#include "level_zero/core/source/driver/extension_function_address.h"
#include "level_zero/core/source/driver/host_pointer_manager.h"
@@ -6145,6 +6146,62 @@ TEST(DeviceReturnCompositeHierarchyTest, GivenCompositeHierarchyIsSetThenGetRoot
multiDeviceFixture.tearDown();
}
template <NEO::DeviceHierarchyMode hierarchyMode>
struct MultiDeviceTest : public Test<MultiDeviceFixture> {
void SetUp() override {
this->deviceHierarchyMode = hierarchyMode;
NEO::debugManager.flags.ZE_AFFINITY_MASK.set("0,2,3");
Test<MultiDeviceFixture>::SetUp();
L0::globalDriverHandles->push_back(driverHandle->toHandle());
L0::globalDriverHandles->push_back(nullptr);
}
void TearDown() override {
L0::globalDriverHandles->clear();
Test<MultiDeviceFixture>::TearDown();
}
void whenGettingDeviceIdentifiersThenMonoticallyIncreasingIdentifiersAreReturned() {
uint32_t count = 0;
std::vector<ze_device_handle_t> hDevices;
EXPECT_EQ(driverHandle->getDevice(&count, nullptr), ZE_RESULT_SUCCESS);
EXPECT_EQ(3u, count);
hDevices.resize(count);
EXPECT_EQ(driverHandle->getDevice(&count, hDevices.data()), ZE_RESULT_SUCCESS);
uint32_t expectedIdentifier = 0u;
for (auto &hDevice : hDevices) {
EXPECT_EQ(expectedIdentifier, Device::fromHandle(hDevice)->getIdentifier());
EXPECT_EQ(expectedIdentifier, zerDeviceTranslateToIdentifier(hDevice));
EXPECT_EQ(hDevice, zerIdentifierTranslateToDeviceHandle(expectedIdentifier));
expectedIdentifier++;
}
EXPECT_EQ(nullptr, zerIdentifierTranslateToDeviceHandle(expectedIdentifier));
}
DebugManagerStateRestore restorer;
};
using MultiDeviceCompositeTest = MultiDeviceTest<NEO::DeviceHierarchyMode::composite>;
TEST_F(MultiDeviceCompositeTest, whenGettingDeviceIdentifiersThenMonoticallyIncreasingIdentifiersAreReturned) {
whenGettingDeviceIdentifiersThenMonoticallyIncreasingIdentifiersAreReturned();
}
using MultiDeviceCombinedTest = MultiDeviceTest<NEO::DeviceHierarchyMode::combined>;
TEST_F(MultiDeviceCombinedTest, whenGettingDeviceIdentifiersThenMonoticallyIncreasingIdentifiersAreReturned) {
whenGettingDeviceIdentifiersThenMonoticallyIncreasingIdentifiersAreReturned();
}
using MultiDeviceFlatTest = MultiDeviceTest<NEO::DeviceHierarchyMode::flat>;
TEST_F(MultiDeviceFlatTest, whenGettingDeviceIdentifiersThenMonoticallyIncreasingIdentifiersAreReturned) {
whenGettingDeviceIdentifiersThenMonoticallyIncreasingIdentifiersAreReturned();
}
TEST(SingleDeviceModeTest, GivenFlatHierarchyIsSetWhenGettingDevicesThenOnlySingleRootDeviceIsExposed) {
DebugManagerStateRestore restorer;

View File

@@ -922,6 +922,32 @@ TEST_F(DriverHandleTest,
EXPECT_EQ(defaultContext, driverHandle->getDefaultContext());
}
TEST_F(DriverHandleTest,
whenTranslatingNullptrDeviceHandleToIdentifierThenErrorIsPropagated) {
auto identifier = zerDeviceTranslateToIdentifier(nullptr);
EXPECT_EQ(std::numeric_limits<uint32_t>::max(), identifier);
const char *expectedError = "Invalid device handle";
const char *errorDescription = nullptr;
EXPECT_EQ(ZE_RESULT_SUCCESS, zeDriverGetLastErrorDescription(driverHandle->toHandle(), &errorDescription));
EXPECT_EQ(0, strcmp(expectedError, errorDescription)) << errorDescription;
}
TEST_F(DriverHandleTest,
whenTranslatingIncorrectIdentifierToDeviceHandleThenErrorIsPropagated) {
uint32_t invalidIdentifier = std::numeric_limits<uint32_t>::max();
EXPECT_EQ(nullptr, zerIdentifierTranslateToDeviceHandle(invalidIdentifier));
const char *expectedError = "Invalid device identifier";
const char *errorDescription = nullptr;
EXPECT_EQ(ZE_RESULT_SUCCESS, zeDriverGetLastErrorDescription(driverHandle->toHandle(), &errorDescription));
EXPECT_EQ(0, strcmp(expectedError, errorDescription)) << errorDescription;
}
TEST_F(DriverHandleTest,
givenInitializedDriverWhenZeDriverGetIsCalledWithGreaterThanZeroCountAndNullDriverHandleThenInvalidNullPointerIsReturned) {
uint32_t count = 0;
@@ -1181,6 +1207,10 @@ TEST_F(DriverExperimentalApiTest, whenRetrievingApiFunctionThenExpectProperPoint
decltype(&zexDriverGetHostPointerBaseAddress) expectedGet = L0::zexDriverGetHostPointerBaseAddress;
decltype(&zeDriverGetDefaultContext) expectedZeDriverGetDefaultContext = zeDriverGetDefaultContext;
decltype(&zerDriverGetDefaultContext) expectedZerDriverGetDefaultContext = zerDriverGetDefaultContext;
decltype(&zerDeviceTranslateToIdentifier) expectedZerDeviceTranslateToIdentifier = zerDeviceTranslateToIdentifier;
decltype(&zerIdentifierTranslateToDeviceHandle) expectedZerIdentifierTranslateToDeviceHandle = zerIdentifierTranslateToDeviceHandle;
decltype(&zexKernelGetBaseAddress) expectedKernelGetBaseAddress = L0::zexKernelGetBaseAddress;
decltype(&zeIntelGetDriverVersionString) expectedIntelGetDriverVersionString = zeIntelGetDriverVersionString;
decltype(&zeIntelMediaCommunicationCreate) expectedIntelMediaCommunicationCreate = L0::zeIntelMediaCommunicationCreate;
@@ -1210,6 +1240,12 @@ TEST_F(DriverExperimentalApiTest, whenRetrievingApiFunctionThenExpectProperPoint
EXPECT_EQ(ZE_RESULT_SUCCESS, zeDriverGetExtensionFunctionAddress(driverHandle, "zerDriverGetDefaultContext", &funPtr));
EXPECT_EQ(expectedZerDriverGetDefaultContext, reinterpret_cast<decltype(&zerDriverGetDefaultContext)>(funPtr));
EXPECT_EQ(ZE_RESULT_SUCCESS, zeDriverGetExtensionFunctionAddress(driverHandle, "zerDeviceTranslateToIdentifier", &funPtr));
EXPECT_EQ(expectedZerDeviceTranslateToIdentifier, reinterpret_cast<decltype(&zerDeviceTranslateToIdentifier)>(funPtr));
EXPECT_EQ(ZE_RESULT_SUCCESS, zeDriverGetExtensionFunctionAddress(driverHandle, "zerIdentifierTranslateToDeviceHandle", &funPtr));
EXPECT_EQ(expectedZerIdentifierTranslateToDeviceHandle, reinterpret_cast<decltype(&zerIdentifierTranslateToDeviceHandle)>(funPtr));
EXPECT_EQ(ZE_RESULT_SUCCESS, zeDriverGetExtensionFunctionAddress(driverHandle, "zexKernelGetBaseAddress", &funPtr));
EXPECT_EQ(expectedKernelGetBaseAddress, reinterpret_cast<decltype(&zexKernelGetBaseAddress)>(funPtr));

View File

@@ -295,6 +295,27 @@ ze_context_handle_t ZE_APICALL zeDriverGetDefaultContext(ze_driver_handle_t hDri
/// - Context handle associated with default driver
ze_context_handle_t ZE_APICALL zerDriverGetDefaultContext();
/// @brief Get Device Identifier
///
/// @details
/// - The application may call this function from simultaneous threads.
/// - The implementation of this function should be lock-free.
/// - Returned identifier is a 32-bit unsigned integer that is unique to the driver.
/// - The identifier can be used then in zerIdentifierTranslateToDeviceHandle to get the device handle.
/// @returns
/// - 32-bit unsigned integer identifier
uint32_t ZE_APICALL zerDeviceTranslateToIdentifier(ze_device_handle_t hDevice); ///< [in] handle of the device
/// @brief Translate Device Identifier to Device Handle from default Driver
///
/// @details
/// - The application may call this function from simultaneous threads.
/// - The implementation of this function should be lock-free.
/// - Returned device is associated to default driver handle.
/// @returns
/// - device handle associated with the identifier
ze_device_handle_t ZE_APICALL zerIdentifierTranslateToDeviceHandle(uint32_t identifier); ///< [in] integer identifier of the device
#if defined(__cplusplus)
} // extern "C"
#endif