diff --git a/level_zero/api/core/ze_core_loader.cpp b/level_zero/api/core/ze_core_loader.cpp index db9a5063c1..349df9dc0b 100644 --- a/level_zero/api/core/ze_core_loader.cpp +++ b/level_zero/api/core/ze_core_loader.cpp @@ -240,6 +240,7 @@ zeGetDeviceProcAddrTable( pDdiTable->pfnReserveCacheExt = L0::zeDeviceReserveCacheExt; pDdiTable->pfnSetCacheAdviceExt = L0::zeDeviceSetCacheAdviceExt; pDdiTable->pfnPciGetPropertiesExt = L0::zeDevicePciGetPropertiesExt; + pDdiTable->pfnGetRootDevice = L0::zeDeviceGetRootDevice; driverDdiTable.coreDdiTable.Device = *pDdiTable; if (driverDdiTable.enableTracing) { pDdiTable->pfnGet = zeDeviceGetTracing; diff --git a/level_zero/api/core/ze_device_api_entrypoints.h b/level_zero/api/core/ze_device_api_entrypoints.h index 3886da00f9..a7261f2a9e 100644 --- a/level_zero/api/core/ze_device_api_entrypoints.h +++ b/level_zero/api/core/ze_device_api_entrypoints.h @@ -132,6 +132,12 @@ ze_result_t zeDevicePciGetPropertiesExt( return L0::Device::fromHandle(hDevice)->getPciProperties(pPciProperties); } +ze_result_t zeDeviceGetRootDevice( + ze_device_handle_t hDevice, + ze_device_handle_t *phRootDevice) { + return L0::Device::fromHandle(hDevice)->getRootDevice(phRootDevice); +} + } // namespace L0 extern "C" { diff --git a/level_zero/core/source/device/device.h b/level_zero/core/source/device/device.h index e5b885f3d1..b87d8f24de 100644 --- a/level_zero/core/source/device/device.h +++ b/level_zero/core/source/device/device.h @@ -68,6 +68,7 @@ struct Device : _ze_device_handle_t { ze_device_p2p_properties_t *pP2PProperties) = 0; virtual ze_result_t getKernelProperties(ze_device_module_properties_t *pKernelProperties) = 0; virtual ze_result_t getPciProperties(ze_pci_ext_properties_t *pPciProperties) = 0; + virtual ze_result_t getRootDevice(ze_device_handle_t *phRootDevice) = 0; virtual ze_result_t getMemoryProperties(uint32_t *pCount, ze_device_memory_properties_t *pMemProperties) = 0; virtual ze_result_t getMemoryAccessProperties(ze_device_memory_access_properties_t *pMemAccessProperties) = 0; virtual ze_result_t getProperties(ze_device_properties_t *pDeviceProperties) = 0; diff --git a/level_zero/core/source/device/device_imp.cpp b/level_zero/core/source/device/device_imp.cpp index 90953fea20..4c22c45705 100644 --- a/level_zero/core/source/device/device_imp.cpp +++ b/level_zero/core/source/device/device_imp.cpp @@ -535,6 +535,17 @@ ze_result_t DeviceImp::getP2PProperties(ze_device_handle_t hPeerDevice, return ZE_RESULT_SUCCESS; } +ze_result_t DeviceImp::getRootDevice(ze_device_handle_t *phRootDevice) { + DriverHandleImp *driverHandleImp = static_cast(driverHandle); + // Given FLAT device Hierarchy mode, then nullptr is returned for the root device since no traversal is allowed. + if (driverHandleImp->deviceHierarchyMode == L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT) { + *phRootDevice = nullptr; + return ZE_RESULT_SUCCESS; + } + *phRootDevice = this->rootDevice; + return ZE_RESULT_SUCCESS; +} + ze_result_t DeviceImp::getPciProperties(ze_pci_ext_properties_t *pPciProperties) { if (!driverInfo) { return ZE_RESULT_ERROR_UNINITIALIZED; @@ -826,8 +837,9 @@ ze_result_t DeviceImp::getProperties(ze_device_properties_t *pDeviceProperties) } if (isSubdevice) { + DriverHandleImp *driverHandleImp = static_cast(driverHandle); const auto &isReturnSubDevicesAsApiDevices = NEO::DebugManager.flags.ReturnSubDevicesAsApiDevices.get(); - if (isReturnSubDevicesAsApiDevices != 1) { + if (isReturnSubDevicesAsApiDevices != 1 && driverHandleImp->deviceHierarchyMode != L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT) { pDeviceProperties->flags |= ZE_DEVICE_PROPERTY_FLAG_SUBDEVICE; } } @@ -910,6 +922,12 @@ ze_result_t DeviceImp::getGlobalTimestamps(uint64_t *hostTimestamp, uint64_t *de } ze_result_t DeviceImp::getSubDevices(uint32_t *pCount, ze_device_handle_t *phSubdevices) { + DriverHandleImp *driverHandleImp = static_cast(driverHandle); + // Given FLAT device Hierarchy mode, then a count of 0 is returned since no traversal is allowed. + if (driverHandleImp->deviceHierarchyMode == L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT) { + *pCount = 0; + return ZE_RESULT_SUCCESS; + } if (*pCount == 0) { *pCount = this->numSubDevices; return ZE_RESULT_SUCCESS; @@ -1209,6 +1227,7 @@ Device *Device::create(DriverHandle *driverHandle, NEO::Device *neoDevice, bool return nullptr; } static_cast(subDevice)->setDebugSurface(debugSurface); + static_cast(subDevice)->rootDevice = device; device->subDevices.push_back(static_cast(subDevice)); } device->numSubDevices = static_cast(device->subDevices.size()); diff --git a/level_zero/core/source/device/device_imp.h b/level_zero/core/source/device/device_imp.h index 46093ee2e4..2e000a59b2 100644 --- a/level_zero/core/source/device/device_imp.h +++ b/level_zero/core/source/device/device_imp.h @@ -51,6 +51,7 @@ struct DeviceImp : public Device { ze_device_p2p_properties_t *pP2PProperties) override; ze_result_t getKernelProperties(ze_device_module_properties_t *pKernelProperties) override; ze_result_t getPciProperties(ze_pci_ext_properties_t *pPciProperties) override; + ze_result_t getRootDevice(ze_device_handle_t *phRootDevice) override; ze_result_t getMemoryProperties(uint32_t *pCount, ze_device_memory_properties_t *pMemProperties) override; ze_result_t getMemoryAccessProperties(ze_device_memory_access_properties_t *pMemAccessProperties) override; ze_result_t getProperties(ze_device_properties_t *pDeviceProperties) override; @@ -128,6 +129,7 @@ struct DeviceImp : public Device { FabricVertex *fabricVertex = nullptr; CommandList *pageFaultCommandList = nullptr; ze_pci_speed_ext_t pciMaxSpeed = {-1, -1, -1}; + Device *rootDevice = nullptr; BcsSplit bcsSplit; diff --git a/level_zero/core/source/driver/driver.cpp b/level_zero/core/source/driver/driver.cpp index e89d9a1cee..bd310641da 100644 --- a/level_zero/core/source/driver/driver.cpp +++ b/level_zero/core/source/driver/driver.cpp @@ -46,6 +46,8 @@ void DriverImp::initialize(ze_result_t *result) { envReader.getSetting("ZE_ENABLE_PCI_ID_DEVICE_ORDER", false); envVariables.fp64Emulation = envReader.getSetting("NEO_FP64_EMULATION", false); + envVariables.deviceHierarchyMode = + envReader.getSetting("ZE_FLAT_DEVICE_HIERARCHY", std::string("COMPOSITE")); auto executionEnvironment = new NEO::ExecutionEnvironment(); UNRECOVERABLE_IF(nullptr == executionEnvironment); diff --git a/level_zero/core/source/driver/driver_handle_imp.cpp b/level_zero/core/source/driver/driver_handle_imp.cpp index ffa5151bbf..f4d3d940d2 100644 --- a/level_zero/core/source/driver/driver_handle_imp.cpp +++ b/level_zero/core/source/driver/driver_handle_imp.cpp @@ -267,6 +267,13 @@ DriverHandle *DriverHandle::create(std::vector> dev driverHandle->enableProgramDebugging = static_cast(envVariables.programDebugging); driverHandle->enableSysman = envVariables.sysman; driverHandle->enablePciIdDeviceOrder = envVariables.pciIdDeviceOrder; + if (strcmp(envVariables.deviceHierarchyMode.c_str(), "COMPOSITE") == 0) { + driverHandle->deviceHierarchyMode = L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_COMPOSITE; + } else if (strcmp(envVariables.deviceHierarchyMode.c_str(), "FLAT") == 0) { + driverHandle->deviceHierarchyMode = L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT; + } else if (strcmp(envVariables.deviceHierarchyMode.c_str(), "COMBINED") == 0) { + driverHandle->deviceHierarchyMode = L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_COMBINED; + } ze_result_t res = driverHandle->initialize(std::move(devices)); if (res != ZE_RESULT_SUCCESS) { delete driverHandle; @@ -288,6 +295,11 @@ ze_result_t DriverHandleImp::getDevice(uint32_t *pCount, ze_device_handle_t *phD exposeSubDevices = NEO::DebugManager.flags.ReturnSubDevicesAsApiDevices.get(); } + // If the user has requested FLAT device hierarchy model, then report all the sub devices as devices. + if (this->deviceHierarchyMode == L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT) { + exposeSubDevices = true; + } + if (*pCount == 0) { if (exposeSubDevices) { for (auto &device : this->devices) { diff --git a/level_zero/core/source/driver/driver_handle_imp.h b/level_zero/core/source/driver/driver_handle_imp.h index 759115539d..bd7ca081e1 100644 --- a/level_zero/core/source/driver/driver_handle_imp.h +++ b/level_zero/core/source/driver/driver_handle_imp.h @@ -23,6 +23,12 @@ struct FabricVertex; struct FabricEdge; struct Image; +enum L0DeviceHierarchyMode { + L0_DEVICE_HIERARCHY_COMPOSITE, + L0_DEVICE_HIERARCHY_FLAT, + L0_DEVICE_HIERARCHY_COMBINED +}; + struct DriverHandleImp : public DriverHandle { ~DriverHandleImp() override; DriverHandleImp(); @@ -139,6 +145,7 @@ struct DriverHandleImp : public DriverHandle { bool enableSysman = false; bool enablePciIdDeviceOrder = false; uint8_t powerHint = 0; + L0DeviceHierarchyMode deviceHierarchyMode = L0_DEVICE_HIERARCHY_COMPOSITE; // Error messages per thread, variable initialized / destoryed per thread, // not based on the lifetime of the object of a class. diff --git a/level_zero/core/source/driver/driver_imp.h b/level_zero/core/source/driver/driver_imp.h index 5e9c14ba26..a723948af6 100644 --- a/level_zero/core/source/driver/driver_imp.h +++ b/level_zero/core/source/driver/driver_imp.h @@ -33,6 +33,7 @@ struct L0EnvVariables { bool sysman; bool pciIdDeviceOrder; bool fp64Emulation; + std::string deviceHierarchyMode; }; } // namespace L0 diff --git a/level_zero/core/test/unit_tests/fixtures/device_fixture.cpp b/level_zero/core/test/unit_tests/fixtures/device_fixture.cpp index c470fd3d2e..d9ba10fe99 100644 --- a/level_zero/core/test/unit_tests/fixtures/device_fixture.cpp +++ b/level_zero/core/test/unit_tests/fixtures/device_fixture.cpp @@ -117,6 +117,23 @@ void MultiDeviceFixture::tearDown() { context->destroy(); } +void MultiDeviceFixtureHierarchy::setUp() { + DebugManager.flags.CreateMultipleRootDevices.set(numRootDevices); + DebugManager.flags.CreateMultipleSubDevices.set(numSubDevices); + auto executionEnvironment = new NEO::ExecutionEnvironment; + executionEnvironment->setExposeSubDevicesAsDevices(exposeSubDevices); + auto devices = NEO::DeviceFactory::createDevices(*executionEnvironment); + driverHandle = std::make_unique>(); + ze_result_t res = driverHandle->initialize(std::move(devices)); + EXPECT_EQ(ZE_RESULT_SUCCESS, res); + + ze_context_handle_t hContext; + ze_context_desc_t desc = {ZE_STRUCTURE_TYPE_CONTEXT_DESC, nullptr, 0}; + res = driverHandle->createContext(&desc, 0u, nullptr, &hContext); + EXPECT_EQ(ZE_RESULT_SUCCESS, res); + context = static_cast(Context::fromHandle(hContext)); +} + void MultipleDevicesWithCustomHwInfo::setUp() { VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); diff --git a/level_zero/core/test/unit_tests/fixtures/device_fixture.h b/level_zero/core/test/unit_tests/fixtures/device_fixture.h index 7cdde99db9..825ebb3bab 100644 --- a/level_zero/core/test/unit_tests/fixtures/device_fixture.h +++ b/level_zero/core/test/unit_tests/fixtures/device_fixture.h @@ -112,6 +112,11 @@ struct MultiDeviceFixture { L0::ContextImp *context = nullptr; }; +struct MultiDeviceFixtureHierarchy : public MultiDeviceFixture { + void setUp(); + bool exposeSubDevices = true; +}; + struct SingleRootMultiSubDeviceFixture : public MultiDeviceFixture { void setUp(); diff --git a/level_zero/core/test/unit_tests/mocks/mock_device.h b/level_zero/core/test/unit_tests/mocks/mock_device.h index 58648a8f78..8e144fbc79 100644 --- a/level_zero/core/test/unit_tests/mocks/mock_device.h +++ b/level_zero/core/test/unit_tests/mocks/mock_device.h @@ -56,6 +56,7 @@ struct Mock : public Device { ADDMETHOD_NOBASE(getExternalMemoryProperties, ze_result_t, ZE_RESULT_SUCCESS, (ze_device_external_memory_properties_t * pExternalMemoryProperties)); ADDMETHOD_NOBASE(getGlobalTimestamps, ze_result_t, ZE_RESULT_SUCCESS, (uint64_t * hostTimestamp, uint64_t *deviceTimestamp)); ADDMETHOD_NOBASE(systemBarrier, ze_result_t, ZE_RESULT_SUCCESS, ()); + ADDMETHOD_NOBASE(getRootDevice, ze_result_t, ZE_RESULT_SUCCESS, (ze_device_handle_t * phRootDevice)); // Runtime internal methods ADDMETHOD_NOBASE(getExecEnvironment, void *, nullptr, ()); ADDMETHOD_NOBASE_REFRETURN(getGfxCoreHelper, NEO::GfxCoreHelper &, ()); diff --git a/level_zero/core/test/unit_tests/sources/device/test_l0_device.cpp b/level_zero/core/test/unit_tests/sources/device/test_l0_device.cpp index 35a34c891e..6c930568ab 100644 --- a/level_zero/core/test/unit_tests/sources/device/test_l0_device.cpp +++ b/level_zero/core/test/unit_tests/sources/device/test_l0_device.cpp @@ -4413,6 +4413,196 @@ TEST_F(P2pBandwidthPropertiesTest, GivenFabricVerticesAreNotAvailableForDevicesW static_cast(device1)->fabricVertex = backupFabricVertex; } +TEST(DeviceReturnFlatHierarchyTest, GivenFlatHierarchyIsSetWithMaskThenFlagsOfDevicePropertiesIsCorrect) { + + DebugManagerStateRestore restorer; + NEO::DebugManager.flags.ZE_AFFINITY_MASK.set("0,1.1,2"); + MultiDeviceFixtureHierarchy multiDeviceFixture{}; + multiDeviceFixture.setUp(); + multiDeviceFixture.driverHandle->deviceHierarchyMode = L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT; + + uint32_t count = 0; + std::vector hDevices; + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, nullptr), ZE_RESULT_SUCCESS); + + // mask is "0,1.1,2", but with L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT 1.1 + // is not valid, so expected count is 2. + EXPECT_EQ(count, 2u); + + hDevices.resize(count); + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, hDevices.data()), ZE_RESULT_SUCCESS); + + for (auto &hDevice : hDevices) { + ze_device_properties_t deviceProperties{}; + deviceProperties.stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES; + EXPECT_EQ(Device::fromHandle(hDevice)->getProperties(&deviceProperties), ZE_RESULT_SUCCESS); + EXPECT_NE(ZE_DEVICE_PROPERTY_FLAG_SUBDEVICE, deviceProperties.flags & ZE_DEVICE_PROPERTY_FLAG_SUBDEVICE); + + uint32_t subDeviceCount = 0; + EXPECT_EQ(Device::fromHandle(hDevice)->getSubDevices(&subDeviceCount, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(subDeviceCount, 0u); + } + + multiDeviceFixture.tearDown(); +} + +TEST(DeviceReturnFlatHierarchyTest, GivenFlatHierarchyIsSetThenFlagsOfDevicePropertiesIsCorrect) { + + MultiDeviceFixtureHierarchy multiDeviceFixture{}; + multiDeviceFixture.setUp(); + multiDeviceFixture.driverHandle->deviceHierarchyMode = L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT; + + uint32_t count = 0; + std::vector hDevices; + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, nullptr), ZE_RESULT_SUCCESS); + + EXPECT_EQ(count, multiDeviceFixture.numRootDevices * multiDeviceFixture.numSubDevices); + + hDevices.resize(count); + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, hDevices.data()), ZE_RESULT_SUCCESS); + + for (auto &hDevice : hDevices) { + ze_device_properties_t deviceProperties{}; + deviceProperties.stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES; + EXPECT_EQ(Device::fromHandle(hDevice)->getProperties(&deviceProperties), ZE_RESULT_SUCCESS); + EXPECT_NE(ZE_DEVICE_PROPERTY_FLAG_SUBDEVICE, deviceProperties.flags & ZE_DEVICE_PROPERTY_FLAG_SUBDEVICE); + + uint32_t subDeviceCount = 0; + EXPECT_EQ(Device::fromHandle(hDevice)->getSubDevices(&subDeviceCount, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(subDeviceCount, 0u); + } + + multiDeviceFixture.tearDown(); +} + +TEST(DeviceReturnFlatHierarchyTest, GivenFlatHierarchyIsSetWithMaskThenGetRootDeviceReturnsNullptr) { + + DebugManagerStateRestore restorer; + NEO::DebugManager.flags.ZE_AFFINITY_MASK.set("0,1.1,2"); + MultiDeviceFixtureHierarchy multiDeviceFixture{}; + multiDeviceFixture.setUp(); + multiDeviceFixture.driverHandle->deviceHierarchyMode = L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT; + + uint32_t count = 0; + std::vector hDevices; + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, nullptr), ZE_RESULT_SUCCESS); + + // mask is "0,1.1,2", but with L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT 1.1 + // is not valid, so expected count is 2. + EXPECT_EQ(count, 2u); + + hDevices.resize(count); + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, hDevices.data()), ZE_RESULT_SUCCESS); + + for (auto &hDevice : hDevices) { + ze_device_handle_t rootDevice = nullptr; + EXPECT_EQ(Device::fromHandle(hDevice)->getRootDevice(&rootDevice), ZE_RESULT_SUCCESS); + EXPECT_EQ(rootDevice, nullptr); + } + + multiDeviceFixture.tearDown(); +} + +TEST(DeviceReturnFlatHierarchyTest, GivenFlatHierarchyIsSetThenGetRootDeviceReturnsNullptr) { + + MultiDeviceFixtureHierarchy multiDeviceFixture{}; + multiDeviceFixture.setUp(); + multiDeviceFixture.driverHandle->deviceHierarchyMode = L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT; + + uint32_t count = 0; + std::vector hDevices; + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, nullptr), ZE_RESULT_SUCCESS); + + EXPECT_EQ(count, multiDeviceFixture.numRootDevices * multiDeviceFixture.numSubDevices); + + hDevices.resize(count); + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, hDevices.data()), ZE_RESULT_SUCCESS); + + for (auto &hDevice : hDevices) { + ze_device_handle_t rootDevice = nullptr; + EXPECT_EQ(Device::fromHandle(hDevice)->getRootDevice(&rootDevice), ZE_RESULT_SUCCESS); + EXPECT_EQ(rootDevice, nullptr); + } + + multiDeviceFixture.tearDown(); +} + +TEST(DeviceReturnCompositeHierarchyTest, GivenCompositeHierarchyIsSetWithMaskThenGetRootDeviceIsNotNullForSubDevices) { + + DebugManagerStateRestore restorer; + NEO::DebugManager.flags.ZE_AFFINITY_MASK.set("0,1,2"); + MultiDeviceFixture multiDeviceFixture{}; + multiDeviceFixture.setUp(); + multiDeviceFixture.driverHandle->deviceHierarchyMode = L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_COMPOSITE; + + uint32_t count = 0; + std::vector hDevices; + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, nullptr), ZE_RESULT_SUCCESS); + + EXPECT_EQ(count, 3u); + + hDevices.resize(count); + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, hDevices.data()), ZE_RESULT_SUCCESS); + + for (auto &hDevice : hDevices) { + + uint32_t subDeviceCount = 0; + EXPECT_EQ(Device::fromHandle(hDevice)->getSubDevices(&subDeviceCount, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(subDeviceCount, multiDeviceFixture.numSubDevices); + std::vector hSubDevices(multiDeviceFixture.numSubDevices); + EXPECT_EQ(Device::fromHandle(hDevice)->getSubDevices(&subDeviceCount, hSubDevices.data()), ZE_RESULT_SUCCESS); + + for (auto &hSubDevice : hSubDevices) { + ze_device_handle_t rootDevice = nullptr; + EXPECT_EQ(Device::fromHandle(hSubDevice)->getRootDevice(&rootDevice), ZE_RESULT_SUCCESS); + EXPECT_NE(rootDevice, nullptr); + ze_device_properties_t deviceProperties{}; + deviceProperties.stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES; + EXPECT_EQ(Device::fromHandle(hSubDevice)->getProperties(&deviceProperties), ZE_RESULT_SUCCESS); + EXPECT_EQ(ZE_DEVICE_PROPERTY_FLAG_SUBDEVICE, deviceProperties.flags & ZE_DEVICE_PROPERTY_FLAG_SUBDEVICE); + } + } + + multiDeviceFixture.tearDown(); +} + +TEST(DeviceReturnCompositeHierarchyTest, GivenCompositeHierarchyIsSetThenGetRootDeviceIsNotNullForSubDevices) { + + MultiDeviceFixture multiDeviceFixture{}; + multiDeviceFixture.setUp(); + multiDeviceFixture.driverHandle->deviceHierarchyMode = L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_COMPOSITE; + + uint32_t count = 0; + std::vector hDevices; + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, nullptr), ZE_RESULT_SUCCESS); + + EXPECT_EQ(count, multiDeviceFixture.numRootDevices); + + hDevices.resize(count); + EXPECT_EQ(multiDeviceFixture.driverHandle->getDevice(&count, hDevices.data()), ZE_RESULT_SUCCESS); + + for (auto &hDevice : hDevices) { + + uint32_t subDeviceCount = 0; + EXPECT_EQ(Device::fromHandle(hDevice)->getSubDevices(&subDeviceCount, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(subDeviceCount, multiDeviceFixture.numSubDevices); + std::vector hSubDevices(multiDeviceFixture.numSubDevices); + EXPECT_EQ(Device::fromHandle(hDevice)->getSubDevices(&subDeviceCount, hSubDevices.data()), ZE_RESULT_SUCCESS); + + for (auto &hSubDevice : hSubDevices) { + ze_device_handle_t rootDevice = nullptr; + EXPECT_EQ(Device::fromHandle(hSubDevice)->getRootDevice(&rootDevice), ZE_RESULT_SUCCESS); + EXPECT_NE(rootDevice, nullptr); + ze_device_properties_t deviceProperties{}; + deviceProperties.stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES; + EXPECT_EQ(Device::fromHandle(hSubDevice)->getProperties(&deviceProperties), ZE_RESULT_SUCCESS); + EXPECT_EQ(ZE_DEVICE_PROPERTY_FLAG_SUBDEVICE, deviceProperties.flags & ZE_DEVICE_PROPERTY_FLAG_SUBDEVICE); + } + } + + multiDeviceFixture.tearDown(); +} + TEST(DeviceReturnSubDevicesAsApiDevicesTest, GivenReturnSubDevicesAsApiDevicesIsSetThenFlagsOfDevicePropertiesIsCorrect) { DebugManagerStateRestore restorer; diff --git a/level_zero/core/test/unit_tests/sources/driver/test_driver.cpp b/level_zero/core/test/unit_tests/sources/driver/test_driver.cpp index f9c1fe2e46..58c596edf3 100644 --- a/level_zero/core/test/unit_tests/sources/driver/test_driver.cpp +++ b/level_zero/core/test/unit_tests/sources/driver/test_driver.cpp @@ -473,6 +473,68 @@ TEST(DriverImpTest, givenEnabledProgramDebuggingWhenCreatingExecutionEnvironment L0::GlobalDriver = nullptr; } +TEST(DriverImpTest, givenDefaultFlatDeviceHierarchyWhenCreatingExecutionEnvironmentThenCompositeHierarchyIsEnabled) { + + NEO::HardwareInfo hwInfo = *NEO::defaultHwInfo.get(); + hwInfo.capabilityTable.levelZeroSupported = true; + + ze_result_t result = ZE_RESULT_ERROR_UNINITIALIZED; + DriverImp driverImp; + driverImp.initialize(&result); + L0::DriverHandleImp *driverHandleImp = reinterpret_cast(L0::GlobalDriverHandle); + EXPECT_EQ(driverHandleImp->deviceHierarchyMode, L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_COMPOSITE); + ASSERT_NE(nullptr, L0::GlobalDriver); + ASSERT_NE(0u, L0::GlobalDriver->numDevices); + + delete L0::GlobalDriver; + L0::GlobalDriverHandle = nullptr; + L0::GlobalDriver = nullptr; +} + +TEST(DriverImpTest, givenFlatDeviceHierarchyWhenCreatingExecutionEnvironmentThenFlatHierarchyIsEnabled) { + + NEO::HardwareInfo hwInfo = *NEO::defaultHwInfo.get(); + hwInfo.capabilityTable.levelZeroSupported = true; + + VariableBackup mockGetenvCalledBackup(&IoFunctions::mockGetenvCalled, 0); + std::unordered_map mockableEnvs = {{"ZE_FLAT_DEVICE_HIERARCHY", "FLAT"}}; + VariableBackup *> mockableEnvValuesBackup(&IoFunctions::mockableEnvValues, &mockableEnvs); + + ze_result_t result = ZE_RESULT_ERROR_UNINITIALIZED; + DriverImp driverImp; + driverImp.initialize(&result); + L0::DriverHandleImp *driverHandleImp = reinterpret_cast(L0::GlobalDriverHandle); + EXPECT_EQ(driverHandleImp->deviceHierarchyMode, L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_FLAT); + ASSERT_NE(nullptr, L0::GlobalDriver); + ASSERT_NE(0u, L0::GlobalDriver->numDevices); + + delete L0::GlobalDriver; + L0::GlobalDriverHandle = nullptr; + L0::GlobalDriver = nullptr; +} + +TEST(DriverImpTest, givenCombinedFlatDeviceHierarchyWhenCreatingExecutionEnvironmentThenCombinedHierarchyIsEnabled) { + + NEO::HardwareInfo hwInfo = *NEO::defaultHwInfo.get(); + hwInfo.capabilityTable.levelZeroSupported = true; + + VariableBackup mockGetenvCalledBackup(&IoFunctions::mockGetenvCalled, 0); + std::unordered_map mockableEnvs = {{"ZE_FLAT_DEVICE_HIERARCHY", "COMBINED"}}; + VariableBackup *> mockableEnvValuesBackup(&IoFunctions::mockableEnvValues, &mockableEnvs); + + ze_result_t result = ZE_RESULT_ERROR_UNINITIALIZED; + DriverImp driverImp; + driverImp.initialize(&result); + L0::DriverHandleImp *driverHandleImp = reinterpret_cast(L0::GlobalDriverHandle); + EXPECT_EQ(driverHandleImp->deviceHierarchyMode, L0::L0DeviceHierarchyMode::L0_DEVICE_HIERARCHY_COMBINED); + ASSERT_NE(nullptr, L0::GlobalDriver); + ASSERT_NE(0u, L0::GlobalDriver->numDevices); + + delete L0::GlobalDriver; + L0::GlobalDriverHandle = nullptr; + L0::GlobalDriver = nullptr; +} + TEST(DriverImpTest, givenEnableProgramDebuggingWithValue2WhenCreatingExecutionEnvironmentThenDebuggingEnabledIsTrue) { NEO::HardwareInfo hwInfo = *NEO::defaultHwInfo.get(); diff --git a/opencl/source/api/api.cpp b/opencl/source/api/api.cpp index c5c394e875..4339b7c91b 100644 --- a/opencl/source/api/api.cpp +++ b/opencl/source/api/api.cpp @@ -262,6 +262,10 @@ cl_int CL_API_CALL clGetDeviceIDs(cl_platform_id platform, exposeSubDevices = DebugManager.flags.ReturnSubDevicesAsApiDevices.get(); } + if (pPlatform->peekExecutionEnvironment()->isExposingSubDevicesAsDevices()) { + exposeSubDevices = true; + } + ClDevice *device = pPlatform->getClDevice(platformDeviceIndex); UNRECOVERABLE_IF(device == nullptr); diff --git a/opencl/test/unit_test/api/cl_get_device_ids_tests.inl b/opencl/test/unit_test/api/cl_get_device_ids_tests.inl index 08ecf7ce28..3c2c894282 100644 --- a/opencl/test/unit_test/api/cl_get_device_ids_tests.inl +++ b/opencl/test/unit_test/api/cl_get_device_ids_tests.inl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -9,6 +9,7 @@ #include "shared/test/common/helpers/debug_manager_state_restore.h" #include "shared/test/common/helpers/ult_hw_config.h" #include "shared/test/common/helpers/variable_backup.h" +#include "shared/test/common/mocks/mock_io_functions.h" #include "shared/test/common/test_macros/test.h" #include "opencl/test/unit_test/fixtures/platform_fixture.h" @@ -179,6 +180,41 @@ TEST(clGetDeviceIDsTest, givenReturnSubDevicesAsApiDevicesWhenCallClGetDeviceIDs EXPECT_EQ(devices[numEntries], dummyDevice); } +TEST(clGetDeviceIDsTest, givenZeFlatDeviceHierarchyWhenCallClGetDeviceIDsThenSubDevicesAreReturnedAsSeparateClDevices) { + platformsImpl->clear(); + constexpr auto numRootDevices = 3u; + VariableBackup backup(&ultHwConfig); + ultHwConfig.useMockedPrepareDeviceEnvironmentsFunc = false; + DebugManagerStateRestore restorer; + DebugManager.flags.CreateMultipleRootDevices.set(numRootDevices); + DebugManager.flags.CreateMultipleSubDevices.set(numRootDevices); + VariableBackup mockGetenvCalledBackup(&IoFunctions::mockGetenvCalled, 0); + std::unordered_map mockableEnvs = {{"ZE_FLAT_DEVICE_HIERARCHY", "FLAT"}}; + VariableBackup *> mockableEnvValuesBackup(&IoFunctions::mockableEnvValues, &mockableEnvs); + cl_uint maxNumDevices; + auto retVal = clGetDeviceIDs(nullptr, CL_DEVICE_TYPE_ALL, 0, nullptr, &maxNumDevices); + EXPECT_EQ(retVal, CL_SUCCESS); + EXPECT_EQ(numRootDevices * numRootDevices, maxNumDevices); + + cl_uint numDevices = 0; + cl_uint numEntries = maxNumDevices - 1; + cl_device_id devices[numRootDevices * numRootDevices]; + + const auto dummyDevice = reinterpret_cast(0x1357); + for (auto i = 0u; i < maxNumDevices; i++) { + devices[i] = dummyDevice; + } + + retVal = clGetDeviceIDs(nullptr, CL_DEVICE_TYPE_ALL, numEntries, devices, &numDevices); + EXPECT_EQ(retVal, CL_SUCCESS); + EXPECT_LT(numDevices, maxNumDevices); + EXPECT_EQ(numEntries, numDevices); + for (auto i = 0u; i < numEntries; i++) { + EXPECT_EQ(devices[i], platform()->getClDevice(i / numRootDevices)->getSubDevice(i % numRootDevices)); + } + EXPECT_EQ(devices[numEntries], dummyDevice); +} + TEST(clGetDeviceIDsTest, givenMultipleRootDevicesAndLimitedNumberOfReturnedDevicesWhenGetDeviceIdsThenLimitedNumberOfRootDevicesIsReturned) { platformsImpl->clear(); constexpr auto numRootDevices = 3u; diff --git a/shared/source/execution_environment/execution_environment.cpp b/shared/source/execution_environment/execution_environment.cpp index dad625dfe1..0d0ec86424 100644 --- a/shared/source/execution_environment/execution_environment.cpp +++ b/shared/source/execution_environment/execution_environment.cpp @@ -19,6 +19,7 @@ #include "shared/source/helpers/string_helpers.h" #include "shared/source/memory_manager/memory_manager.h" #include "shared/source/memory_manager/os_agnostic_memory_manager.h" +#include "shared/source/os_interface/debug_env_reader.h" #include "shared/source/os_interface/driver_info.h" #include "shared/source/os_interface/os_environment.h" #include "shared/source/os_interface/os_interface.h" @@ -153,6 +154,10 @@ void ExecutionEnvironment::parseAffinityMask() { if (NEO::DebugManager.flags.ReturnSubDevicesAsApiDevices.get() != -1) { exposeSubDevicesAsApiDevices = NEO::DebugManager.flags.ReturnSubDevicesAsApiDevices.get(); } + // If the user has requested FLAT device hierarchy models, then report all the sub devices as devices. + if (this->subDevicesAsDevices) { + exposeSubDevicesAsApiDevices = true; + } uint32_t numRootDevices = static_cast(rootDeviceEnvironments.size()); @@ -317,6 +322,14 @@ void ExecutionEnvironment::configureNeoEnvironment() { DebugManager.flags.UseKmdMigration.setIfDefault(0); DebugManager.flags.SplitBcsSize.setIfDefault(256); } + NEO::EnvironmentVariableReader envReader; + std::string hierarchyModel = envReader.getSetting("ZE_FLAT_DEVICE_HIERARCHY", std::string("COMPOSITE")); + if (strcmp(hierarchyModel.c_str(), "COMPOSITE") == 0) { + setExposeSubDevicesAsDevices(false); + } + if (strcmp(hierarchyModel.c_str(), "FLAT") == 0) { + setExposeSubDevicesAsDevices(true); + } } bool ExecutionEnvironment::comparePciIdBusNumber(std::unique_ptr &rootDeviceEnvironment1, std::unique_ptr &rootDeviceEnvironment2) { diff --git a/shared/source/execution_environment/execution_environment.h b/shared/source/execution_environment/execution_environment.h index 69b185a7e3..6706d1f391 100644 --- a/shared/source/execution_environment/execution_environment.h +++ b/shared/source/execution_environment/execution_environment.h @@ -43,6 +43,10 @@ class ExecutionEnvironment : public ReferenceTrackedObject void setMetricsEnabled(bool value) { this->metricsEnabled = value; } + void setExposeSubDevicesAsDevices(bool value) { + this->subDevicesAsDevices = value; + } + bool isExposingSubDevicesAsDevices() const { return this->subDevicesAsDevices; } bool areMetricsEnabled() { return this->metricsEnabled; } void setFP64EmulationEnabled() { fp64EmulationEnabled = true; @@ -64,6 +68,7 @@ class ExecutionEnvironment : public ReferenceTrackedObject void configureNeoEnvironment(); bool metricsEnabled = false; bool fp64EmulationEnabled = false; + bool subDevicesAsDevices = false; DebuggingMode debuggingEnabledMode = DebuggingMode::Disabled; std::unordered_map rootDeviceNumCcsMap; diff --git a/shared/test/unit_test/execution_environment/execution_environment_tests.cpp b/shared/test/unit_test/execution_environment/execution_environment_tests.cpp index d5f5d7ff1f..c793211dc7 100644 --- a/shared/test/unit_test/execution_environment/execution_environment_tests.cpp +++ b/shared/test/unit_test/execution_environment/execution_environment_tests.cpp @@ -27,6 +27,7 @@ #include "shared/test/common/mocks/mock_device.h" #include "shared/test/common/mocks/mock_driver_model.h" #include "shared/test/common/mocks/mock_execution_environment.h" +#include "shared/test/common/mocks/mock_io_functions.h" #include "shared/test/common/mocks/mock_memory_manager.h" #include "shared/test/common/mocks/mock_memory_operations_handler.h" #include "shared/test/common/test_macros/test.h" @@ -439,6 +440,22 @@ TEST(ExecutionEnvironment, givenExecutionEnvironmentWhenSettingFP64EmulationEnab EXPECT_TRUE(executionEnvironment.isFP64EmulationEnabled()); } +TEST(ExecutionEnvironmentDeviceHierarchy, givenExecutionEnvironmentWithCompositeDeviceHierarchyThenExposeSubDevicesAsDevicesIsFalse) { + VariableBackup mockGetenvCalledBackup(&IoFunctions::mockGetenvCalled, 0); + std::unordered_map mockableEnvs = {{"ZE_FLAT_DEVICE_HIERARCHY", "COMPOSITE"}}; + VariableBackup *> mockableEnvValuesBackup(&IoFunctions::mockableEnvValues, &mockableEnvs); + ExecutionEnvironment executionEnvironment{}; + EXPECT_FALSE(executionEnvironment.isExposingSubDevicesAsDevices()); +} + +TEST(ExecutionEnvironmentDeviceHierarchy, givenExecutionEnvironmentWithFlatDeviceHierarchyThenExposeSubDevicesAsDevicesIsTrue) { + VariableBackup mockGetenvCalledBackup(&IoFunctions::mockGetenvCalled, 0); + std::unordered_map mockableEnvs = {{"ZE_FLAT_DEVICE_HIERARCHY", "FLAT"}}; + VariableBackup *> mockableEnvValuesBackup(&IoFunctions::mockableEnvValues, &mockableEnvs); + ExecutionEnvironment executionEnvironment{}; + EXPECT_TRUE(executionEnvironment.isExposingSubDevicesAsDevices()); +} + void ExecutionEnvironmentSortTests::SetUp() { executionEnvironment.prepareRootDeviceEnvironments(numRootDevices); for (uint32_t rootDeviceIndex = 0; rootDeviceIndex < numRootDevices; rootDeviceIndex++) {