Skip to content

Commit 10afbef

Browse files
BoarQingYueqing Zhang
andauthored
[VitisAI] Add External EP Loader (#26627)
## [VitisAI] Add External EP Loader ### Description This PR introduces a dynamic external execution provider loading mechanism for the VitisAI execution provider, enabling runtime loading of alternative execution providers through a plugin-style architecture. ### Key Changes #### 1. **New External EP Library Infrastructure** (`global_api.cc`) - Added `ExternalEpLibaray` class to dynamically load external execution provider libraries at runtime - Implemented complete library lifecycle management (loading, unloading, symbol resolution) - Added global registry (`g_external_ep_libaries`) with caching to avoid redundant library loading - Created `CreateExecutionProviderFromAnotherEp()` function to instantiate execution providers from external libraries **Implementation Details:** - **Simplified symbol resolution**: Only resolves the essential `GetProvider` symbol (required) - **Removed optional symbols**: No longer attempts to resolve `CreateEpFactories` or `RyzenAI_SetSessionOptions` - Lazy initialization pattern with `Ensure()` method - Safe cleanup with `Clear()` method and proper error handling - Platform-agnostic library loading using `LIBRARY_PREFIX` and `LIBRARY_EXTENSION` macros #### 2. **API Extension** (`global_api.h`) - Declared new public function: `CreateExecutionProviderFromAnotherEp()` - Added required includes: - `core/framework/execution_provider.h` for `IExecutionProvider` interface - `<memory>` for smart pointer support #### 3. **Factory Integration** (`vitisai_provider_factory.cc`) - Integrated external EP loading into the VitisAI provider factory workflow - Added provider option check for `external_ep_libray` key - **Logic Flow**: 1. Check if `external_ep_libray` option is specified 2. If yes, load and return the external execution provider 3. If no, create and return standard VitisAI execution provider Co-authored-by: Yueqing Zhang <[email protected]>
1 parent 66c9f1c commit 10afbef

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

onnxruntime/core/providers/vitisai/imp/global_api.cc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,3 +611,53 @@ vaip_core::OrtApiForVaip* create_org_api_hook() {
611611
return &the_global_api;
612612
}
613613
}
614+
615+
struct ExternalEpLibaray {
616+
ExternalEpLibaray(const std::string& libray_name) : libray_name_{libray_name} {
617+
Ensure();
618+
}
619+
onnxruntime::Provider* (*get_provider_api)();
620+
void (*create_ep_factories)(void*, const OrtApiBase*, void*, OrtEpFactory**, size_t, size_t*);
621+
void (*set_session_option)(OrtSessionOptions*);
622+
623+
void Ensure() {
624+
if (handle_)
625+
return;
626+
auto& env = Provider_GetHost()->Env__Default();
627+
auto library_filename = PathString(LIBRARY_PREFIX) + PathString(libray_name_.begin(), libray_name_.end()) + LIBRARY_EXTENSION;
628+
auto full_path = env.GetRuntimePath() + library_filename;
629+
ORT_THROW_IF_ERROR(env.LoadDynamicLibrary(full_path, true, &handle_));
630+
ORT_THROW_IF_ERROR(env.GetSymbolFromLibrary(handle_, "GetProvider", (void**)&get_provider_api));
631+
}
632+
633+
void Clear() {
634+
if (handle_) {
635+
auto& env = Provider_GetHost()->Env__Default();
636+
auto status = env.UnloadDynamicLibrary(handle_);
637+
vai_assert(status.IsOK(), status.ErrorMessage());
638+
handle_ = nullptr;
639+
}
640+
}
641+
642+
private:
643+
std::string libray_name_;
644+
void* handle_{};
645+
};
646+
static std::unordered_map<std::string, std::unique_ptr<ExternalEpLibaray>> g_external_ep_libaries;
647+
648+
std::unique_ptr<onnxruntime::IExecutionProvider>
649+
CreateExecutionProviderFromAnotherEp(const std::string& lib, const OrtSessionOptions& session_options,
650+
std::unordered_map<std::string, std::string>& provider_options) {
651+
auto it = g_external_ep_libaries.find(lib);
652+
if (it == g_external_ep_libaries.end()) {
653+
it = g_external_ep_libaries.emplace(lib, std::make_unique<ExternalEpLibaray>(lib)).first;
654+
}
655+
auto ep_lib = it->second.get();
656+
auto get_provider_func = ep_lib->get_provider_api;
657+
auto provider = get_provider_func();
658+
std::unique_ptr<onnxruntime::IExecutionProvider> ret;
659+
provider->Initialize();
660+
std::ignore = provider->CreateIExecutionProvider(nullptr, nullptr, 0, const_cast<onnxruntime::ProviderOptions&>(provider_options), session_options, *((OrtLogger*)nullptr), ret);
661+
662+
return ret;
663+
}

onnxruntime/core/providers/vitisai/include/vaip/global_api.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
#define ORT_API_MANUAL_INIT
77
#include "core/session/onnxruntime_cxx_api.h"
88
#include "core/framework/provider_options.h"
9+
#include "core/framework/execution_provider.h"
910
#include "vaip/my_ort.h"
1011
#include "vaip/dll_safe.h"
1112
#include "vaip/custom_op.h"
1213
#include <optional>
14+
#include <memory>
1315
void initialize_vitisai_ep();
1416
void deinitialize_vitisai_ep();
1517
vaip_core::DllSafe<std::vector<std::unique_ptr<vaip_core::ExecutionProvider>>> compile_onnx_model(const onnxruntime::GraphViewer& graph_viewer, const onnxruntime::logging::Logger& logger, const onnxruntime::ProviderOptions& options);
@@ -40,3 +42,6 @@ using EventInfo = std::tuple<
4042
void profiler_collect(
4143
std::vector<EventInfo>& api_events,
4244
std::vector<EventInfo>& kernel_events);
45+
std::unique_ptr<onnxruntime::IExecutionProvider>
46+
CreateExecutionProviderFromAnotherEp(const std::string& lib, const OrtSessionOptions& session_options,
47+
std::unordered_map<std::string, std::string>& provider_options);

onnxruntime/core/providers/vitisai/vitisai_provider_factory.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include <cctype>
88
#include <unordered_map>
99
#include <string>
10-
1110
#include "vaip/global_api.h"
1211
#include "./vitisai_execution_provider.h"
1312
#include "core/framework/execution_provider.h"
@@ -57,6 +56,10 @@ std::unique_ptr<IExecutionProvider> VitisAIProviderFactory::CreateProvider(const
5756
}
5857
}
5958

59+
auto it = provider_options.find("external_ep_libray");
60+
if (it != provider_options.end()) {
61+
return CreateExecutionProviderFromAnotherEp(it->second, session_options, provider_options);
62+
}
6063
auto ep_instance = std::make_unique<VitisAIExecutionProvider>(provider_options);
6164
ep_instance->SetLogger(reinterpret_cast<const logging::Logger*>(&session_logger));
6265
return ep_instance;

0 commit comments

Comments
 (0)