diff --git a/include/onnxruntime/core/session/onnxruntime_ep_device_ep_metadata_keys.h b/include/onnxruntime/core/session/onnxruntime_ep_device_ep_metadata_keys.h index 672103bedc437..bbd6a43bb7a41 100644 --- a/include/onnxruntime/core/session/onnxruntime_ep_device_ep_metadata_keys.h +++ b/include/onnxruntime/core/session/onnxruntime_ep_device_ep_metadata_keys.h @@ -12,4 +12,7 @@ static const char* const kOrtEpDevice_EpMetadataKey_Version = "version"; // Prefix for execution provider compatibility information stored in model metadata. // Used when generating EP context models to store compatibility strings for each EP. // Full key format: "ep_compatibility_info." -static const char* const kOrtModelMetadata_EpCompatibilityInfoPrefix = "ep_compatibility_info."; \ No newline at end of file +static const char* const kOrtModelMetadata_EpCompatibilityInfoPrefix = "ep_compatibility_info."; + +// Key for the execution provider library path (for dynamically loaded EPs) +static const char* const kOrtEpDevice_EpMetadataKey_LibraryPath = "library_path"; diff --git a/onnxruntime/core/session/plugin_ep/ep_factory_provider_bridge.cc b/onnxruntime/core/session/plugin_ep/ep_factory_provider_bridge.cc index d6e51a44c1c69..42b65239de92c 100644 --- a/onnxruntime/core/session/plugin_ep/ep_factory_provider_bridge.cc +++ b/onnxruntime/core/session/plugin_ep/ep_factory_provider_bridge.cc @@ -4,6 +4,8 @@ #include "core/session/plugin_ep/ep_factory_provider_bridge.h" #include "core/providers/shared_library/provider_host_api.h" +#include "core/session/plugin_ep/ep_library_plugin.h" +#include "core/session/onnxruntime_ep_device_ep_metadata_keys.h" namespace onnxruntime { OrtStatus* ProviderBridgeEpFactory::GetSupportedDevices(EpFactoryInternal& ep_factory, @@ -20,6 +22,11 @@ OrtStatus* ProviderBridgeEpFactory::GetSupportedDevices(EpFactoryInternal& ep_fa auto* ep_device = ep_devices[i]; if (ep_device) { ep_device->ep_factory = &ep_factory; + + // Add library path to EP metadata if available + if (library_path_.has_value()) { + ep_device->ep_metadata.Add(kOrtEpDevice_EpMetadataKey_LibraryPath, library_path_->string()); + } } } diff --git a/onnxruntime/core/session/plugin_ep/ep_factory_provider_bridge.h b/onnxruntime/core/session/plugin_ep/ep_factory_provider_bridge.h index 437af62dc2c0c..8c5ef526baba1 100644 --- a/onnxruntime/core/session/plugin_ep/ep_factory_provider_bridge.h +++ b/onnxruntime/core/session/plugin_ep/ep_factory_provider_bridge.h @@ -3,6 +3,10 @@ #pragma once +#include +#include +#include + #include "core/framework/error_code_helper.h" #include "core/session/abi_devices.h" #include "core/session/abi_session_options_impl.h" @@ -12,12 +16,14 @@ namespace onnxruntime { class ProviderBridgeEpFactory : public EpFactoryInternalImpl { public: - ProviderBridgeEpFactory(OrtEpFactory& ep_factory, ProviderLibrary& provider_library) + ProviderBridgeEpFactory(OrtEpFactory& ep_factory, ProviderLibrary& provider_library, + std::optional library_path = std::nullopt) : EpFactoryInternalImpl(ep_factory.GetName(&ep_factory), ep_factory.GetVendor(&ep_factory), ep_factory.GetVendorId(&ep_factory)), ep_factory_{ep_factory}, - provider_library_{provider_library} { + provider_library_{provider_library}, + library_path_{std::move(library_path)} { } private: @@ -59,8 +65,9 @@ class ProviderBridgeEpFactory : public EpFactoryInternalImpl { return ep_factory_.CreateSyncStreamForDevice(&ep_factory_, device, stream_options, stream); } - OrtEpFactory& ep_factory_; // OrtEpFactory from the provider bridge EP - ProviderLibrary& provider_library_; // ProviderLibrary from the provider bridge EP + OrtEpFactory& ep_factory_; + ProviderLibrary& provider_library_; + std::optional library_path_; }; } // namespace onnxruntime diff --git a/onnxruntime/core/session/plugin_ep/ep_library.h b/onnxruntime/core/session/plugin_ep/ep_library.h index 24ab74e1c77fc..af5bc23143e33 100644 --- a/onnxruntime/core/session/plugin_ep/ep_library.h +++ b/onnxruntime/core/session/plugin_ep/ep_library.h @@ -23,6 +23,7 @@ class EpLibrary { virtual Status Load() { return Status::OK(); } virtual const std::vector& GetFactories() = 0; // valid after Load() virtual Status Unload() { return Status::OK(); } + virtual ~EpLibrary() = default; ORT_DISALLOW_COPY_AND_ASSIGNMENT(EpLibrary); diff --git a/onnxruntime/core/session/plugin_ep/ep_library_provider_bridge.cc b/onnxruntime/core/session/plugin_ep/ep_library_provider_bridge.cc index 06cf54aea4071..da94a9f12ba9d 100644 --- a/onnxruntime/core/session/plugin_ep/ep_library_provider_bridge.cc +++ b/onnxruntime/core/session/plugin_ep/ep_library_provider_bridge.cc @@ -4,6 +4,7 @@ #include "core/session/plugin_ep/ep_library_provider_bridge.h" #include "core/session/plugin_ep/ep_factory_provider_bridge.h" +#include "core/session/plugin_ep/ep_library_plugin.h" namespace onnxruntime { Status EpLibraryProviderBridge::Load() { @@ -26,8 +27,9 @@ Status EpLibraryProviderBridge::Load() { // to do this we need to capture `factory` and plug it in to is_supported_fn and create_fn. // we also need to update any returned OrtEpDevice instances to swap the wrapper EpFactoryInternal in so that we can // call Provider::CreateIExecutionProvider in EpFactoryInternal::CreateIExecutionProvider. + for (const auto& factory : ep_library_plugin_->GetFactories()) { - auto factory_impl = std::make_unique(*factory, *provider_library_); + auto factory_impl = std::make_unique(*factory, *provider_library_, library_path_); auto internal_factory = std::make_unique(std::move(factory_impl)); factory_ptrs_.push_back(internal_factory.get()); diff --git a/onnxruntime/core/session/plugin_ep/ep_library_provider_bridge.h b/onnxruntime/core/session/plugin_ep/ep_library_provider_bridge.h index c7e8ebefc3785..45277b2828f56 100644 --- a/onnxruntime/core/session/plugin_ep/ep_library_provider_bridge.h +++ b/onnxruntime/core/session/plugin_ep/ep_library_provider_bridge.h @@ -21,9 +21,11 @@ namespace onnxruntime { class EpLibraryProviderBridge : public EpLibrary { public: EpLibraryProviderBridge(std::unique_ptr provider_library, - std::unique_ptr ep_library_plugin) + std::unique_ptr ep_library_plugin, + std::optional library_path = std::nullopt) : provider_library_{std::move(provider_library)}, - ep_library_plugin_{std::move(ep_library_plugin)} { + ep_library_plugin_{std::move(ep_library_plugin)}, + library_path_{std::move(library_path)} { } const char* RegistrationName() const override { @@ -53,6 +55,9 @@ class EpLibraryProviderBridge : public EpLibrary { // implement EpFactoryInternal::CreateIExecutionProvider by calling Provider::CreateIExecutionProvider. std::unique_ptr ep_library_plugin_; + // Library path for EP metadata + std::optional library_path_; + std::vector> factories_; std::vector factory_ptrs_; // for convenience std::vector internal_factory_ptrs_; // for convenience diff --git a/onnxruntime/core/session/utils.cc b/onnxruntime/core/session/utils.cc index d4041dfce5a7a..7da7fabb15b15 100644 --- a/onnxruntime/core/session/utils.cc +++ b/onnxruntime/core/session/utils.cc @@ -421,13 +421,14 @@ Status LoadPluginOrProviderBridge(const std::string& registration_name, << (is_provider_bridge ? " as a provider bridge" : " as a plugin"); // create EpLibraryPlugin to ensure CreateEpFactories and ReleaseEpFactory are available - auto ep_library_plugin = std::make_unique(registration_name, std::move(resolved_library_path)); + auto ep_library_plugin = std::make_unique(registration_name, resolved_library_path); ORT_RETURN_IF_ERROR(ep_library_plugin->Load()); if (is_provider_bridge) { // wrap the EpLibraryPlugin with EpLibraryProviderBridge to add to directly create an IExecutionProvider auto ep_library_provider_bridge = std::make_unique(std::move(provider_library), - std::move(ep_library_plugin)); + std::move(ep_library_plugin), + resolved_library_path); ORT_RETURN_IF_ERROR(ep_library_provider_bridge->Load()); internal_factories = ep_library_provider_bridge->GetInternalFactories(); ep_library = std::move(ep_library_provider_bridge);