Repository navigation
Avoid double initialization when registering plugin EP libraries - #33701
Conversation
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Co-authored-by: tianleiwu <30328909+tianleiwu@users.noreply.github.com>
Co-authored-by: tianleiwu <30328909+tianleiwu@users.noreply.github.com>
Co-authored-by: tianleiwu <30328909+tianleiwu@users.noreply.github.com>
Tianlei Wu (tianleiwu)
left a comment
There was a problem hiding this comment.
Verdict: COMMENT — the fix is correct and verified on Linux (the double load/unload reproduces on main and is gone with this PR). The findings below are non-blocking suggestions. The Windows CI legs should confirm the original report (#33603).
What I verified (Linux x86-64, AMD EPYC 7V12, GCC 13.2, Release; built together with #33700, whose files are disjoint)
- PR head:
optional_provider_probe_test7/7 passed in both the regular and theno_exceptionsvariants (the 3 new tests ran, none skipped);onnxruntime_autoep_test123/123 passed. mainproduction code + this PR's tests:PluginRegistrationInitializesOnceAndUnregisterUnloadsfails (event history_LUL...where_Lis expected, i.e. load / unload / load per registration) andFailedPluginLoadUnloadsRetainedProbefails (_LULUvs_LU). The 4 pre-existing probe tests pass on both.RetainedPluginProbeCanRetryWithoutLeakingReferencescalls the newLoad(bool)overload, so it cannot be built againstmain.
| # | Severity | Where | Issue |
|---|---|---|---|
| 1 | Suggestion | provider_bridge_library.h (inline) |
Load(true) can fail and leave the DLL loaded, moving the Unload() obligation to the caller while the destructor never unloads; document it or replace the bare bool with an enum / named probe API |
| 2 | Suggestion | optional_provider_probe_test_library.cc (inline) |
The tests rely on dlclose / FreeLibrary running the fixture's static destructor synchronously; state the invariant next to the tracker (nit: the Windows event log stops recording at 63 characters) |
| 3 | Nitpick | PR description | No validation evidence, and the checklist items are unchecked |
The control flow is correct on every path I traced: the gsl::finally guard in utils.cc drops the probe's reference on the plugin path (refcount 2 to 1 after EpLibraryPlugin::Load()), on plugin load failure (back to 0, so the retained library cannot leak) and on exceptions, and it is a no-op on the provider-bridge path where the library is moved into EpLibraryProviderBridge.
Not run: Windows (where #33603 was reported; the Linux fixture reproduces the same load/unload/load mechanism through dlopen reference counts), macOS, and the wider shared-lib test suite.
Document retained-load failure ownership and synchronous fixture unload requirements. Preserve Windows histories beyond 63 characters, diagnose environment-recording failures, and cover 128-character histories during repeated plugin registration/unload. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are reported for the plugin execution-provider registration lifecycle changes.
No open issues 🎉
What changed in this PR
Addresses #33603 by avoiding an unnecessary unload/reload cycle during plugin execution-provider registration, while preserving provider-bridge initialization order and unloading on unregistration.
Changes:
- Retains the probe’s library reference until the plugin loader acquires its own.
- Releases probe references on success or failure and reuses retained handles on retries.
- Adds lifecycle fixtures and regression tests for initialization, repeated registration, failed loads, and retries.
| File | Description |
|---|---|
onnxruntime/test/shared_lib/optional_provider_probe_test.cc |
Adds registration, cleanup, and retry lifecycle tests. |
onnxruntime/test/shared_lib/optional_provider_probe_test_library.cc |
Adds plugin fixtures with load/unload tracking and failure scenarios. |
onnxruntime/core/session/utils.cc |
Retains the probe reference through plugin loading and ensures cleanup. |
onnxruntime/core/session/provider_bridge_ort.cc |
Supports retaining libraries without GetProvider and reusing retained handles. |
onnxruntime/core/session/provider_bridge_library.h |
Declares the retention option and documents caller cleanup responsibilities. |
cmake/onnxruntime_unittests.cmake |
Builds and stages the new plugin fixtures for probe tests. |
Review effort: Balanced
Keep plugin fixtures independent of runtime/ONNX globals and give each fixture type a distinct load path. This prevents a provider image retained by Darwin or the ASan loader from satisfying a later plugin probe, while preserving synchronous registration/unload and retained-failure coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Description
GetProvideris absent until the plugin loader acquires its own reference. Preserve provider-bridge dependency initialization order.Motivation and Context
RegisterExecutionProviderLibraryunloads non-bridge plugin EPs after probing forGetProvider, then immediately reloads them. This repeats initialization and teardown of the EP DLL and its dependencies, adding an unnecessary DLL lifecycle to registration latency.