Skip to content

Commit b0f08cd

Browse files
committed
fix: refactor plugin code
1 parent caf528a commit b0f08cd

File tree

3 files changed

+350
-143
lines changed

3 files changed

+350
-143
lines changed

onnxruntime/core/providers/openvino/openvino_provider_factory.cc

Lines changed: 23 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#include <cctype>
66
#include <map>
77
#include <set>
8-
#include <sstream>
98

109
#include <utility>
1110
#include "core/providers/shared_library/provider_api.h"
@@ -20,7 +19,6 @@
2019

2120
namespace onnxruntime {
2221
namespace openvino_ep {
23-
2422
void ParseConfigOptions(ProviderInfo& pi) {
2523
if (pi.config_options == nullptr)
2624
return;
@@ -380,7 +378,7 @@ struct OpenVINOProviderFactory : IExecutionProviderFactory {
380378
// The implementation of the SessionOptionsAppendExecutionProvider C API function automatically adds EP options to
381379
// the session option configurations with the key prefix "ep.<lowercase_ep_name>.".
382380
// Extract those EP options into a new "provider_options" map.
383-
std::string lowercase_ep_name = "OpenVINOExecutionProvider";
381+
std::string lowercase_ep_name = kOpenVINOExecutionProvider;
384382
std::transform(lowercase_ep_name.begin(), lowercase_ep_name.end(), lowercase_ep_name.begin(), [](unsigned char c) {
385383
return static_cast<char>(std::tolower(c));
386384
});
@@ -436,7 +434,7 @@ struct OpenVINO_Provider : Provider {
436434
}
437435

438436
Status CreateIExecutionProvider(const OrtHardwareDevice* const* /*devices*/,
439-
const OrtKeyValuePairs* const* /*ep_metadata*/,
437+
const OrtKeyValuePairs* const* ep_metadata,
440438
size_t num_devices,
441439
ProviderOptions& provider_options,
442440
const OrtSessionOptions& session_options,
@@ -445,12 +443,27 @@ struct OpenVINO_Provider : Provider {
445443
if (num_devices != 1) {
446444
return Status(common::ONNXRUNTIME, ORT_EP_FAIL, "OpenVINO EP only supports one device.");
447445
}
448-
std::array<const void*, 2> params{
449-
&provider_options,
450-
&session_options.GetConfigOptions(),
451-
};
452-
auto ep_factory = CreateExecutionProviderFactory(&params);
453-
ep = ep_factory->CreateProvider(session_options, logger);
446+
447+
ProviderInfo pi;
448+
const auto& config_options = session_options.GetConfigOptions();
449+
ParseProviderInfo(provider_options, &config_options, pi);
450+
451+
const auto& device_meta_data = ep_metadata[0];
452+
auto it = device_meta_data->Entries().find("ov_device");
453+
if (it == device_meta_data->Entries().end()) {
454+
return Status(common::ONNXRUNTIME, ORT_INVALID_ARGUMENT, "OpenVINO EP device metadata not found.");
455+
}
456+
pi.device_type = it->second;
457+
458+
/*
459+
TODO: This is where we need to perform some checking / manupulation of the session_options before
460+
they are passed into CreateProviders() below.
461+
Note: pi.device_type is getting set above, but I *think* it will just get overridden by the
462+
ParseConfigOptions() that will be done inside of CreateProvider();
463+
*/
464+
465+
auto factory = std::make_unique<OpenVINOProviderFactory>(pi, SharedContext::Get());
466+
ep = factory->CreateProvider(session_options, logger);
454467
return Status::OK();
455468
}
456469

@@ -464,106 +477,6 @@ struct OpenVINO_Provider : Provider {
464477
ProviderInfo_OpenVINO_Impl info_;
465478
}; // OpenVINO_Provider
466479

467-
// OrtEpApi infrastructure to be able to use the OpenVINO EP as an OrtEpFactory for auto EP selection.
468-
struct OpenVINOEpFactory : OrtEpFactory {
469-
OpenVINOEpFactory(const OrtApi& ort_api_in)
470-
: ort_api{ort_api_in} {
471-
GetName = GetNameImpl;
472-
GetVendor = GetVendorImpl;
473-
GetSupportedDevices = GetSupportedDevicesImpl;
474-
CreateEp = CreateEpImpl;
475-
ReleaseEp = ReleaseEpImpl;
476-
}
477-
478-
static const char* GetNameImpl(const OrtEpFactory*) noexcept {
479-
return ep_name;
480-
}
481-
482-
static const char* GetVendorImpl(const OrtEpFactory*) noexcept {
483-
return vendor;
484-
}
485-
486-
static OrtStatus* GetSupportedDevicesImpl(OrtEpFactory* ep_factory,
487-
const OrtHardwareDevice* const* devices,
488-
size_t num_devices,
489-
OrtEpDevice** ep_devices,
490-
size_t max_ep_devices,
491-
size_t* num_ep_devices) noexcept {
492-
if (!ep_factory || !devices || !ep_devices || !num_ep_devices) {
493-
return nullptr;
494-
}
495-
496-
*num_ep_devices = 0;
497-
const OpenVINOEpFactory* factory = static_cast<const OpenVINOEpFactory*>(ep_factory);
498-
499-
// Simple device discovery and EP device creation
500-
for (size_t i = 0; i < num_devices && *num_ep_devices < max_ep_devices; ++i) {
501-
const std::uint32_t vendorId = factory->ort_api.HardwareDevice_VendorId(devices[i]);
502-
const char* vendorName = factory->ort_api.HardwareDevice_Vendor(devices[i]);
503-
504-
// Check if this is an Intel device
505-
if ((vendorId == intel_vendor_id) ||
506-
(vendorName && std::string(vendorName).find("Intel") != std::string::npos)) {
507-
508-
const auto device_type = factory->ort_api.HardwareDevice_Type(devices[i]);
509-
510-
// Map device type to OpenVINO string
511-
const char* device_type_str = nullptr;
512-
switch (device_type) {
513-
case OrtHardwareDeviceType_CPU: device_type_str = "CPU"; break;
514-
case OrtHardwareDeviceType_GPU: device_type_str = "GPU"; break;
515-
case OrtHardwareDeviceType_NPU: device_type_str = "NPU"; break;
516-
default: continue; // Skip unknown device types
517-
}
518-
519-
// Create EP options
520-
OrtKeyValuePairs* ep_options = nullptr;
521-
factory->ort_api.CreateKeyValuePairs(&ep_options);
522-
factory->ort_api.AddKeyValuePair(ep_options, "device_type", device_type_str);
523-
524-
// Create EP device
525-
OrtEpDevice* ep_device = nullptr;
526-
OrtStatus* status = factory->ort_api.GetEpApi()->CreateEpDevice(
527-
ep_factory, devices[i], nullptr, ep_options, &ep_device);
528-
529-
factory->ort_api.ReleaseKeyValuePairs(ep_options);
530-
531-
if (status == nullptr) {
532-
ep_devices[(*num_ep_devices)++] = ep_device;
533-
} else {
534-
return status;
535-
}
536-
}
537-
}
538-
539-
return nullptr;
540-
}
541-
542-
static OrtStatus* CreateEpImpl(OrtEpFactory* ep_factory,
543-
const OrtHardwareDevice* const* devices,
544-
const OrtKeyValuePairs* const* ep_metadata_pairs,
545-
size_t num_devices,
546-
const OrtSessionOptions* session_options,
547-
const OrtLogger* logger,
548-
OrtEp** ep) noexcept {
549-
if (!ep_factory || !ep) {
550-
return nullptr;
551-
}
552-
const OpenVINOEpFactory* factory = static_cast<const OpenVINOEpFactory*>(ep_factory);
553-
return factory->ort_api.CreateStatus(ORT_INVALID_ARGUMENT, "OpenVINO EP factory does not support this method.");
554-
}
555-
556-
static void ReleaseEpImpl(OrtEpFactory*, OrtEp*) noexcept {
557-
// no-op as we never create an EP here.
558-
}
559-
560-
const OrtApi& ort_api;
561-
// Intel vendor ID. Refer to the ACPI ID registry (search Intel): https://uefi.org/ACPI_ID_List
562-
static constexpr std::uint32_t intel_vendor_id{0x8086};
563-
static constexpr const char* const ep_name{kOpenVINOExecutionProvider};
564-
static constexpr const char* const vendor{"Intel Corporation"};
565-
};
566-
567480
} // namespace openvino_ep
568481
} // namespace onnxruntime
569482

@@ -573,37 +486,4 @@ ORT_API(onnxruntime::Provider*, GetProvider) {
573486
static onnxruntime::openvino_ep::OpenVINO_Provider g_provider;
574487
return &g_provider;
575488
}
576-
577-
OrtStatus* CreateEpFactories(const char* /*registration_name*/, const OrtApiBase* ort_api_base,
578-
OrtEpFactory** factories, size_t max_factories, size_t* num_factories) {
579-
if (!ort_api_base || !factories || !num_factories) {
580-
return nullptr;
581-
}
582-
583-
const OrtApi* ort_api = ort_api_base->GetApi(ORT_API_VERSION);
584-
if (!ort_api) {
585-
return nullptr;
586-
}
587-
588-
if (max_factories < 1) {
589-
return ort_api->CreateStatus(ORT_INVALID_ARGUMENT,
590-
"Not enough space to return EP factory. Need at least one.");
591-
}
592-
593-
try {
594-
factories[0] = new onnxruntime::openvino_ep::OpenVINOEpFactory(*ort_api);
595-
*num_factories = 1;
596-
return nullptr;
597-
} catch (...) {
598-
return ort_api->CreateStatus(ORT_FAIL, "Failed to create OpenVINO EP factory.");
599-
}
600-
}
601-
602-
OrtStatus* ReleaseEpFactory(OrtEpFactory* factory) {
603-
if (factory) {
604-
delete static_cast<onnxruntime::openvino_ep::OpenVINOEpFactory*>(factory);
605-
}
606-
return nullptr;
607-
}
608-
609489
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
// Copyright (C) Intel Corporation
2+
// Licensed under the MIT License
3+
4+
#include <memory>
5+
#include <map>
6+
#include <string>
7+
#include <algorithm>
8+
#include <vector>
9+
#include <ranges>
10+
#include <format>
11+
12+
#define ORT_API_MANUAL_INIT
13+
#include "onnxruntime_cxx_api.h"
14+
#undef ORT_API_MANUAL_INIT
15+
16+
#include "onnxruntime_c_api.h"
17+
#include "ov_factory.h"
18+
#include "openvino/openvino.hpp"
19+
#include "ov_interface.h"
20+
21+
using namespace onnxruntime::openvino_ep;
22+
using ov_core_singleton = onnxruntime::openvino_ep::WeakSingleton<ov::Core>;
23+
24+
static void InitCxxApi(const OrtApiBase& ort_api_base) {
25+
static std::once_flag init_api;
26+
std::call_once(init_api, [&]() {
27+
const OrtApi* ort_api = ort_api_base.GetApi(ORT_API_VERSION);
28+
Ort::InitApi(ort_api);
29+
});
30+
}
31+
32+
OpenVINOEpPluginFactory::OpenVINOEpPluginFactory(ApiPtrs apis, const std::string& ov_metadevice_name, std::shared_ptr<ov::Core> core)
33+
: ApiPtrs{apis},
34+
ep_name_(ov_metadevice_name.empty() ? provider_name_ : std::string(provider_name_) + "." + ov_metadevice_name),
35+
device_type_(ov_metadevice_name),
36+
ov_core_(std::move(core)) {
37+
OrtEpFactory::GetName = GetNameImpl;
38+
OrtEpFactory::GetVendor = GetVendorImpl;
39+
OrtEpFactory::GetVendorId = GetVendorIdImpl;
40+
OrtEpFactory::GetSupportedDevices = GetSupportedDevicesImpl;
41+
OrtEpFactory::GetVersion = GetVersionImpl;
42+
ort_version_supported = ORT_API_VERSION; // Set to the ORT version we were compiled with.
43+
}
44+
45+
const std::vector<std::string>& OpenVINOEpPluginFactory::GetOvDevices() {
46+
static std::vector<std::string> devices = ov_core_singleton::Get()->get_available_devices();
47+
return devices;
48+
}
49+
50+
const std::vector<std::string>& OpenVINOEpPluginFactory::GetOvMetaDevices() {
51+
static std::vector<std::string> virtual_devices = [ov_core = ov_core_singleton::Get()] {
52+
std::vector<std::string> supported_virtual_devices{};
53+
for (const auto& meta_device : known_meta_devices_) {
54+
try {
55+
ov_core->get_property(meta_device, ov::supported_properties);
56+
supported_virtual_devices.push_back(meta_device);
57+
} catch (ov::Exception&) {
58+
// meta device isn't supported.
59+
}
60+
}
61+
return supported_virtual_devices;
62+
}();
63+
64+
return virtual_devices;
65+
}
66+
67+
OrtStatus* OpenVINOEpPluginFactory::GetSupportedDevices(const OrtHardwareDevice* const* devices,
68+
size_t num_devices,
69+
OrtEpDevice** ep_devices,
70+
size_t max_ep_devices,
71+
size_t* p_num_ep_devices) {
72+
size_t& num_ep_devices = *p_num_ep_devices;
73+
74+
// Create a map for device type mapping
75+
static const std::map<OrtHardwareDeviceType, std::string> ort_to_ov_device_name = {
76+
{OrtHardwareDeviceType::OrtHardwareDeviceType_CPU, "CPU"},
77+
{OrtHardwareDeviceType::OrtHardwareDeviceType_GPU, "GPU"},
78+
{OrtHardwareDeviceType::OrtHardwareDeviceType_NPU, "NPU"},
79+
};
80+
81+
for (size_t i = 0; i < num_devices && num_ep_devices < max_ep_devices; ++i) {
82+
const OrtHardwareDevice& device = *devices[i];
83+
if (ort_api.HardwareDevice_VendorId(&device) != vendor_id_) {
84+
// Not an Intel Device.
85+
continue;
86+
}
87+
88+
auto device_type = ort_api.HardwareDevice_Type(&device);
89+
auto device_it = ort_to_ov_device_name.find(device_type);
90+
if (device_it == ort_to_ov_device_name.end()) {
91+
// We don't know about this device type
92+
continue;
93+
}
94+
95+
const auto& ov_device_type = device_it->second;
96+
std::string ov_device_name;
97+
auto get_pci_device_id = [&](const std::string& ov_device) {
98+
try {
99+
ov::device::PCIInfo pci_info = ov_core_->get_property(ov_device, ov::device::pci_info);
100+
return pci_info.device;
101+
} catch (ov::Exception&) {
102+
return 0u; // If we can't get the PCI info, we won't have a device ID.
103+
}
104+
};
105+
106+
auto filtered_devices = GetOvDevices(ov_device_type);
107+
auto matched_device = filtered_devices.begin();
108+
if (filtered_devices.size() > 1 && device_type == OrtHardwareDeviceType::OrtHardwareDeviceType_GPU) {
109+
// If there are multiple devices of the same type, we need to match by device ID.
110+
matched_device = std::find_if(filtered_devices.begin(), filtered_devices.end(), [&](const std::string& ov_device) {
111+
uint32_t ort_device_id = ort_api.HardwareDevice_DeviceId(&device);
112+
return ort_device_id == get_pci_device_id(ov_device);
113+
});
114+
}
115+
116+
if (matched_device == filtered_devices.end()) {
117+
// We didn't find a matching OpenVINO device for the OrtHardwareDevice.
118+
continue;
119+
}
120+
121+
// these can be returned as nullptr if you have nothing to add.
122+
OrtKeyValuePairs* ep_metadata = nullptr;
123+
OrtKeyValuePairs* ep_options = nullptr;
124+
ort_api.CreateKeyValuePairs(&ep_metadata);
125+
ort_api.AddKeyValuePair(ep_metadata, ov_device_key_, matched_device->c_str());
126+
127+
// Create EP device
128+
auto* status = ort_api.GetEpApi()->CreateEpDevice(this, &device, ep_metadata, ep_options,
129+
&ep_devices[num_ep_devices++]);
130+
131+
ort_api.ReleaseKeyValuePairs(ep_metadata);
132+
ort_api.ReleaseKeyValuePairs(ep_options);
133+
134+
if (status != nullptr) {
135+
return status;
136+
}
137+
}
138+
139+
return nullptr;
140+
}
141+
142+
extern "C" {
143+
//
144+
// Public symbols
145+
//
146+
OrtStatus* CreateEpFactories(const char* /*registration_name*/, const OrtApiBase* ort_api_base,
147+
OrtEpFactory** factories, size_t max_factories, size_t* num_factories) {
148+
InitCxxApi(*ort_api_base);
149+
const ApiPtrs api_ptrs{Ort::GetApi(), Ort::GetEpApi(), Ort::GetModelEditorApi()};
150+
151+
// Get available devices from OpenVINO
152+
auto ov_core = ov_core_singleton::Get();
153+
std::vector<std::string> supported_factories = {""};
154+
const auto& meta_devices = OpenVINOEpPluginFactory::GetOvMetaDevices();
155+
supported_factories.insert(supported_factories.end(), meta_devices.begin(), meta_devices.end());
156+
157+
const size_t required_factories = supported_factories.size();
158+
if (max_factories < required_factories) {
159+
return Ort::Status(std::format("Not enough space to return EP factories. Need at least {} factories.", required_factories).c_str(), ORT_INVALID_ARGUMENT);
160+
}
161+
162+
size_t factory_index = 0;
163+
for (const auto& device_name : supported_factories) {
164+
// Create a factory for this specific device
165+
factories[factory_index++] = new OpenVINOEpPluginFactory(api_ptrs, device_name, ov_core);
166+
}
167+
168+
*num_factories = factory_index;
169+
return nullptr;
170+
}
171+
172+
OrtStatus* ReleaseEpFactory(OrtEpFactory* factory) {
173+
delete static_cast<OpenVINOEpPluginFactory*>(factory);
174+
return nullptr;
175+
}
176+
}

0 commit comments

Comments
 (0)