Remove unsupported plugin from proxy in order to avoid exception catching (#18518)

* Remove unsupported plugin from proxy in order to avoid exception
catching

* Remove from alias for

* Globally remove unavailable devices

* Do not load proxy if no available devices

* Try to fix CI

* Add debug messages

* Avoid two times the same plugin

* Revert "Add debug messages"

This reverts commit 562e36c633.

* Cache hidden devices

* Update if fallback order was changed

* Try to fix CI

* Fixed CoreThreading tests

* Fixed typo

* Try to fix plugin initialization

* Fixed initialization

* Fixed lock
This commit is contained in:
Ilya Churaev
2023-07-17 11:10:59 +04:00
committed by GitHub
parent a2b75bbc87
commit f38566834b
4 changed files with 136 additions and 19 deletions

View File

@@ -614,6 +614,14 @@ ov::Plugin ov::CoreImpl::get_plugin(const std::string& pluginName) const {
initial_config[ov::device::priorities.name()] = it->second; initial_config[ov::device::priorities.name()] = it->second;
} }
plugin.set_property(initial_config); plugin.set_property(initial_config);
try {
plugin.get_property(ov::available_devices);
} catch (const ov::Exception& ex) {
OPENVINO_THROW("Failed to create plugin for device ",
deviceName,
"\nPlease, check your environment\n",
ex.what());
}
} }
#endif #endif
// TODO: remove this block of code once GPU removes support of ov::cache_dir // TODO: remove this block of code once GPU removes support of ov::cache_dir
@@ -664,8 +672,9 @@ ov::Plugin ov::CoreImpl::get_plugin(const std::string& pluginName) const {
}); });
} }
std::lock_guard<std::mutex> g_lock(get_mutex());
// add plugin as extension itself // add plugin as extension itself
std::lock_guard<std::mutex> g_lock(get_mutex());
if (desc.extensionCreateFunc) { // static OpenVINO case if (desc.extensionCreateFunc) { // static OpenVINO case
try { try {
InferenceEngine::IExtensionPtr ext; InferenceEngine::IExtensionPtr ext;

View File

@@ -146,11 +146,13 @@ void ov::proxy::Plugin::set_property(const ov::AnyMap& properties) {
// Empty config_name means means global config for all devices // Empty config_name means means global config for all devices
std::string config_name = is_device_in_config(hw_config) ? std::to_string(get_device_from_config(hw_config)) : ""; std::string config_name = is_device_in_config(hw_config) ? std::to_string(get_device_from_config(hw_config)) : "";
bool proxy_config_was_changed = false;
// Parse alias config // Parse alias config
it = hw_config.find(ov::proxy::alias_for.name()); it = hw_config.find(ov::proxy::alias_for.name());
bool fill_order = hw_config.find(ov::proxy::device_priorities.name()) == hw_config.end() && m_device_order.empty(); bool fill_order = hw_config.find(ov::proxy::device_priorities.name()) == hw_config.end() && m_device_order.empty();
if (it != hw_config.end()) { if (it != hw_config.end()) {
for (auto&& dev : it->second.as<std::vector<std::string>>()) { for (auto&& dev : it->second.as<std::vector<std::string>>()) {
proxy_config_was_changed = true;
m_alias_for.emplace(dev); m_alias_for.emplace(dev);
if (fill_order) if (fill_order)
m_device_order.emplace_back(dev); m_device_order.emplace_back(dev);
@@ -160,6 +162,7 @@ void ov::proxy::Plugin::set_property(const ov::AnyMap& properties) {
// Restore device order // Restore device order
it = hw_config.find(ov::proxy::device_priorities.name()); it = hw_config.find(ov::proxy::device_priorities.name());
if (it != hw_config.end()) { if (it != hw_config.end()) {
proxy_config_was_changed = true;
m_device_order.clear(); m_device_order.clear();
std::vector<std::pair<std::string, size_t>> priority_order; std::vector<std::pair<std::string, size_t>> priority_order;
// Biggest number means minimum priority // Biggest number means minimum priority
@@ -207,6 +210,7 @@ void ov::proxy::Plugin::set_property(const ov::AnyMap& properties) {
std::lock_guard<std::mutex> lock(m_plugin_mutex); std::lock_guard<std::mutex> lock(m_plugin_mutex);
it = hw_config.find(ov::device::priorities.name()); it = hw_config.find(ov::device::priorities.name());
if (it != hw_config.end()) { if (it != hw_config.end()) {
proxy_config_was_changed = true;
m_configs[config_name][ov::device::priorities.name()] = it->second; m_configs[config_name][ov::device::priorities.name()] = it->second;
// Main device is needed in case if we don't have alias and would like to be able change fallback order per // Main device is needed in case if we don't have alias and would like to be able change fallback order per
// device // device
@@ -214,12 +218,23 @@ void ov::proxy::Plugin::set_property(const ov::AnyMap& properties) {
m_alias_for.insert(it->second.as<std::vector<std::string>>()[0]); m_alias_for.insert(it->second.as<std::vector<std::string>>()[0]);
} }
} }
const std::string primary_dev = get_primary_device(get_device_from_config(hw_config)); if (proxy_config_was_changed) {
// need initialization of hidden devices
m_init_devs = false;
}
// Add fallback priority to detect supported devices in case of HETERO fallback // Add fallback priority to detect supported devices in case of HETERO fallback
auto device_priority = get_internal_property(ov::device::priorities.name(), config_name); auto device_priority = get_internal_property(ov::device::priorities.name(), config_name);
if (!device_priority.empty()) if (!device_priority.empty())
hw_config[ov::device::priorities.name()] = device_priority; hw_config[ov::device::priorities.name()] = device_priority;
auto dev_id = get_device_from_config(hw_config);
auto dev_properties = remove_proxy_properties(hw_config, true); auto dev_properties = remove_proxy_properties(hw_config, true);
if (dev_properties.empty() && hw_config.empty())
// Nothing to do
return;
const std::string primary_dev = get_primary_device(dev_id);
std::string dev_prop_name; std::string dev_prop_name;
ov::DeviceIDParser pr_parser(primary_dev); ov::DeviceIDParser pr_parser(primary_dev);
for (const auto& it : dev_properties) { for (const auto& it : dev_properties) {
@@ -460,28 +475,49 @@ std::vector<std::vector<std::string>> ov::proxy::Plugin::get_hidden_devices() co
// Proxy plugin has 2 modes of matching devices: // Proxy plugin has 2 modes of matching devices:
// * Fallback - in this mode we report devices only for the first hidden plugin // * Fallback - in this mode we report devices only for the first hidden plugin
// * Alias - Case when we group all devices under one common name // * Alias - Case when we group all devices under one common name
std::vector<std::vector<std::string>> result; if (m_init_devs)
return m_hidden_devices;
std::lock_guard<std::mutex> lock(m_init_devs_mutex);
if (m_init_devs)
return m_hidden_devices;
m_hidden_devices.clear();
const auto core = get_core(); const auto core = get_core();
OPENVINO_ASSERT(core != nullptr); OPENVINO_ASSERT(core != nullptr);
OPENVINO_ASSERT(!m_alias_for.empty()); // alias_for cannot be empty. 1 is for fallback mode, >1 in other OPENVINO_ASSERT(
!m_alias_for.empty(),
get_device_name(),
" cannot find available devices!"); // alias_for cannot be empty. 1 is for fallback mode, >1 in other
// If we have 1 alias we use simple hetero mode // If we have 1 alias we use simple hetero mode
if (m_alias_for.size() == 1) { if (m_alias_for.size() == 1) {
auto device = *m_alias_for.begin(); auto device = *m_alias_for.begin();
// Allow to get runtime error, because only one plugin under the alias // Allow to get runtime error, because only one plugin under the alias
const std::vector<std::string> real_devices_ids = core->get_property(device, ov::available_devices); std::vector<std::string> real_devices_ids;
try {
real_devices_ids = core->get_property(device, ov::available_devices);
} catch (const std::runtime_error&) {
OPENVINO_THROW(get_device_name(), " cannot find available devices!");
}
for (const auto& device_id : real_devices_ids) { for (const auto& device_id : real_devices_ids) {
const std::string full_device_name = device_id.empty() ? device : device + '.' + device_id; const std::string full_device_name = device_id.empty() ? device : device + '.' + device_id;
std::vector<std::string> devices{full_device_name}; std::vector<std::string> devices;
// Add fallback devices use device_id for individual fallback property // Add fallback devices use device_id for individual fallback property
auto fallback = get_internal_property(ov::device::priorities.name(), device_id).as<std::string>(); auto fallback = get_internal_property(ov::device::priorities.name(), device_id).as<std::string>();
if (!fallback.empty()) { if (!fallback.empty()) {
for (const auto& fallback_dev : ov::util::split(fallback, ' ')) { for (const auto& fallback_dev : ov::util::split(fallback, ' ')) {
devices.emplace_back(fallback_dev); if (fallback_dev != device)
devices.emplace_back(fallback_dev);
else
devices.emplace_back(full_device_name);
} }
} else {
devices.emplace_back(full_device_name);
} }
result.emplace_back(devices); m_hidden_devices.emplace_back(devices);
} }
} else { } else {
typedef struct DeviceId { typedef struct DeviceId {
@@ -498,11 +534,13 @@ std::vector<std::vector<std::string>> ov::proxy::Plugin::get_hidden_devices() co
// 2. Use individual fallback priorities to fill each list // 2. Use individual fallback priorities to fill each list
std::vector<DeviceID_t> all_highlevel_devices; std::vector<DeviceID_t> all_highlevel_devices;
std::set<std::array<uint8_t, ov::device::UUID::MAX_UUID_SIZE>> unique_devices; std::set<std::array<uint8_t, ov::device::UUID::MAX_UUID_SIZE>> unique_devices;
std::unordered_set<std::string> unavailable_devices;
for (const auto& device : m_device_order) { for (const auto& device : m_device_order) {
std::vector<std::string> supported_device_ids; std::vector<std::string> supported_device_ids;
try { try {
supported_device_ids = core->get_property(device, ov::available_devices); supported_device_ids = core->get_property(device, ov::available_devices);
} catch (const std::runtime_error&) { } catch (const std::runtime_error&) {
unavailable_devices.emplace(device);
// Device cannot be loaded // Device cannot be loaded
continue; continue;
} }
@@ -537,6 +575,10 @@ std::vector<std::vector<std::string>> ov::proxy::Plugin::get_hidden_devices() co
} }
} }
OPENVINO_ASSERT(!all_highlevel_devices.empty(),
get_device_name(),
" cannot find available devices!"); // Devices should be found
// Use individual fallback order to generate result list // Use individual fallback order to generate result list
for (size_t i = 0; i < all_highlevel_devices.size(); i++) { for (size_t i = 0; i < all_highlevel_devices.size(); i++) {
std::vector<std::string> real_fallback_order; std::vector<std::string> real_fallback_order;
@@ -549,6 +591,8 @@ std::vector<std::vector<std::string>> ov::proxy::Plugin::get_hidden_devices() co
bool use_hetero_mode = device.no_uuid ? true : false; bool use_hetero_mode = device.no_uuid ? true : false;
std::vector<std::string> device_order; std::vector<std::string> device_order;
for (const auto& fallback_dev : fallback_order) { for (const auto& fallback_dev : fallback_order) {
if (unavailable_devices.count(fallback_dev))
continue;
if (!found_primary_device) { if (!found_primary_device) {
auto it = device.device_to_full_name.find(fallback_dev); auto it = device.device_to_full_name.find(fallback_dev);
if (it != device.device_to_full_name.end()) { if (it != device.device_to_full_name.end()) {
@@ -567,13 +611,7 @@ std::vector<std::vector<std::string>> ov::proxy::Plugin::get_hidden_devices() co
continue; continue;
} }
// Try to find unique device // Try to find unique device
std::vector<std::string> supported_device_ids; std::vector<std::string> supported_device_ids = core->get_property(fallback_dev, ov::available_devices);
try {
supported_device_ids = core->get_property(fallback_dev, ov::available_devices);
} catch (const std::runtime_error&) {
// Device cannot be loaded, so skipp this device
continue;
}
bool found_device = false; bool found_device = false;
bool dev_without_uuid = false; bool dev_without_uuid = false;
for (const auto& device_id : supported_device_ids) { for (const auto& device_id : supported_device_ids) {
@@ -602,7 +640,7 @@ std::vector<std::vector<std::string>> ov::proxy::Plugin::get_hidden_devices() co
device_order.emplace_back(device.device_to_full_name.begin()->second); device_order.emplace_back(device.device_to_full_name.begin()->second);
real_fallback_order.emplace_back(device.device_to_full_name.begin()->first); real_fallback_order.emplace_back(device.device_to_full_name.begin()->first);
} }
result.emplace_back(device_order); m_hidden_devices.emplace_back(device_order);
std::string new_fallback; std::string new_fallback;
for (const auto& dev : real_fallback_order) { for (const auto& dev : real_fallback_order) {
if (!new_fallback.empty()) if (!new_fallback.empty())
@@ -613,7 +651,8 @@ std::vector<std::vector<std::string>> ov::proxy::Plugin::get_hidden_devices() co
m_configs[std::to_string(i)][ov::device::priorities.name()] = new_fallback; m_configs[std::to_string(i)][ov::device::priorities.name()] = new_fallback;
} }
} }
return result; m_init_devs = true;
return m_hidden_devices;
} }
bool ov::proxy::Plugin::has_internal_property(const std::string& property, const std::string& config_name) const { bool ov::proxy::Plugin::has_internal_property(const std::string& property, const std::string& config_name) const {

View File

@@ -51,11 +51,14 @@ private:
const ov::AnyMap& properties) const; const ov::AnyMap& properties) const;
size_t m_default_device = 0; size_t m_default_device = 0;
std::vector<std::string> m_device_order; mutable std::vector<std::string> m_device_order;
std::unordered_set<std::string> m_alias_for; mutable std::unordered_set<std::string> m_alias_for;
// Update per device config in get_hidden_devices // Update per device config in get_hidden_devices
mutable std::unordered_map<std::string, ov::AnyMap> m_configs; mutable std::unordered_map<std::string, ov::AnyMap> m_configs;
mutable std::mutex m_plugin_mutex; mutable std::mutex m_plugin_mutex;
mutable std::mutex m_init_devs_mutex;
mutable std::vector<std::vector<std::string>> m_hidden_devices;
mutable bool m_init_devs{false};
}; };
} // namespace proxy } // namespace proxy

View File

@@ -148,6 +148,72 @@ TEST_F(ProxyTests, get_available_devices_with_low_level_plugin) {
EXPECT_TRUE(mock_reference_dev.empty()); EXPECT_TRUE(mock_reference_dev.empty());
} }
TEST_F(ProxyTests, load_proxy_without_several_devices) {
ov::AnyMap config;
config[ov::proxy::alias_for.name()] = std::vector<std::string>{"Fake1", "Fake2"};
config[ov::proxy::device_priorities.name()] = std::vector<std::string>{"Fake1:0", "Fake2:1"};
config[ov::device::priorities.name()] = std::vector<std::string>{"Fake1", "Fake2"};
// Change device priority
core.set_property("MOCK", config);
auto available_devices = core.get_available_devices();
EXPECT_THROW(core.get_property("MOCK", ov::device::priorities), ov::Exception);
std::set<std::string> mock_reference_dev = {"MOCK", "MOCK.0", "MOCK.1", "MOCK.2"};
for (const auto& dev : available_devices) {
if (mock_reference_dev.find(dev) != mock_reference_dev.end()) {
mock_reference_dev.erase(dev);
}
}
// Mock devices shouldn't be found
EXPECT_EQ(mock_reference_dev.size(), 4);
}
TEST_F(ProxyTests, load_proxy_without_devices) {
ov::AnyMap config;
config[ov::proxy::alias_for.name()] = "Fake";
config[ov::proxy::device_priorities.name()] = "Fake:1";
config[ov::device::priorities.name()] = std::vector<std::string>{"Fake"};
// Change device priority
core.set_property("MOCK", config);
auto available_devices = core.get_available_devices();
EXPECT_THROW(core.get_property("MOCK", ov::device::priorities), ov::Exception);
std::set<std::string> mock_reference_dev = {"MOCK", "MOCK.0", "MOCK.1", "MOCK.2"};
for (const auto& dev : available_devices) {
if (mock_reference_dev.find(dev) != mock_reference_dev.end()) {
mock_reference_dev.erase(dev);
}
}
// Mock devices shouldn't be found
EXPECT_EQ(mock_reference_dev.size(), 4);
}
TEST_F(ProxyTests, load_proxy_with_unavailable_device) {
ov::AnyMap config;
config[ov::proxy::alias_for.name()] = std::vector<std::string>{"Fake", "BDE"};
config[ov::proxy::device_priorities.name()] = std::vector<std::string>{"Fake:1", "BDE:0"};
config[ov::device::priorities.name()] = std::vector<std::string>{"Fake", "BDE"};
// Change device priority
core.set_property("MOCK", config);
auto available_devices = core.get_available_devices();
{
// We don't change fallback order for hetero case
std::unordered_map<std::string, std::string> mock_reference_dev = {{"MOCK.0", "BDE"},
{"MOCK.1", "BDE"},
{"MOCK.2", "BDE"}};
for (const auto& it : mock_reference_dev) {
std::cout << it.second << std::endl;
EXPECT_EQ(core.get_property(it.first, ov::device::priorities), it.second);
}
}
std::set<std::string> mock_reference_dev = {"MOCK.0", "MOCK.1", "MOCK.2"};
for (const auto& dev : available_devices) {
if (mock_reference_dev.find(dev) != mock_reference_dev.end()) {
mock_reference_dev.erase(dev);
}
}
// All devices should be found
EXPECT_TRUE(mock_reference_dev.empty());
}
TEST_F(ProxyTests, get_available_devices_with_disabled_plugin) { TEST_F(ProxyTests, get_available_devices_with_disabled_plugin) {
ov::AnyMap config; ov::AnyMap config;
config[ov::device::priorities.name()] = "BDE"; config[ov::device::priorities.name()] = "BDE";