/* * Copyright (C) 2019-2021 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "shared/source/device/sub_device.h" #include "shared/source/os_interface/device_factory.h" #include "shared/source/os_interface/os_context.h" #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/ult_device_factory.h" #include "opencl/source/cl_device/cl_device.h" #include "opencl/test/unit_test/mocks/mock_cl_device.h" #include "opencl/test/unit_test/mocks/mock_memory_manager.h" #include "opencl/test/unit_test/mocks/mock_platform.h" using namespace NEO; TEST(SubDevicesTest, givenDefaultConfigWhenCreateRootDeviceThenItDoesntContainSubDevices) { auto device = std::unique_ptr(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); EXPECT_EQ(0u, device->getNumSubDevices()); EXPECT_EQ(1u, device->getNumAvailableDevices()); } TEST(SubDevicesTest, givenCreateMultipleSubDevicesFlagSetWhenCreateRootDeviceThenItsSubdevicesHaveProperRootIdSet) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(2); VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); auto device = std::unique_ptr(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); EXPECT_EQ(2u, device->getNumSubDevices()); EXPECT_EQ(0u, device->getRootDeviceIndex()); EXPECT_EQ(0u, device->subdevices.at(0)->getRootDeviceIndex()); EXPECT_EQ(0u, device->subdevices.at(0)->getSubDeviceIndex()); EXPECT_EQ(0u, device->subdevices.at(1)->getRootDeviceIndex()); EXPECT_EQ(1u, device->subdevices.at(1)->getSubDeviceIndex()); } TEST(SubDevicesTest, givenCreateMultipleSubDevicesFlagSetWhenCreateRootDeviceThenItContainsSubDevices) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(2); VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); auto device = std::unique_ptr(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); EXPECT_EQ(2u, device->getNumSubDevices()); EXPECT_EQ(2u, device->getNumAvailableDevices()); EXPECT_EQ(1u, device->subdevices.at(0)->getNumAvailableDevices()); EXPECT_EQ(1u, device->subdevices.at(1)->getNumAvailableDevices()); } TEST(SubDevicesTest, givenDeviceWithSubDevicesWhenSubDeviceApiRefCountsAreChangedThenChangeIsPropagatedToRootDevice) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(2); VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); initPlatform(); auto nonDefaultPlatform = std::make_unique(*platform()->peekExecutionEnvironment()); nonDefaultPlatform->initializeWithNewDevices(); auto device = nonDefaultPlatform->getClDevice(0); auto defaultDevice = platform()->getClDevice(0); auto subDevice = device->getDeviceById(1); auto baseDeviceApiRefCount = device->getRefApiCount(); auto baseDeviceInternalRefCount = device->getRefInternalCount(); auto baseSubDeviceApiRefCount = subDevice->getRefApiCount(); auto baseSubDeviceInternalRefCount = subDevice->getRefInternalCount(); auto baseDefaultDeviceApiRefCount = defaultDevice->getRefApiCount(); auto baseDefaultDeviceInternalRefCount = defaultDevice->getRefInternalCount(); subDevice->retainApi(); EXPECT_EQ(baseDeviceApiRefCount, device->getRefApiCount()); EXPECT_EQ(baseDeviceInternalRefCount + 1, device->getRefInternalCount()); EXPECT_EQ(baseSubDeviceApiRefCount + 1, subDevice->getRefApiCount()); EXPECT_EQ(baseSubDeviceInternalRefCount + 1, subDevice->getRefInternalCount()); EXPECT_EQ(baseDefaultDeviceApiRefCount, defaultDevice->getRefApiCount()); EXPECT_EQ(baseDefaultDeviceInternalRefCount, defaultDevice->getRefInternalCount()); subDevice->releaseApi(); EXPECT_EQ(baseDeviceApiRefCount, device->getRefApiCount()); EXPECT_EQ(baseDeviceInternalRefCount, device->getRefInternalCount()); EXPECT_EQ(baseSubDeviceApiRefCount, subDevice->getRefApiCount()); EXPECT_EQ(baseSubDeviceInternalRefCount, subDevice->getRefInternalCount()); EXPECT_EQ(baseDefaultDeviceApiRefCount, defaultDevice->getRefApiCount()); EXPECT_EQ(baseDefaultDeviceInternalRefCount, defaultDevice->getRefInternalCount()); } TEST(SubDevicesTest, givenDeviceWithSubDevicesWhenSubDeviceInternalRefCountsAreChangedThenChangeIsPropagatedToRootDevice) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(2); VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); auto device = std::unique_ptr(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); device->incRefInternal(); auto subDevice = device->getDeviceById(0); auto baseDeviceInternalRefCount = device->getRefInternalCount(); auto baseSubDeviceInternalRefCount = subDevice->getRefInternalCount(); subDevice->incRefInternal(); EXPECT_EQ(baseDeviceInternalRefCount + 1, device->getRefInternalCount()); EXPECT_EQ(baseSubDeviceInternalRefCount, subDevice->getRefInternalCount()); device->incRefInternal(); EXPECT_EQ(baseDeviceInternalRefCount + 2, device->getRefInternalCount()); EXPECT_EQ(baseSubDeviceInternalRefCount, subDevice->getRefInternalCount()); subDevice->decRefInternal(); EXPECT_EQ(baseDeviceInternalRefCount + 1, device->getRefInternalCount()); EXPECT_EQ(baseSubDeviceInternalRefCount, subDevice->getRefInternalCount()); device->decRefInternal(); EXPECT_EQ(baseDeviceInternalRefCount, device->getRefInternalCount()); EXPECT_EQ(baseSubDeviceInternalRefCount, subDevice->getRefInternalCount()); } TEST(SubDevicesTest, givenClDeviceWithSubDevicesWhenSubDeviceInternalRefCountsAreChangedThenChangeIsPropagatedToRootDevice) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(2); VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); auto device = std::make_unique(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); device->incRefInternal(); auto &subDevice = device->subDevices[0]; auto baseDeviceInternalRefCount = device->getRefInternalCount(); auto baseSubDeviceInternalRefCount = subDevice->getRefInternalCount(); subDevice->incRefInternal(); EXPECT_EQ(baseDeviceInternalRefCount + 1, device->getRefInternalCount()); EXPECT_EQ(baseSubDeviceInternalRefCount, subDevice->getRefInternalCount()); device->incRefInternal(); EXPECT_EQ(baseDeviceInternalRefCount + 2, device->getRefInternalCount()); EXPECT_EQ(baseSubDeviceInternalRefCount, subDevice->getRefInternalCount()); subDevice->decRefInternal(); EXPECT_EQ(baseDeviceInternalRefCount + 1, device->getRefInternalCount()); EXPECT_EQ(baseSubDeviceInternalRefCount, subDevice->getRefInternalCount()); device->decRefInternal(); EXPECT_EQ(baseDeviceInternalRefCount, device->getRefInternalCount()); EXPECT_EQ(baseSubDeviceInternalRefCount, subDevice->getRefInternalCount()); } TEST(SubDevicesTest, givenDeviceWithSubDevicesWhenSubDeviceCreationFailThenWholeDeviceIsDestroyed) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(10); MockExecutionEnvironment executionEnvironment; executionEnvironment.prepareRootDeviceEnvironments(1); executionEnvironment.incRefInternal(); executionEnvironment.memoryManager.reset(new FailMemoryManager(10, executionEnvironment)); auto device = Device::create(&executionEnvironment, 0u); EXPECT_EQ(nullptr, device); } TEST(SubDevicesTest, givenCreateMultipleRootDevicesFlagsEnabledWhenDevicesAreCreatedThenEachHasUniqueDeviceIndex) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleRootDevices.set(2); VariableBackup backup{&ultHwConfig}; ultHwConfig.useMockedPrepareDeviceEnvironmentsFunc = false; initPlatform(); EXPECT_EQ(0u, platform()->getClDevice(0)->getRootDeviceIndex()); EXPECT_EQ(1u, platform()->getClDevice(1)->getRootDeviceIndex()); } TEST(SubDevicesTest, givenRootDeviceWithSubDevicesWhenOsContextIsCreatedThenItsBitfieldBasesOnSubDevicesCount) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(2); VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); auto device = std::unique_ptr(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); EXPECT_EQ(2u, device->getNumSubDevices()); uint32_t rootDeviceBitfield = 0b11; EXPECT_EQ(rootDeviceBitfield, static_cast(device->getDefaultEngine().osContext->getDeviceBitfield().to_ulong())); } TEST(SubDevicesTest, givenSubDeviceWhenOsContextIsCreatedThenItsBitfieldBasesOnSubDeviceId) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(2); VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); auto device = std::unique_ptr(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); EXPECT_EQ(2u, device->getNumSubDevices()); auto firstSubDevice = static_cast(device->subdevices.at(0)); auto secondSubDevice = static_cast(device->subdevices.at(1)); uint32_t firstSubDeviceMask = (1u << 0); uint32_t secondSubDeviceMask = (1u << 1); EXPECT_EQ(firstSubDeviceMask, static_cast(firstSubDevice->getDefaultEngine().osContext->getDeviceBitfield().to_ulong())); EXPECT_EQ(secondSubDeviceMask, static_cast(secondSubDevice->getDefaultEngine().osContext->getDeviceBitfield().to_ulong())); } TEST(SubDevicesTest, givenDeviceWithoutSubDevicesWhenGettingDeviceByIdZeroThenGetThisDevice) { auto device = std::unique_ptr(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); EXPECT_EQ(1u, device->getNumAvailableDevices()); EXPECT_EQ(device.get(), device->getDeviceById(0u)); } TEST(SubDevicesTest, givenDeviceWithSubDevicesWhenGettingDeviceByIdThenGetCorrectSubDevice) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(2); VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); auto device = std::unique_ptr(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); EXPECT_EQ(2u, device->getNumSubDevices()); EXPECT_EQ(device->subdevices.at(0), device->getDeviceById(0)); EXPECT_EQ(device->subdevices.at(1), device->getDeviceById(1)); EXPECT_THROW(device->getDeviceById(2), std::exception); } TEST(SubDevicesTest, givenSubDevicesWhenGettingDeviceByIdZeroThenGetThisSubDevice) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(2); VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); auto device = std::unique_ptr(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); EXPECT_EQ(2u, device->getNumSubDevices()); auto subDevice = device->subdevices.at(0); EXPECT_EQ(subDevice, subDevice->getDeviceById(0)); } TEST(RootDevicesTest, givenRootDeviceWithoutSubdevicesWhenCreateEnginesThenDeviceCreatesCorrectNumberOfEngines) { auto hwInfo = *defaultHwInfo; auto &gpgpuEngines = HwHelper::get(hwInfo.platform.eRenderCoreFamily).getGpgpuEngineInstances(hwInfo); auto executionEnvironment = new MockExecutionEnvironment; MockDevice device(executionEnvironment, 0); EXPECT_EQ(0u, device.engines.size()); device.createEngines(); EXPECT_EQ(gpgpuEngines.size(), device.engines.size()); } TEST(RootDevicesTest, givenRootDeviceWithSubdevicesWhenCreateEnginesThenDeviceCreatesSpecialEngine) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(2); VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); auto executionEnvironment = new MockExecutionEnvironment; MockDevice device(executionEnvironment, 0); device.numSubDevices = 2; EXPECT_EQ(0u, device.engines.size()); device.createEngines(); EXPECT_EQ(1u, device.engines.size()); } TEST(SubDevicesTest, givenRootDeviceWithSubDevicesWhenGettingGlobalMemorySizeThenSubDevicesReturnReducedAmountOfGlobalMemAllocSize) { const uint32_t numSubDevices = 2u; UltDeviceFactory deviceFactory{1, numSubDevices}; auto rootDevice = deviceFactory.rootDevices[0]; auto totalGlobalMemorySize = rootDevice->getGlobalMemorySize(static_cast(rootDevice->getDeviceBitfield().to_ulong())); auto expectedGlobalMemorySize = totalGlobalMemorySize / numSubDevices; for (const auto &subDevice : deviceFactory.subDevices) { auto mockSubDevice = static_cast(subDevice); auto subDeviceBitfield = static_cast(mockSubDevice->getDeviceBitfield().to_ulong()); EXPECT_EQ(expectedGlobalMemorySize, mockSubDevice->getGlobalMemorySize(subDeviceBitfield)); } } TEST(SubDevicesTest, whenCreatingEngineInstancedSubDeviceThenSetCorrectSubdeviceIndex) { class MyRootDevice : public RootDevice { public: using RootDevice::createEngineInstancedSubDevice; using RootDevice::RootDevice; }; auto executionEnvironment = new ExecutionEnvironment(); executionEnvironment->prepareRootDeviceEnvironments(1); executionEnvironment->rootDeviceEnvironments[0]->setHwInfo(defaultHwInfo.get()); DeviceFactory::createMemoryManagerFunc(*executionEnvironment); auto rootDevice = std::unique_ptr(Device::create(executionEnvironment, 0)); auto subDevice = std::unique_ptr(rootDevice->createEngineInstancedSubDevice(1, defaultHwInfo->capabilityTable.defaultEngineType)); ASSERT_NE(nullptr, subDevice.get()); EXPECT_EQ(2u, subDevice->getDeviceBitfield().to_ulong()); } TEST(SubDevicesTest, givenDebugFlagSetAndMoreThanOneCcsWhenCreatingRootDeviceWithoutGenericSubDevicesThenCreateEngineInstanced) { DebugManagerStateRestore restorer; DebugManager.flags.EngineInstancedSubDevices.set(true); auto executionEnvironment = new ExecutionEnvironment(); executionEnvironment->prepareRootDeviceEnvironments(1); executionEnvironment->rootDeviceEnvironments[0]->setHwInfo(defaultHwInfo.get()); executionEnvironment->rootDeviceEnvironments[0]->getMutableHardwareInfo()->gtSystemInfo.CCSInfo.NumberOfCCSEnabled = 2; UltDeviceFactory deviceFactory(1, 1, *executionEnvironment); auto &rootDevice = deviceFactory.rootDevices[0]; auto &hwInfo = rootDevice->getHardwareInfo(); uint32_t ccsCount = hwInfo.gtSystemInfo.CCSInfo.NumberOfCCSEnabled; EXPECT_EQ(ccsCount, rootDevice->getNumAvailableDevices()); for (uint32_t i = 0; i < ccsCount; i++) { auto engineType = static_cast(aub_stream::EngineType::ENGINE_CCS + i); auto subDevice = static_cast(rootDevice->getDeviceById(i)); ASSERT_NE(nullptr, subDevice); EXPECT_TRUE(subDevice->engineInstanced); EXPECT_EQ(engineType, subDevice->engineType); } } TEST(SubDevicesTest, givenDebugFlagSetAndSingleCcsWhenCreatingRootDeviceWithoutGenericSubDevicesThenCreateEngineInstanced) { DebugManagerStateRestore restorer; DebugManager.flags.EngineInstancedSubDevices.set(true); auto executionEnvironment = new ExecutionEnvironment(); executionEnvironment->prepareRootDeviceEnvironments(1); executionEnvironment->rootDeviceEnvironments[0]->setHwInfo(defaultHwInfo.get()); executionEnvironment->rootDeviceEnvironments[0]->getMutableHardwareInfo()->gtSystemInfo.CCSInfo.NumberOfCCSEnabled = 1; UltDeviceFactory deviceFactory(1, 1, *executionEnvironment); auto &rootDevice = deviceFactory.rootDevices[0]; EXPECT_EQ(1u, rootDevice->getNumAvailableDevices()); EXPECT_FALSE(rootDevice->getDeviceById(0)->isSubDevice()); } TEST(SubDevicesTest, givenDebugFlagSetWhenCreatingRootDeviceWithGenericSubDevicesAndSingleCcsThenDontCreateEngineInstanced) { DebugManagerStateRestore restorer; DebugManager.flags.EngineInstancedSubDevices.set(true); auto executionEnvironment = new ExecutionEnvironment(); executionEnvironment->prepareRootDeviceEnvironments(1); executionEnvironment->rootDeviceEnvironments[0]->setHwInfo(defaultHwInfo.get()); executionEnvironment->rootDeviceEnvironments[0]->getMutableHardwareInfo()->gtSystemInfo.CCSInfo.NumberOfCCSEnabled = 1; UltDeviceFactory deviceFactory(1, 2, *executionEnvironment); auto &rootDevice = deviceFactory.rootDevices[0]; for (uint32_t i = 0; i < 2; i++) { auto subDevice = static_cast(rootDevice->getDeviceById(i)); ASSERT_NE(nullptr, subDevice); EXPECT_FALSE(subDevice->engineInstanced); EXPECT_EQ(1u, subDevice->getNumAvailableDevices()); EXPECT_EQ(aub_stream::EngineType::NUM_ENGINES, subDevice->engineType); } } TEST(SubDevicesTest, givenDebugFlagSetWhenCreatingRootDeviceWithGenericSubDevicesThenCreateEngineInstanced) { DebugManagerStateRestore restorer; DebugManager.flags.EngineInstancedSubDevices.set(true); uint32_t ccsCount = 2; auto executionEnvironment = new ExecutionEnvironment(); executionEnvironment->prepareRootDeviceEnvironments(1); executionEnvironment->rootDeviceEnvironments[0]->setHwInfo(defaultHwInfo.get()); executionEnvironment->rootDeviceEnvironments[0]->getMutableHardwareInfo()->gtSystemInfo.CCSInfo.NumberOfCCSEnabled = ccsCount; UltDeviceFactory deviceFactory(1, 2, *executionEnvironment); auto &rootDevice = deviceFactory.rootDevices[0]; for (uint32_t i = 0; i < 2; i++) { auto subDevice = static_cast(rootDevice->getDeviceById(i)); ASSERT_NE(nullptr, subDevice); EXPECT_FALSE(subDevice->engineInstanced); EXPECT_EQ(ccsCount, subDevice->getNumAvailableDevices()); EXPECT_EQ(aub_stream::EngineType::NUM_ENGINES, subDevice->engineType); for (uint32_t j = 0; j < ccsCount; j++) { auto engineType = static_cast(aub_stream::EngineType::ENGINE_CCS + j); auto engineSubDevice = static_cast(subDevice->getDeviceById(j)); ASSERT_NE(nullptr, engineSubDevice); EXPECT_TRUE(engineSubDevice->engineInstanced); EXPECT_EQ(1u, engineSubDevice->getNumAvailableDevices()); EXPECT_EQ(engineType, engineSubDevice->engineType); EXPECT_EQ(subDevice->getSubDeviceIndex(), engineSubDevice->getSubDeviceIndex()); EXPECT_EQ(subDevice->getDeviceBitfield(), engineSubDevice->getDeviceBitfield()); } } } TEST(SubDevicesTest, whenInitializeRootCsrThenDirectSubmissionIsNotInitialized) { auto device = std::make_unique(); device->initializeRootCommandStreamReceiver(); auto csr = device->getEngine(1u).commandStreamReceiver; EXPECT_FALSE(csr->isDirectSubmissionEnabled()); } TEST(SubDevicesTest, givenCreateMultipleSubDevicesFlagSetWhenBindlessHeapHelperCreatedThenSubDeviceReturnRootDeviceMember) { DebugManagerStateRestore restorer; DebugManager.flags.CreateMultipleSubDevices.set(2); VariableBackup mockDeviceFlagBackup(&MockDevice::createSingleDevice, false); auto device = std::unique_ptr(MockDevice::createWithNewExecutionEnvironment(defaultHwInfo.get())); device->getExecutionEnvironment()->rootDeviceEnvironments[device->getRootDeviceIndex()]->createBindlessHeapsHelper(device->getMemoryManager(), device->getNumAvailableDevices() > 1, device->getRootDeviceIndex()); EXPECT_EQ(device->getBindlessHeapsHelper(), device->subdevices.at(0)->getBindlessHeapsHelper()); }