diff --git a/src/plugins/auto/plugin.cpp b/src/plugins/auto/plugin.cpp index aa05129cb46..165f5c3db6c 100644 --- a/src/plugins/auto/plugin.cpp +++ b/src/plugins/auto/plugin.cpp @@ -850,83 +850,92 @@ std::string MultiDeviceInferencePlugin::GetDeviceList(const std::mapGetAvailableDevices(); auto deviceListConfig = config.find(ov::device::priorities.name()); - if (deviceListConfig->second.empty()) { - for (auto&& device : deviceList) { - // filter out the supported devices - if (!_pluginConfig.isSupportedDevice(device)) - continue; - allDevices += device + ","; - } - } else { + for (auto&& device : deviceList) { + // filter out the supported devices + if (!_pluginConfig.isSupportedDevice(device)) + continue; + allDevices += device + ","; + } + std::vector devicesMerged; + if (deviceListConfig != config.end() && !deviceListConfig->second.empty()) { auto priorities = deviceListConfig->second; // parsing the string and splitting the comma-separated tokens - std::vector deviceVec = _pluginConfig.ParsePrioritiesDevices(priorities); - std::vector devicesToBeDeleted; - auto updateDeviceVec = [&](const std::string& delPattern = "") { - auto iter = deviceVec.begin(); - while (iter != deviceVec.end()) { - if (delPattern.empty()) { - if ((*iter).find("-") == 0) { - devicesToBeDeleted.push_back((*iter).erase(0, 1)); - iter = deviceVec.erase(iter); - } else { - iter++; - } - } else { - if ((*iter).find(delPattern) != std::string::npos) - iter = deviceVec.erase(iter); - else - iter++; - } - } + std::vector devicesToBeMerged = _pluginConfig.ParsePrioritiesDevices(priorities); + std::vector devicesToBeDeleted(devicesToBeMerged.size()); + const auto& iterDel = std::copy_if(devicesToBeMerged.begin(), + devicesToBeMerged.end(), + devicesToBeDeleted.begin(), + [](const std::string& item) { + return item.front() == '-'; + }); + devicesToBeDeleted.resize(std::distance(devicesToBeDeleted.begin(), iterDel)); + const auto& iterMerge = + std::remove_if(devicesToBeMerged.begin(), devicesToBeMerged.end(), [](const std::string& item) { + return item.front() == '-'; + }); + devicesToBeMerged.resize(std::distance(devicesToBeMerged.begin(), iterMerge)); + for (auto&& device : devicesToBeDeleted) + LOG_INFO_TAG("remove %s from device candidate list", device.c_str()); + auto isAnyDev = [](std::string& device, const std::vector& devices) { + auto iter = std::find_if(devices.begin(), devices.end(), [device](const std::string& devItem) { + return devItem.find(device) != std::string::npos; + }); + return iter != devices.end(); }; - updateDeviceVec(); - if (devicesToBeDeleted.size() == 0) { - allDevices = deviceListConfig->second; - } else { - auto deviceNeedToMerge = [&](const std::string& devicename) { - for (auto&& iter : devicesToBeDeleted) { - if (iter.find(devicename) != std::string::npos) - return true; - } - return false; - }; - auto mergeDeviceList = [&]() { - std::vector mergedList; - auto prevSize = mergedList.size(); - for (auto&& iter : deviceVec) { - for (auto&& viter : deviceList) { - if (viter.find(iter) != std::string::npos && deviceNeedToMerge(iter)) - mergedList.push_back(std::move(viter)); - } - // if virtual devices or mock devices - if (mergedList.size() == prevSize) - mergedList.push_back(std::move(iter)); - prevSize = mergedList.size(); - } - return mergedList; - }; - - deviceVec = deviceVec.size() == 0 ? deviceList : mergeDeviceList(); - for (auto& iter : devicesToBeDeleted) { - LOG_INFO_TAG("remove %s from device candidate list", iter.c_str()); - updateDeviceVec(iter); - } - for (auto&& device : deviceVec) { - if (!_pluginConfig.isSupportedDevice(device)) + auto deviceWithDefaultID = [](std::string& device) { + // AUTO assume the default device ID will be "0" for the single device. + return device.find(".") == std::string::npos ? device + ".0" : device; + }; + if (devicesToBeMerged.empty()) { + for (auto&& device : deviceList) { + if (isAnyDev(device, devicesToBeDeleted) || !_pluginConfig.isSupportedDevice(device)) continue; - allDevices += device + ","; + devicesMerged.push_back(device); + } + } else { + for (auto&& device : devicesToBeMerged) { + if (!isAnyDev(device, deviceList)) { + DeviceIDParser parsed{device}; + auto iter = std::find(devicesMerged.begin(), devicesMerged.end(), parsed.getDeviceName()); + if (iter != devicesMerged.end() && parsed.getDeviceName() != device && parsed.getDeviceID() == "0") + // The device is the device with default device ID (eg. GPU.0) and + // its wide name (eg. GPU) has been in device candidate list. + continue; + // Add user specified device into candidate list + devicesMerged.push_back(device); + } else { + // Update device name if supported device with id existed + for (auto&& item : deviceList) { + auto realDevice = deviceWithDefaultID(item); + if (isAnyDev(realDevice, devicesToBeDeleted) || item.find(device) == std::string::npos) + continue; + auto iter = std::find(devicesMerged.begin(), devicesMerged.end(), deviceWithDefaultID(item)); + // Remove the device with default device id from candidate device list (eg. GPU.0) + // if its wide name is a single device (eg. GPU). + DeviceIDParser parsed{item}; + if (parsed.getDeviceName() == item && iter != devicesMerged.end()) + devicesMerged.erase(iter); + // continue if targe device has been in the candidate device list. + if (std::find(devicesMerged.begin(), devicesMerged.end(), item) != devicesMerged.end()) + continue; + devicesMerged.push_back(item); + } + } } } } - - // remove the last ',' if exist - if (allDevices.back() == ',') - allDevices.pop_back(); - + if (devicesMerged.size()) { + allDevices.clear(); + std::for_each(devicesMerged.begin(), devicesMerged.end(), [&allDevices](const std::string& device) { + allDevices += device + ","; + }); + } if (allDevices.empty()) { IE_THROW() << "Please, check environment due to no supported devices can be used"; } + // remove the last ',' if exist + if (allDevices.back() == ',') + allDevices.pop_back(); return allDevices; } diff --git a/src/plugins/auto/plugin_config.cpp b/src/plugins/auto/plugin_config.cpp index b344585a06c..7fffa536a5b 100644 --- a/src/plugins/auto/plugin_config.cpp +++ b/src/plugins/auto/plugin_config.cpp @@ -5,6 +5,10 @@ namespace MultiDevicePlugin { const std::set PluginConfig::_availableDevices = {"AUTO", "CPU", "GPU", "TEMPLATE", "NVIDIA", "VPUX", "MULTI", "HETERO", "mock"}; +// AUTO will enable the blocklist if +// 1.No device priority passed to AUTO/MULTI.(eg. core.compile_model(model, "AUTO", configs);) +// 2.No valid device parsed out from device priority (eg. core.compile_model(model, "AUTO:-CPU,-GPU", configs);). +const std::set PluginConfig::_deviceBlocklist = {"VPUX", "GNA"}; PluginConfig::PluginConfig() { set_default(); diff --git a/src/plugins/auto/utils/plugin_config.hpp b/src/plugins/auto/utils/plugin_config.hpp index f0221d47192..243e1800199 100644 --- a/src/plugins/auto/utils/plugin_config.hpp +++ b/src/plugins/auto/utils/plugin_config.hpp @@ -205,7 +205,7 @@ public: if ((realEndPos = realDevName.find('(')) != std::string::npos) { realDevName = realDevName.substr(0, realEndPos); } - if (_availableDevices.end() == std::find(_availableDevices.begin(), _availableDevices.end(), realDevName)) { + if (_deviceBlocklist.end() != std::find(_deviceBlocklist.begin(), _deviceBlocklist.end(), realDevName)) { return false; } return true; @@ -217,17 +217,13 @@ public: std::string::size_type endpos = 0; while ((endpos = priorities.find(separator, pos)) != std::string::npos) { auto subStr = priorities.substr(pos, endpos - pos); - if (!isSupportedDevice(subStr)) { - IE_THROW() << "Unavailable device name: " << subStr; - } - devices.push_back(subStr); + if (!subStr.empty()) + devices.push_back(subStr); pos = endpos + 1; } auto subStr = priorities.substr(pos, priorities.length() - pos); - if (!isSupportedDevice(subStr)) { - IE_THROW() << "Unavailable device name: " << subStr; - } - devices.push_back(subStr); + if (!subStr.empty()) + devices.push_back(subStr); return devices; } @@ -239,5 +235,6 @@ private: std::map property_validators; BaseValidator::Ptr device_property_validator; static const std::set _availableDevices; + static const std::set _deviceBlocklist; }; } // namespace MultiDevicePlugin diff --git a/src/tests/unit/auto/get_device_list.cpp b/src/tests/unit/auto/get_device_list.cpp index 73e0a8938e3..27456ffcd99 100644 --- a/src/tests/unit/auto/get_device_list.cpp +++ b/src/tests/unit/auto/get_device_list.cpp @@ -23,6 +23,7 @@ using ::testing::Property; using ::testing::Eq; using ::testing::AnyNumber; using ::testing::ReturnRef; +using ::testing::NiceMock; using ::testing::AtLeast; using ::testing::InvokeWithoutArgs; using Config = std::map; @@ -33,24 +34,35 @@ const char igpuFullDeviceName[] = "Intel(R) Gen9 HD Graphics (iGPU)"; const char dgpuFullDeviceName[] = "Intel(R) Iris(R) Xe MAX Graphics (dGPU)"; // const char myriadFullDeviceName[] = "Intel Movidius Myriad X VPU"; // const char vpuxFullDeviceName[] = ""; -const std::vector availableDevs = {"CPU", "GPU.0", "GPU.1", "VPUX", "UNSUPPORTED_DEVICE"}; +const std::vector availableDevs = {"CPU", "GPU", "VPUX"}; +const std::vector availableDevsWithId = {"CPU", "GPU.0", "GPU.1", "VPUX"}; +using Params = std::tuple; using ConfigParams = std::tuple< - std::string, // Priority devices - std::string // expect metaDevices + std::vector, // Available devices retrieved from Core + Params // Params {devicePriority, expect metaDevices} >; class GetDeviceListTest : public ::testing::TestWithParam { public: - std::shared_ptr core; - std::shared_ptr plugin; + std::shared_ptr> core; + std::shared_ptr> plugin; public: static std::string getTestCaseName(testing::TestParamInfo obj) { + Params priorityAndMetaDev; std::string priorityDevices; std::string metaDevices; - std::tie(priorityDevices, metaDevices) = obj.param; + std::vector availableDevices; + std::tie(availableDevices, priorityAndMetaDev) = obj.param; + std::tie(priorityDevices, metaDevices) = priorityAndMetaDev; std::ostringstream result; result << "priorityDevices_" << priorityDevices; result << "_expectedDevices" << metaDevices; + result << "_availableDevicesList"; + std::string devicesStr; + for (auto&& device : availableDevices) { + devicesStr += "_" + device; + } + result << devicesStr; return result.str(); } @@ -61,15 +73,12 @@ public: void SetUp() override { // prepare mockicore and cnnNetwork for loading - core = std::shared_ptr(new MockICore()); - auto* origin_plugin = new MockMultiDeviceInferencePlugin(); - plugin = std::shared_ptr(origin_plugin); + core = std::shared_ptr>(new NiceMock()); + auto* origin_plugin = new NiceMock(); + plugin = std::shared_ptr>(origin_plugin); // replace core with mock Icore plugin->SetCore(core); - - ON_CALL(*core, GetAvailableDevices()).WillByDefault(Return(availableDevs)); - ON_CALL(*plugin, GetDeviceList).WillByDefault([this]( const std::map& config) { return plugin->MultiDeviceInferencePlugin::GetDeviceList(config); @@ -79,40 +88,72 @@ public: TEST_P(GetDeviceListTest, GetDeviceListTestWithExcludeList) { // get Parameter + Params priorityAndMetaDev; std::string priorityDevices; std::string metaDevices; - std::tie(priorityDevices, metaDevices) = this->GetParam(); + std::vector availableDevs; + std::tie(availableDevs, priorityAndMetaDev) = this->GetParam(); + std::tie(priorityDevices, metaDevices) = priorityAndMetaDev; - //EXPECT_CALL(*plugin, GetDeviceList(_)).Times(1); + ON_CALL(*core, GetAvailableDevices()).WillByDefault(Return(availableDevs)); EXPECT_CALL(*core, GetAvailableDevices()).Times(1); auto result = plugin->GetDeviceList({{ov::device::priorities.name(), priorityDevices}}); EXPECT_EQ(result, metaDevices); } +const std::vector testConfigsWithId = {Params{" ", " "}, + Params{"", "CPU,GPU.0,GPU.1"}, + Params{"CPU, ", "CPU, "}, + Params{" ,CPU", " ,CPU"}, + Params{"CPU,", "CPU"}, + Params{"CPU,,GPU", "CPU,GPU.0,GPU.1"}, + Params{"CPU, ,GPU", "CPU, ,GPU.0,GPU.1"}, + Params{"CPU,GPU,GPU.1", "CPU,GPU.0,GPU.1"}, + Params{"CPU,GPU,VPUX,INVALID_DEVICE", "CPU,GPU.0,GPU.1,VPUX,INVALID_DEVICE"}, + Params{"VPUX,GPU,CPU,-GPU.0", "VPUX,GPU.1,CPU"}, + Params{"-GPU.0,GPU,CPU", "GPU.1,CPU"}, + Params{"-GPU.0,GPU", "GPU.1"}, + Params{"-GPU,GPU.0", "GPU.0"}, + Params{"-GPU.0", "CPU,GPU.1"}, + Params{"-GPU.0,-GPU.1", "CPU"}, + Params{"-GPU.0,-GPU.1,INVALID_DEVICE", "INVALID_DEVICE"}, + Params{"-GPU.0,-GPU.1,-INVALID_DEVICE", "CPU"}, + Params{"-GPU.0,-CPU", "GPU.1"}}; -// ConfigParams details -// example -// ConfigParams {devicePriority, expect metaDevices, ifThrowException} +const std::vector testConfigs = {Params{" ", " "}, + Params{"", "CPU,GPU"}, + Params{"GPU", "GPU"}, + Params{"GPU.0", "GPU.0"}, + Params{"GPU,GPU.0", "GPU"}, + Params{"CPU", "CPU"}, + Params{" ,CPU", " ,CPU"}, + Params{" ,GPU", " ,GPU"}, + Params{"GPU, ", "GPU, "}, + Params{"CPU,GPU", "CPU,GPU"}, + Params{"CPU,-GPU", "CPU"}, + Params{"CPU,-GPU,GPU.0", "CPU,GPU.0"}, + Params{"CPU,-GPU,GPU.1", "CPU,GPU.1"}, + Params{"CPU,GPU,-GPU.0", "CPU"}, + Params{"CPU,GPU,-GPU.1", "CPU,GPU"}, + Params{"CPU,GPU.0,GPU", "CPU,GPU"}, + Params{"CPU,GPU,GPU.0", "CPU,GPU"}, + Params{"CPU,GPU,GPU.1", "CPU,GPU,GPU.1"}, + Params{"CPU,GPU.1,GPU", "CPU,GPU.1,GPU"}, + Params{"CPU,VPUX", "CPU,VPUX"}, + Params{"CPU,-VPUX", "CPU"}, + Params{"CPU,-INVALID_DEVICE", "CPU"}, + Params{"CPU,GPU,VPUX", "CPU,GPU,VPUX"}}; -const std::vector testConfigs = { - // - ConfigParams {"CPU,GPU,VPUX", - "CPU,GPU,VPUX"}, - ConfigParams {"VPUX,GPU,CPU,-GPU.0", - "VPUX,GPU.1,CPU"}, - ConfigParams {"-GPU.0,GPU,CPU", - "GPU.1,CPU"}, - ConfigParams {"-GPU.0,GPU", - "GPU.1"}, - ConfigParams {"-GPU.0", "CPU,GPU.1,VPUX"}, - ConfigParams {"-GPU.0,-GPU.1", "CPU,VPUX"}, - ConfigParams {"-GPU.0,-CPU", "GPU.1,VPUX"} -}; +INSTANTIATE_TEST_SUITE_P(smoke_Auto_BehaviorTests_GetDeviceListWithID, + GetDeviceListTest, + ::testing::Combine(::testing::Values(availableDevsWithId), + ::testing::ValuesIn(testConfigsWithId)), + GetDeviceListTest::getTestCaseName); - -INSTANTIATE_TEST_SUITE_P(smoke_Auto_BehaviorTests, GetDeviceListTest, - ::testing::ValuesIn(testConfigs), - GetDeviceListTest::getTestCaseName); +INSTANTIATE_TEST_SUITE_P(smoke_Auto_BehaviorTests_GetDeviceList, + GetDeviceListTest, + ::testing::Combine(::testing::Values(availableDevs), ::testing::ValuesIn(testConfigs)), + GetDeviceListTest::getTestCaseName); //toDo need add test for ParseMetaDevices(_, config) to check device config of //return metaDevices