Skip to content

Commit 80dfee9

Browse files
Device type refactoring (#630)
* Refactor device check logic * Validate the provider options key passed * Add support for mapping LUID to device * Fix lint warnings * generalise LUID for GPU and NPU
1 parent 1e85f1d commit 80dfee9

File tree

7 files changed

+118
-99
lines changed

7 files changed

+118
-99
lines changed

onnxruntime/core/providers/openvino/backends/basic_backend.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ void BasicBackend::PopulateConfigValue(ov::AnyMap& device_config) {
284284
//// Parse to get the device mode (e.g., "AUTO:CPU,GPU" -> "AUTO")
285285
std::unordered_set<std::string> supported_mode = {"AUTO", "HETERO", "MULTI"};
286286
auto device_mode = find_device_type_mode(session_context_.device_type);
287-
ORT_ENFORCE(supported_mode.find(device_mode)!=supported_mode.end(), " Invalid device mode is passed : " , session_context_.device_type);
287+
ORT_ENFORCE(supported_mode.find(device_mode) != supported_mode.end(), " Invalid device mode is passed : ", session_context_.device_type);
288288
// Parse individual devices (e.g., "AUTO:CPU,GPU" -> ["CPU", "GPU"])
289289
auto individual_devices = parse_individual_devices(session_context_.device_type);
290290
if (!device_mode.empty()) individual_devices.emplace_back(device_mode);

onnxruntime/core/providers/openvino/contexts.h

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <vector>
77
#include <map>
88
#include <unordered_map>
9+
#include <unordered_set>
910
#include <string>
1011
#include <filesystem>
1112
#include <memory>
@@ -102,6 +103,9 @@ struct ProviderInfo {
102103
bool so_share_ep_contexts{false}; // ORT session option
103104
fs::path so_context_file_path{}; // ORT session option
104105
const ConfigOptions* config_options{NULL};
106+
const std::unordered_set<std::string> valid_provider_keys = {"device_type", "device_id", "device_luid", "cache_dir",
107+
"load_config", "context", "num_of_threads", "model_priority", "num_streams", "enable_opencl_throttling", "enable_qdq_optimizer",
108+
"disable_dynamic_shapes"};
105109
};
106110

107111
// Holds context applicable to the entire EP instance.

onnxruntime/core/providers/openvino/openvino_execution_provider.cc

-51
Original file line numberDiff line numberDiff line change
@@ -58,57 +58,6 @@ OpenVINOExecutionProvider::OpenVINOExecutionProvider(const ProviderInfo& info, s
5858
shared_context_{shared_context},
5959
ep_ctx_handle_{session_context_.openvino_sdk_version, *GetLogger()} {
6060
InitProviderOrtApi();
61-
62-
// to check if target device is available
63-
// using OVCore capability GetAvailableDevices to fetch list of devices plugged in
64-
if (info.cache_dir.empty()) {
65-
bool all_devices_found = false;
66-
// Checking for device_type configuration
67-
if (info.device_type != "") {
68-
std::vector<std::string> devices_to_check;
69-
if (info.device_type.find("HETERO:") == 0 ||
70-
info.device_type.find("MULTI:") == 0 ||
71-
info.device_type.find("BATCH:") == 0 ||
72-
info.device_type.find("AUTO:") == 0) {
73-
auto delimit = info.device_type.find(":");
74-
const auto& devices = info.device_type.substr(delimit + 1);
75-
devices_to_check = split(devices, ',');
76-
} else {
77-
devices_to_check.push_back(info.device_type);
78-
}
79-
80-
// Re-initialize before loop
81-
all_devices_found = true;
82-
for (const auto& device : devices_to_check) {
83-
bool device_found = false;
84-
std::string device_prefix = device;
85-
int device_idx = 0;
86-
// Get the index and remove the index from device_prefix
87-
if (auto delimit = device_prefix.find("."); delimit != std::string::npos) {
88-
try {
89-
device_idx = std::stoi(device_prefix.substr(delimit + 1));
90-
} catch (std::exception& ex) {
91-
ORT_THROW("[ERROR] [OpenVINO] Wrong index in specified device - " + device + " :", ex.what());
92-
}
93-
device_prefix = device_prefix.substr(0, delimit);
94-
}
95-
std::vector<std::string> available_devices = OVCore::Get()->GetAvailableDevices(device_prefix);
96-
// If idx is 0, maybe index is not set (e.g. GPU)
97-
// Then the device is found if we have at least one device of the type
98-
if (device_idx == 0 && available_devices.size() >= 1) {
99-
device_found = true;
100-
} else {
101-
// Find full device (e.g GPU.1) in the list
102-
if (std::find(std::begin(available_devices), std::end(available_devices), device) != std::end(available_devices))
103-
device_found = true;
104-
}
105-
all_devices_found = all_devices_found && device_found;
106-
}
107-
}
108-
if (!all_devices_found) {
109-
ORT_THROW("[ERROR] [OpenVINO] Specified device - " + info.device_type + " is not available");
110-
}
111-
}
11261
}
11362

11463
OpenVINOExecutionProvider::~OpenVINOExecutionProvider() {

onnxruntime/core/providers/openvino/openvino_provider_factory.cc

+96-38
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
namespace onnxruntime {
1919
namespace openvino_ep {
2020
void ParseConfigOptions(ProviderInfo& pi) {
21-
2221
if (pi.config_options == nullptr)
2322
return;
2423

@@ -58,23 +57,29 @@ bool ParseBooleanOption(const ProviderOptions& provider_options, std::string opt
5857
return false;
5958
}
6059

61-
std::string ParseDeviceType(std::shared_ptr<OVCore> ov_core, const ProviderOptions& provider_options, std::string option_name) {
62-
// This function normally does not check if the selected device is available, but does some sanity checks
63-
// Only if the device is not standard, then availability is checked.
64-
// Availability is checked for the selected device in the OpenVINOExecutionProvider constructor
65-
60+
std::string ParseDeviceType(std::shared_ptr<OVCore> ov_core, const ProviderOptions& provider_options) {
61+
std::set<std::string> supported_device_types = {"CPU", "GPU", "NPU"};
62+
std::set<std::string> supported_device_modes = {"AUTO", "HETERO", "MULTI"};
6663
std::vector<std::string> devices_to_check;
6764
std::string selected_device;
68-
if (provider_options.contains(option_name)) {
69-
selected_device = provider_options.at(option_name);
70-
// If we have multiple device configuration, we need to check all of them
71-
if ((selected_device.find("HETERO:") == 0) ||
72-
(selected_device.find("MULTI:") == 0) ||
73-
(selected_device.find("BATCH:") == 0) ||
74-
(selected_device.find("AUTO:") == 0)) {
75-
auto delimit = selected_device.find(":");
76-
const auto& devices = selected_device.substr(delimit + 1);
77-
devices_to_check = split(devices, ',');
65+
std::vector<std::string> luid_list;
66+
std::string device_mode = "";
67+
std::map<std::string, std::string> ov_luid_map;
68+
69+
if (provider_options.contains("device_type")) {
70+
selected_device = provider_options.at("device_type");
71+
std::erase(selected_device, ' ');
72+
if (selected_device == "AUTO") return selected_device;
73+
74+
if (auto delimit = selected_device.find(":"); delimit != std::string::npos) {
75+
device_mode = selected_device.substr(0, delimit);
76+
if (supported_device_modes.contains(device_mode)) {
77+
const auto& devices = selected_device.substr(delimit + 1);
78+
devices_to_check = split(devices, ',');
79+
ORT_ENFORCE(devices_to_check.size() > 0, "Modes should have devices listed based on priority");
80+
} else {
81+
ORT_THROW("[ERROR] [OpenVINO] Invalid device_type is selected. Supported modes are AUTO/HETERO/MULTI");
82+
}
7883
} else {
7984
devices_to_check.push_back(selected_device);
8085
}
@@ -102,9 +107,18 @@ std::string ParseDeviceType(std::shared_ptr<OVCore> ov_core, const ProviderOptio
102107
#endif
103108
}
104109

105-
// Devices considered to be supported by default
106-
std::unordered_set<std::string> supported_device_types = {"CPU", "GPU", "NPU"};
110+
// Get the LUID passed from the provider option in a comma separated string list
111+
// Compare each of the LUID's against the LUID obtained using ov property and map with the right device
112+
if (provider_options.contains("device_luid")) {
113+
std::string luid_str = provider_options.at("device_luid");
114+
std::erase(luid_str, ' ');
115+
luid_list = split(luid_str, ',');
116+
}
117+
118+
bool all_devices_found = true;
119+
107120
for (auto device : devices_to_check) {
121+
bool device_found = false;
108122
// Check deprecated device format (CPU_FP32, GPU.0_FP16, etc.) and remove the suffix in place
109123
// Suffix will be parsed in ParsePrecision
110124
if (auto delimit = device.find("_"); delimit != std::string::npos) {
@@ -113,26 +127,57 @@ std::string ParseDeviceType(std::shared_ptr<OVCore> ov_core, const ProviderOptio
113127
// Just the device name without .0, .1, etc. suffix
114128
auto device_prefix = device;
115129
// Check if device index is appended (.0, .1, etc.), if so, remove it
116-
if (auto delimit = device_prefix.find("."); delimit != std::string::npos) {
130+
if (auto delimit = device_prefix.find("."); delimit != std::string::npos)
117131
device_prefix = device_prefix.substr(0, delimit);
118-
if (device_prefix == "CPU")
119-
ORT_THROW("[ERROR] [OpenVINO] CPU device is only supported without index, CPU.x is illegal.\n");
132+
if (supported_device_types.contains(device_prefix)) {
133+
try {
134+
std::vector<std::string> available_devices = ov_core->GetAvailableDevices(device_prefix);
135+
// Here we need to find the full device name (with .idx, but without _precision)
136+
if (std::find(std::begin(available_devices), std::end(available_devices), device) != std::end(available_devices))
137+
device_found = true;
138+
if (device_prefix != "CPU" && luid_list.size() > 0) {
139+
for (auto dev : available_devices) {
140+
ov::device::LUID ov_luid = OVCore::Get()->core.get_property(dev, ov::device::luid);
141+
std::stringstream ov_luid_str;
142+
ov_luid_str << ov_luid;
143+
ov_luid_map.emplace(ov_luid_str.str(), dev);
144+
}
145+
}
146+
} catch (const char* msg) {
147+
ORT_THROW(msg);
148+
}
120149
}
121-
// Only device is not supported by default (some exotic device), check if it's available
122-
if (!supported_device_types.contains(device_prefix)) {
123-
std::vector<std::string> available_devices = ov_core->GetAvailableDevices();
124-
// Here we need to find the full device name (with .idx, but without _precision)
125-
if (std::find(std::begin(available_devices), std::end(available_devices), device) == std::end(available_devices)) {
126-
ORT_THROW(
127-
"[ERROR] [OpenVINO] You have selected wrong configuration value for the key 'device_type'. "
128-
"Select from 'CPU', 'GPU', 'NPU', 'GPU.x' where x = 0,1,2 and so on or from"
129-
" HETERO/MULTI/AUTO/BATCH options available. \n");
150+
all_devices_found = all_devices_found && device_found;
151+
}
152+
if (luid_list.size() > 0) {
153+
std::string ov_luid_devices;
154+
for (auto luid_str : luid_list) {
155+
if (ov_luid_map.contains(luid_str)) {
156+
if (!ov_luid_devices.empty()) ov_luid_devices = ov_luid_devices + ",";
157+
ov_luid_devices = ov_luid_devices + ov_luid_map.at(luid_str);
158+
} else {
159+
ORT_THROW("Invalid device_luid is set");
160+
}
161+
}
162+
if (!device_mode.empty()) {
163+
selected_device = device_mode + ":" + ov_luid_devices;
164+
for (auto dev_str : devices_to_check) {
165+
auto default_dev = split(dev_str, '.')[0];
166+
if (ov_luid_devices.find(default_dev) == std::string::npos)
167+
selected_device = selected_device + "," + dev_str;
130168
}
169+
} else {
170+
selected_device = ov_luid_devices;
131171
}
132172
}
133-
// All devices have passed the check, return selected device
134-
LOGS_DEFAULT(INFO) << "[OpenVINO-EP] Choosing Device: " << selected_device;
135-
return selected_device;
173+
// If invalid device is chosen error is thrown
174+
if (!all_devices_found)
175+
ORT_THROW(
176+
"[ERROR] [OpenVINO] You have selected wrong configuration value for the key 'device_type'. "
177+
"Select from 'CPU', 'GPU', 'NPU', 'GPU.x' where x = 0,1,2 and so on or from"
178+
" HETERO/MULTI/AUTO/BATCH options available. \n");
179+
else
180+
return selected_device;
136181
}
137182

138183
void ParseProviderOptions([[maybe_unused]] ProviderInfo& result, [[maybe_unused]] const ProviderOptions& config_options) {}
@@ -175,12 +220,22 @@ struct OpenVINO_Provider : Provider {
175220
ProviderInfo pi;
176221
pi.config_options = config_options;
177222

223+
// Lambda function to check for invalid keys and throw an error
224+
auto validateKeys = [&]() {
225+
for (const auto& pair : provider_options) {
226+
if (pi.valid_provider_keys.find(pair.first) == pi.valid_provider_keys.end()) {
227+
ORT_THROW("Invalid provider_option key: " + pair.first);
228+
}
229+
}
230+
};
231+
validateKeys();
232+
178233
std::string bool_flag = "";
179234

180235
// Minor optimization: we'll hold an OVCore reference to ensure we don't create a new core between ParseDeviceType and
181236
// (potential) SharedContext creation.
182237
auto ov_core = OVCore::Get();
183-
pi.device_type = ParseDeviceType(ov_core, provider_options, "device_type");
238+
pi.device_type = ParseDeviceType(ov_core, provider_options);
184239

185240
if (provider_options.contains("device_id")) {
186241
std::string dev_id = provider_options.at("device_id").data();
@@ -303,12 +358,15 @@ struct OpenVINO_Provider : Provider {
303358
<< "Executing with num_streams=1";
304359
}
305360
}
306-
pi.enable_opencl_throttling = ParseBooleanOption(provider_options, "enable_opencl_throttling");
361+
try {
362+
pi.enable_opencl_throttling = ParseBooleanOption(provider_options, "enable_opencl_throttling");
307363

308-
pi.enable_qdq_optimizer = ParseBooleanOption(provider_options, "enable_qdq_optimizer");
309-
310-
pi.disable_dynamic_shapes = ParseBooleanOption(provider_options, "disable_dynamic_shapes");
364+
pi.enable_qdq_optimizer = ParseBooleanOption(provider_options, "enable_qdq_optimizer");
311365

366+
pi.disable_dynamic_shapes = ParseBooleanOption(provider_options, "disable_dynamic_shapes");
367+
} catch (std::string msg) {
368+
ORT_THROW(msg);
369+
}
312370
// Always true for NPU plugin or when passed .
313371
if (pi.device_type.find("NPU") != std::string::npos) {
314372
pi.disable_dynamic_shapes = true;

onnxruntime/core/providers/openvino/ov_interface.cc

+11-5
Original file line numberDiff line numberDiff line change
@@ -178,25 +178,31 @@ std::vector<std::string> OVCore::GetAvailableDevices(const std::string& device_t
178178
} catch (const ov::Exception&) {
179179
// plugin is not created by e.g. invalid env
180180
// Empty device list will be returned
181-
} catch (const std::runtime_error&) {
181+
} catch (const std::runtime_error& ex) {
182182
// plugin is not created by e.g. invalid env
183183
// Empty device list will be returned
184+
ORT_THROW("[ERROR] [OpenVINO] An exception occurred while trying to create the ",
185+
device_type,
186+
" device: ",
187+
ex.what());
184188
} catch (const std::exception& ex) {
185-
ORT_THROW("[ERROR] [OpenVINO] An exception is thrown while trying to create the ",
189+
ORT_THROW("[ERROR] [OpenVINO] An exception occurred while trying to create the ",
186190
device_type,
187191
" device: ",
188192
ex.what());
189193
} catch (...) {
190-
ORT_THROW("[ERROR] [OpenVINO] Unknown exception is thrown while trying to create the ",
194+
ORT_THROW("[ERROR] [OpenVINO] Unknown exception occurred while trying to create the ",
191195
device_type,
192196
" device");
193197
}
194198

195-
if (devicesIDs.size() > 1) {
199+
if (devicesIDs.size() > 1 ||
200+
(devicesIDs.size() == 1 && devicesIDs[0] == "0")) {
196201
for (const auto& deviceID : devicesIDs) {
197202
available_devices.push_back(device_type + '.' + deviceID);
198203
}
199-
} else if (!devicesIDs.empty()) {
204+
}
205+
if (!devicesIDs.empty()) {
200206
available_devices.push_back(device_type);
201207
}
202208

onnxruntime/core/providers/openvino/qdq_transformations/qdq_stripping.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ static bool CheckQRuleSet(const NodeUnit& node_unit,
386386
} else if (op_type == "Add") {
387387
// Add keeps all Qs
388388
return true;
389-
} else {
389+
} else {
390390
// Keep Q of an unsupported Op only if the target that succeeds it is a supported Op in this list
391391
return IsNextTargetNodeOfQValid(q_node, &target_node, src_graph, {"Conv", "Add", "MatMul"}, false);
392392
}

onnxruntime/test/perftest/ort_test_session.cc

+5-3
Original file line numberDiff line numberDiff line change
@@ -680,11 +680,11 @@ select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)");
680680
ov_options[key] = value;
681681
} else if (deprecated_device_types.find(value) != deprecated_device_types.end()) {
682682
ov_options[key] = value;
683-
} else if (value.find("HETERO:") == 0) {
683+
} else if (value.find("HETERO") == 0) {
684684
ov_options[key] = value;
685-
} else if (value.find("MULTI:") == 0) {
685+
} else if (value.find("MULTI") == 0) {
686686
ov_options[key] = value;
687-
} else if (value.find("AUTO:") == 0) {
687+
} else if (value.find("AUTO") == 0) {
688688
ov_options[key] = value;
689689
} else {
690690
ORT_THROW(
@@ -792,6 +792,8 @@ select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)");
792792
}
793793
} else if (key == "device_memory_name") {
794794
device_memory_name_ = std::move(value);
795+
} else if (key == "device_luid") {
796+
ov_options[key] = value;
795797
} else {
796798
ORT_THROW(
797799
"[ERROR] [OpenVINO] wrong key type entered. Choose from the following runtime key options that are available for OpenVINO."

0 commit comments

Comments
 (0)