From 6d34481a82e6bee5cd144f98524cdc820d373902 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 17 Oct 2025 07:28:28 -0700 Subject: [PATCH 01/43] save work --- cmake/CMakeLists.txt | 22 ++++++++++++-- cmake/onnxruntime_session.cmake | 4 +++ cmake/onnxruntime_unittests.cmake | 5 ++-- onnxruntime/core/session/utils.cc | 10 ++++++- .../test/autoep/library/ep_stream_support.h | 4 +-- .../autoep/library/example_plugin_ep_utils.h | 11 +++---- tools/ci_build/build.py | 30 ++++++++++++------- 7 files changed, 61 insertions(+), 25 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 116d369885a27..1c94bd6e96bc7 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1650,9 +1650,25 @@ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") endif() endif() -#Now the 'onnxruntime_EXTERNAL_LIBRARIES' variable should be sealed. It will be used in onnxruntime.cmake which will be included in the next. -#The order of the following targets matters. Right depends on left. If target A appears before target B. Then A.cmake can not use variables defined in B.cmake. -set(ONNXRUNTIME_CMAKE_FILES onnxruntime_flatbuffers onnxruntime_common onnxruntime_mlas onnxruntime_graph onnxruntime_lora onnxruntime_framework onnxruntime_util onnxruntime_providers onnxruntime_optimizer onnxruntime_session ${ONNXRUNTIME_EAGER_CMAKE_FILE_NAME}) +# Now the 'onnxruntime_EXTERNAL_LIBRARIES' variable should be sealed. It will be used in onnxruntime.cmake which will +# be included next. + +# The order of the following CMake file names (which exclude the ".cmake" suffix) matters. Later CMake files may depend +# on earlier ones but earler ones cannot depend on later ones. For example, if A appears before B, then A.cmake cannot +# use variables defined in B.cmake. +set(ONNXRUNTIME_CMAKE_FILES + onnxruntime_flatbuffers + onnxruntime_common + onnxruntime_mlas + onnxruntime_graph + onnxruntime_lora + onnxruntime_framework + onnxruntime_util + onnxruntime_providers + onnxruntime_optimizer + onnxruntime_session + ${ONNXRUNTIME_EAGER_CMAKE_FILE_NAME} + ) if (onnxruntime_USE_WINML) # WINML uses and depends on the shared lib. Note: You can build WINML without DML and you will get a diff --git a/cmake/onnxruntime_session.cmake b/cmake/onnxruntime_session.cmake index f81a7a9726b76..59d4b7c4a71e8 100644 --- a/cmake/onnxruntime_session.cmake +++ b/cmake/onnxruntime_session.cmake @@ -45,6 +45,10 @@ if(onnxruntime_ENABLE_INSTRUMENT) target_compile_definitions(onnxruntime_session PUBLIC ONNXRUNTIME_ENABLE_INSTRUMENT) endif() +if(TARGET onnxruntime_providers_shared) + target_compile_definitions(onnxruntime_session PRIVATE ORT_PROVIDER_BRIDGE_IS_SUPPORTED) +endif() + if(NOT MSVC) set_source_files_properties(${ONNXRUNTIME_ROOT}/core/session/environment.cc PROPERTIES COMPILE_FLAGS "-Wno-parentheses") endif() diff --git a/cmake/onnxruntime_unittests.cmake b/cmake/onnxruntime_unittests.cmake index 460736ff8506e..91375d8235d6a 100644 --- a/cmake/onnxruntime_unittests.cmake +++ b/cmake/onnxruntime_unittests.cmake @@ -1978,8 +1978,7 @@ endif() # Build library that can be used with RegisterExecutionProviderLibrary and automatic EP selection # We need a shared lib build to use that as a dependency for the test library -# Currently we only have device discovery on Windows so no point building the test app on other platforms. -if (WIN32 AND onnxruntime_BUILD_SHARED_LIB AND +if (onnxruntime_BUILD_SHARED_LIB AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten" AND NOT onnxruntime_MINIMAL_BUILD) # example_plugin_ep @@ -1987,7 +1986,7 @@ if (WIN32 AND onnxruntime_BUILD_SHARED_LIB AND "${TEST_SRC_DIR}/autoep/library/*.cc") onnxruntime_add_shared_library_module(example_plugin_ep ${onnxruntime_autoep_test_library_src}) target_include_directories(example_plugin_ep PRIVATE ${REPO_ROOT}/include/onnxruntime/core/session) - target_link_libraries(example_plugin_ep PRIVATE onnxruntime) + target_link_libraries(example_plugin_ep PRIVATE onnxruntime ${GSL_TARGET}) if(UNIX) if (APPLE) diff --git a/onnxruntime/core/session/utils.cc b/onnxruntime/core/session/utils.cc index 4a50bab5e8cbc..95b292b2dad36 100644 --- a/onnxruntime/core/session/utils.cc +++ b/onnxruntime/core/session/utils.cc @@ -414,7 +414,15 @@ Status LoadPluginOrProviderBridge(const std::string& registration_name, auto provider_library = std::make_unique(resolved_library_path.native().c_str(), true, ProviderLibraryPathType::Absolute); - bool is_provider_bridge = provider_library->Load() == Status::OK(); // library has GetProvider + + const bool is_provider_bridge = [&]() -> bool { +#if defined(ORT_PROVIDER_BRIDGE_IS_SUPPORTED) + return provider_library->Load() == Status::OK(); // library has GetProvider +#else + return false; +#endif + }(); + LOGS_DEFAULT(INFO) << "Loading EP library: " << library_path << (is_provider_bridge ? " as a provider bridge" : " as a plugin"); diff --git a/onnxruntime/test/autoep/library/ep_stream_support.h b/onnxruntime/test/autoep/library/ep_stream_support.h index a825e5afd2250..8bc977408ff2f 100644 --- a/onnxruntime/test/autoep/library/ep_stream_support.h +++ b/onnxruntime/test/autoep/library/ep_stream_support.h @@ -36,7 +36,7 @@ class StreamImpl : public OrtSyncStreamImpl, public ApiPtrs { // EP instance if the stream is being created internally for inferencing. // nullptr when the stream is created outside of an inference session for data copies. - const OrtEp* ep_; + [[maybe_unused]] const OrtEp* ep_; ExampleEpFactory* factory_{nullptr}; }; @@ -60,5 +60,5 @@ class NotificationImpl : public OrtSyncNotificationImpl, public ApiPtrs { static OrtStatus* ORT_API_CALL WaitOnHostImpl(_In_ OrtSyncNotificationImpl* this_ptr) noexcept; static void ORT_API_CALL ReleaseImpl(_In_ OrtSyncNotificationImpl* this_ptr) noexcept; - void* event_{NULL}; // placeholder. e.g. CANN uses aclrtEvent, CUDA uses cudaEvent_t + [[maybe_unused]] void* event_{NULL}; // placeholder. e.g. CANN uses aclrtEvent, CUDA uses cudaEvent_t }; diff --git a/onnxruntime/test/autoep/library/example_plugin_ep_utils.h b/onnxruntime/test/autoep/library/example_plugin_ep_utils.h index decc89251dc7b..7070dabc57c8d 100644 --- a/onnxruntime/test/autoep/library/example_plugin_ep_utils.h +++ b/onnxruntime/test/autoep/library/example_plugin_ep_utils.h @@ -47,11 +47,12 @@ #define EP_FILE __FILE__ #endif -#define LOG(level, ...) \ - do { \ - std::ostringstream ss; \ - ss << __VA_ARGS__; \ - api_.Logger_LogMessage(&logger_, ORT_LOGGING_LEVEL_##level, ss.str().c_str(), EP_FILE, __LINE__, __FUNCTION__); \ +#define LOG(level, ...) \ + do { \ + std::ostringstream ss; \ + ss << __VA_ARGS__; \ + Ort::Status ignored{api_.Logger_LogMessage(&logger_, ORT_LOGGING_LEVEL_##level, ss.str().c_str(), \ + EP_FILE, __LINE__, __FUNCTION__)}; \ } while (false) #define RETURN_ERROR(code, ...) \ diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index 327caf83c7850..37d4ebb5e6406 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -1588,17 +1588,25 @@ def dump_logs_on_failure(): # run shared_lib_test if necessary if args.build_shared_lib: - adb_push("libonnxruntime.so", device_dir, cwd=cwd) - adb_push("onnxruntime_shared_lib_test", device_dir, cwd=cwd) - adb_push("libcustom_op_library.so", device_dir, cwd=cwd) - adb_push("libcustom_op_get_const_input_test_library.so", device_dir, cwd=cwd) - adb_push("onnxruntime_customopregistration_test", device_dir, cwd=cwd) - adb_shell(f"chmod +x {device_dir}/onnxruntime_shared_lib_test") - adb_shell(f"chmod +x {device_dir}/onnxruntime_customopregistration_test") - run_adb_shell(f"LD_LIBRARY_PATH=$LD_LIBRARY_PATH:{device_dir} {device_dir}/onnxruntime_shared_lib_test") - run_adb_shell( - f"LD_LIBRARY_PATH=$LD_LIBRARY_PATH:{device_dir} {device_dir}/onnxruntime_customopregistration_test" - ) + shared_library_test_program_names = [ + "onnxruntime_shared_lib_test", + "onnxruntime_customopregistration_test", + "onnxruntime_autoep_test", + ] + + shared_libraries = [ + "libonnxruntime.so", + "libcustom_op_library.so", + "libcustom_op_get_const_input_test_library.so", + ] + + for file_to_copy in (shared_library_test_program_names + shared_libraries): + adb_push(file_to_copy, device_dir, cwd=cwd) + + # run test programs + for test_program_name in shared_library_test_program_names: + adb_shell(f"chmod +x {device_dir}/{test_program_name}") + run_adb_shell(f"LD_LIBRARY_PATH=$LD_LIBRARY_PATH:{device_dir} {device_dir}/{test_program_name}") all_android_tests_passed = True From 790ba41d2db6c85f4ee68d5c4baebb426645d2c3 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 17 Oct 2025 08:03:33 -0700 Subject: [PATCH 02/43] update comment --- tools/ci_build/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index 37d4ebb5e6406..70a3762e33fee 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -1586,7 +1586,7 @@ def dump_logs_on_failure(): else: run_adb_shell(f"{device_dir}/onnx_test_runner {device_dir}/test") - # run shared_lib_test if necessary + # run shared library tests if applicable if args.build_shared_lib: shared_library_test_program_names = [ "onnxruntime_shared_lib_test", From 81c7d95e62ea2fba2ceb565c8b924d383a51967b Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 17 Oct 2025 09:33:32 -0700 Subject: [PATCH 03/43] update autoep tests to build/run on Android --- onnxruntime/test/autoep/test_allocators.cc | 5 ----- onnxruntime/test/autoep/test_autoep_utils.cc | 7 +------ onnxruntime/test/autoep/test_data_transfer.cc | 5 ----- onnxruntime/test/autoep/test_execution.cc | 5 ----- onnxruntime/test/autoep/test_registration.cc | 11 ++++------- onnxruntime/test/autoep/test_selection.cc | 5 ----- 6 files changed, 5 insertions(+), 33 deletions(-) diff --git a/onnxruntime/test/autoep/test_allocators.cc b/onnxruntime/test/autoep/test_allocators.cc index 88b522eb10dca..4a909a34f5dd2 100644 --- a/onnxruntime/test/autoep/test_allocators.cc +++ b/onnxruntime/test/autoep/test_allocators.cc @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -// registration/selection is only supported on windows as there's no device discovery on other platforms -#ifdef _WIN32 - #include #include #include @@ -134,5 +131,3 @@ TEST(SharedAllocators, GetSharedAllocator) { } // namespace test } // namespace onnxruntime - -#endif // _WIN32 diff --git a/onnxruntime/test/autoep/test_autoep_utils.cc b/onnxruntime/test/autoep/test_autoep_utils.cc index 7045ccca2f576..d5605fbb03935 100644 --- a/onnxruntime/test/autoep/test_autoep_utils.cc +++ b/onnxruntime/test/autoep/test_autoep_utils.cc @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -// registration/selection is only supported on windows as there's no device discovery on other platforms -#ifdef _WIN32 - #include "test/autoep/test_autoep_utils.h" #include @@ -47,11 +44,9 @@ void Utils::RegisterAndGetExampleEp(Ort::Env& env, RegisteredEpDeviceUniquePtr& ASSERT_NE(example_ep, nullptr); registered_ep = RegisteredEpDeviceUniquePtr(example_ep, [&env, c_api](const OrtEpDevice* /*ep*/) { - c_api.UnregisterExecutionProviderLibrary(env, example_ep_info.registration_name.c_str()); + Ort::Status ignored{c_api.UnregisterExecutionProviderLibrary(env, example_ep_info.registration_name.c_str())}; }); } } // namespace test } // namespace onnxruntime - -#endif // _WIN32 diff --git a/onnxruntime/test/autoep/test_data_transfer.cc b/onnxruntime/test/autoep/test_data_transfer.cc index 71c69698ed386..5f23d7eb2a010 100644 --- a/onnxruntime/test/autoep/test_data_transfer.cc +++ b/onnxruntime/test/autoep/test_data_transfer.cc @@ -3,9 +3,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -// registration/selection is only supported on windows as there's no device discovery on other platforms -#ifdef _WIN32 - #include #include #include @@ -73,5 +70,3 @@ TEST(OrtEpLibrary, DataTransfer) { } // namespace test } // namespace onnxruntime - -#endif // _WIN32 diff --git a/onnxruntime/test/autoep/test_execution.cc b/onnxruntime/test/autoep/test_execution.cc index 78be22d082692..352dbe4c69f31 100644 --- a/onnxruntime/test/autoep/test_execution.cc +++ b/onnxruntime/test/autoep/test_execution.cc @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -// registration/selection is only supported on windows as there's no device discovery on other platforms -#ifdef _WIN32 - #include // #include #include @@ -156,5 +153,3 @@ TEST(OrtEpLibrary, PluginEp_GenEpContextModel) { } } // namespace test } // namespace onnxruntime - -#endif // _WIN32 diff --git a/onnxruntime/test/autoep/test_registration.cc b/onnxruntime/test/autoep/test_registration.cc index 88c2e320990e1..5a353d1d8e863 100644 --- a/onnxruntime/test/autoep/test_registration.cc +++ b/onnxruntime/test/autoep/test_registration.cc @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -// registration/selection is only supported on windows as there's no device discovery on other platforms -#ifdef _WIN32 - #include #include #include @@ -35,7 +32,7 @@ TEST(OrtEpLibrary, LoadUnloadPluginLibrary) { ASSERT_ORTSTATUS_OK(Ort::GetApi().GetEpDevices(*ort_env, &ep_devices, &num_devices)); // should be one device for the example EP auto num_test_ep_devices = std::count_if(ep_devices, ep_devices + num_devices, - [®istration_name, &c_api](const OrtEpDevice* device) { + [&](const OrtEpDevice* device) { // the example uses the registration name for the EP name // but that is not a requirement and the two can differ. return c_api->EpDevice_EpName(device) == registration_name; @@ -58,7 +55,7 @@ TEST(OrtEpLibrary, LoadUnloadPluginLibraryCxxApi) { // should be one device for the example EP auto test_ep_device = std::find_if(ep_devices.begin(), ep_devices.end(), - [®istration_name](Ort::ConstEpDevice& device) { + [&](Ort::ConstEpDevice& device) { // the example uses the registration name for the EP name // but that is not a requirement and the two can differ. return device.EpName() == registration_name; @@ -83,7 +80,9 @@ TEST(OrtEpLibrary, LoadUnloadPluginLibraryCxxApi) { ASSERT_NE(device.Vendor(), nullptr); Ort::ConstKeyValuePairs device_metadata = device.Metadata(); std::unordered_map metadata_entries = device_metadata.GetKeyValuePairs(); +#if defined(_WIN32) ASSERT_GT(metadata_entries.size(), 0); // should have at least SPDRP_HARDWAREID on Windows +#endif // and this should unload it without throwing ort_env->UnregisterExecutionProviderLibrary(registration_name.c_str()); @@ -91,5 +90,3 @@ TEST(OrtEpLibrary, LoadUnloadPluginLibraryCxxApi) { } // namespace test } // namespace onnxruntime - -#endif // _WIN32 diff --git a/onnxruntime/test/autoep/test_selection.cc b/onnxruntime/test/autoep/test_selection.cc index 72f39be917f90..4524f0ce50a57 100644 --- a/onnxruntime/test/autoep/test_selection.cc +++ b/onnxruntime/test/autoep/test_selection.cc @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -// registration/selection is only supported on windows as there's no device discovery on other platforms -#ifdef _WIN32 - #include // #include #include @@ -502,5 +499,3 @@ TEST(AutoEpSelection, PolicyDelegateReturnsError) { } // namespace test } // namespace onnxruntime - -#endif // _WIN32 From 2e14060bb33ee9e1de80a219664a92732a55bf5a Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 17 Oct 2025 09:47:21 -0700 Subject: [PATCH 04/43] update comment in CMakeLists.txt --- cmake/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 1c94bd6e96bc7..485daddfbcf91 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1650,12 +1650,12 @@ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") endif() endif() -# Now the 'onnxruntime_EXTERNAL_LIBRARIES' variable should be sealed. It will be used in onnxruntime.cmake which will -# be included next. +# From this point on, onnxruntime_EXTERNAL_LIBRARIES should be no longer be modified. It will be used in +# onnxruntime.cmake which will be included next. -# The order of the following CMake file names (which exclude the ".cmake" suffix) matters. Later CMake files may depend -# on earlier ones but earler ones cannot depend on later ones. For example, if A appears before B, then A.cmake cannot -# use variables defined in B.cmake. +# The order of the CMake file names (which exclude the ".cmake" suffix) in ONNXRUNTIME_CMAKE_FILES matters. Later CMake +# files may depend on earlier ones but earlier ones cannot depend on later ones. For example, if A appears before B, +# then A.cmake cannot use variables defined in B.cmake. set(ONNXRUNTIME_CMAKE_FILES onnxruntime_flatbuffers onnxruntime_common From e52f862570ef1729105aa3fe7ac6590ce16ae260 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:27:54 -0700 Subject: [PATCH 05/43] replace ProviderSharedLibrary oid Ensure() with Status Initialize(), remove ifdefs. --- cmake/onnxruntime_session.cmake | 4 ---- .../core/session/provider_bridge_ort.cc | 21 +++++++++++-------- onnxruntime/core/session/utils.cc | 8 +------ 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/cmake/onnxruntime_session.cmake b/cmake/onnxruntime_session.cmake index 59d4b7c4a71e8..f81a7a9726b76 100644 --- a/cmake/onnxruntime_session.cmake +++ b/cmake/onnxruntime_session.cmake @@ -45,10 +45,6 @@ if(onnxruntime_ENABLE_INSTRUMENT) target_compile_definitions(onnxruntime_session PUBLIC ONNXRUNTIME_ENABLE_INSTRUMENT) endif() -if(TARGET onnxruntime_providers_shared) - target_compile_definitions(onnxruntime_session PRIVATE ORT_PROVIDER_BRIDGE_IS_SUPPORTED) -endif() - if(NOT MSVC) set_source_files_properties(${ONNXRUNTIME_ROOT}/core/session/environment.cc PROPERTIES COMPILE_FLAGS "-Wno-parentheses") endif() diff --git a/onnxruntime/core/session/provider_bridge_ort.cc b/onnxruntime/core/session/provider_bridge_ort.cc index 960b9eff051be..1793f12c3ab44 100644 --- a/onnxruntime/core/session/provider_bridge_ort.cc +++ b/onnxruntime/core/session/provider_bridge_ort.cc @@ -1774,24 +1774,27 @@ struct ProviderHostImpl : ProviderHost { #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_MINIMAL_BUILD_CUSTOM_OPS) Status LoadDynamicLibrary(onnxruntime::PathString library_name) override { return LoadDynamicLibraryFromProvider(library_name); }; #endif -} provider_host_; +} g_provider_host; #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(pop) #endif struct ProviderSharedLibrary { - void Ensure() { - if (handle_) - return; + Status Initialize() { + if (handle_) { + return Status::OK(); + } auto full_path = Env::Default().GetRuntimePath() + PathString(LIBRARY_PREFIX ORT_TSTR("onnxruntime_providers_shared") LIBRARY_EXTENSION); - ORT_THROW_IF_ERROR(Env::Default().LoadDynamicLibrary(full_path, true /*shared_globals on unix*/, &handle_)); + ORT_RETURN_IF_ERROR(Env::Default().LoadDynamicLibrary(full_path, true /*shared_globals on unix*/, &handle_)); void (*PProvider_SetHost)(void*); - ORT_THROW_IF_ERROR(Env::Default().GetSymbolFromLibrary(handle_, "Provider_SetHost", (void**)&PProvider_SetHost)); + ORT_RETURN_IF_ERROR(Env::Default().GetSymbolFromLibrary(handle_, "Provider_SetHost", (void**)&PProvider_SetHost)); - PProvider_SetHost(&provider_host_); + PProvider_SetHost(&g_provider_host); + + return Status::OK(); } void Unload() { @@ -1818,7 +1821,7 @@ struct ProviderSharedLibrary { static ProviderSharedLibrary s_library_shared; bool InitProvidersSharedLibrary() try { - s_library_shared.Ensure(); + ORT_THROW_IF_ERROR(s_library_shared.Initialize()); return true; } catch (const std::exception&) { return false; @@ -1840,7 +1843,7 @@ Status ProviderLibrary::Load() { try { std::lock_guard lock{mutex_}; if (!provider_) { - s_library_shared.Ensure(); + ORT_RETURN_IF_ERROR(s_library_shared.Initialize()); if (absolute_) { // If filename_ is not absolute it should not be loaded. diff --git a/onnxruntime/core/session/utils.cc b/onnxruntime/core/session/utils.cc index 95b292b2dad36..1b752daccd746 100644 --- a/onnxruntime/core/session/utils.cc +++ b/onnxruntime/core/session/utils.cc @@ -415,13 +415,7 @@ Status LoadPluginOrProviderBridge(const std::string& registration_name, true, ProviderLibraryPathType::Absolute); - const bool is_provider_bridge = [&]() -> bool { -#if defined(ORT_PROVIDER_BRIDGE_IS_SUPPORTED) - return provider_library->Load() == Status::OK(); // library has GetProvider -#else - return false; -#endif - }(); + bool is_provider_bridge = provider_library->Load() == Status::OK(); // library has GetProvider LOGS_DEFAULT(INFO) << "Loading EP library: " << library_path << (is_provider_bridge ? " as a provider bridge" : " as a plugin"); From ff569c61cc8a1ac2363d0d79a2794dcd41645fea Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:33:04 -0700 Subject: [PATCH 06/43] remove newlines --- onnxruntime/core/session/utils.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/onnxruntime/core/session/utils.cc b/onnxruntime/core/session/utils.cc index 1b752daccd746..4a50bab5e8cbc 100644 --- a/onnxruntime/core/session/utils.cc +++ b/onnxruntime/core/session/utils.cc @@ -414,9 +414,7 @@ Status LoadPluginOrProviderBridge(const std::string& registration_name, auto provider_library = std::make_unique(resolved_library_path.native().c_str(), true, ProviderLibraryPathType::Absolute); - bool is_provider_bridge = provider_library->Load() == Status::OK(); // library has GetProvider - LOGS_DEFAULT(INFO) << "Loading EP library: " << library_path << (is_provider_bridge ? " as a provider bridge" : " as a plugin"); From ff3ed1818dfd524214e1d5b3020bb96c4fdc525c Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:12:42 -0700 Subject: [PATCH 07/43] pass by ref in for loop --- onnxruntime/test/autoep/library/ep.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onnxruntime/test/autoep/library/ep.cc b/onnxruntime/test/autoep/library/ep.cc index 5d8245618dcd6..5fc7ea31b9011 100644 --- a/onnxruntime/test/autoep/library/ep.cc +++ b/onnxruntime/test/autoep/library/ep.cc @@ -399,7 +399,7 @@ OrtStatus* ExampleEp::CreateEpContextNodes(gsl::span fused_nodes std::vector value_names; value_names.reserve(value_infos.size()); - for (const auto vi : value_infos) { + for (const auto& vi : value_infos) { value_names.push_back(vi.GetName()); } From 6a815267d68287da8ab22f59a81a623c618ef7a0 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:49:40 -0700 Subject: [PATCH 08/43] try to fix GCC warning about maybe_unused on data members --- .../test/autoep/library/ep_stream_support.cc | 17 +++++++++++------ .../test/autoep/library/ep_stream_support.h | 12 +++++++----- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/onnxruntime/test/autoep/library/ep_stream_support.cc b/onnxruntime/test/autoep/library/ep_stream_support.cc index c648474d4fad7..12e1b935be4b2 100644 --- a/onnxruntime/test/autoep/library/ep_stream_support.cc +++ b/onnxruntime/test/autoep/library/ep_stream_support.cc @@ -70,14 +70,17 @@ OrtStatus* ORT_API_CALL NotificationImpl::WaitOnDeviceImpl(_In_ OrtSyncNotificat void* handle = impl.ort_api.SyncStream_GetHandle(stream); static_cast(handle); + auto event = impl.event_; + static_cast(event); + // Setup the event or similar that will be activated on notification. // See CudaNotification or CannNotification for examples. // // e.g. - // CUDA: cudaStreamWaitEvent(static_cast(device_stream.GetHandle()), event_) - // CANN: aclrtStreamWaitEvent(static_cast(device_stream.GetHandle()), event_) + // CUDA: cudaStreamWaitEvent(static_cast(handle), event) + // CANN: aclrtStreamWaitEvent(static_cast(handle), event) // - // `event_` should be a member that is created in the ctor. + // `NotificationImpl::event_` should be a member that is created in the ctor. // The stream handle should come from the StreamImpl instance and can be the real type so no static_cast is needed. return nullptr; } @@ -85,11 +88,13 @@ OrtStatus* ORT_API_CALL NotificationImpl::WaitOnDeviceImpl(_In_ OrtSyncNotificat /*static*/ OrtStatus* ORT_API_CALL NotificationImpl::WaitOnHostImpl(_In_ OrtSyncNotificationImpl* this_ptr) noexcept { auto& impl = *static_cast(this_ptr); - static_cast(impl); + + auto event = impl.event_; + static_cast(event); // e.g. - // CUDA: cudaEventSynchronize(event_) - // CANN: aclrtSynchronizeEvent(event_) + // CUDA: cudaEventSynchronize(event) + // CANN: aclrtSynchronizeEvent(event) return nullptr; } diff --git a/onnxruntime/test/autoep/library/ep_stream_support.h b/onnxruntime/test/autoep/library/ep_stream_support.h index 8bc977408ff2f..fb4b3eda8c461 100644 --- a/onnxruntime/test/autoep/library/ep_stream_support.h +++ b/onnxruntime/test/autoep/library/ep_stream_support.h @@ -15,7 +15,12 @@ class ExampleEpFactory; class StreamImpl : public OrtSyncStreamImpl, public ApiPtrs { public: StreamImpl(ExampleEpFactory& factory, const OrtEp* ep, const OrtKeyValuePairs* /*stream_options*/) - : ApiPtrs(factory), ep_{ep}, factory_{&factory} { + : ApiPtrs(factory), factory_{&factory} { + // `ep` is the EP instance if the stream is being created internally for inferencing. + // nullptr when the stream is created outside of an inference session for data copies. + // It is not used by this example implementation. + static_cast(ep); + ort_version_supported = ORT_API_VERSION; CreateNotification = CreateNotificationImpl; GetHandle = GetHandleImpl; @@ -34,9 +39,6 @@ class StreamImpl : public OrtSyncStreamImpl, public ApiPtrs { void* handle_{nullptr}; // use the real stream type, like cudaStream_t or aclrtStream, etc. - // EP instance if the stream is being created internally for inferencing. - // nullptr when the stream is created outside of an inference session for data copies. - [[maybe_unused]] const OrtEp* ep_; ExampleEpFactory* factory_{nullptr}; }; @@ -60,5 +62,5 @@ class NotificationImpl : public OrtSyncNotificationImpl, public ApiPtrs { static OrtStatus* ORT_API_CALL WaitOnHostImpl(_In_ OrtSyncNotificationImpl* this_ptr) noexcept; static void ORT_API_CALL ReleaseImpl(_In_ OrtSyncNotificationImpl* this_ptr) noexcept; - [[maybe_unused]] void* event_{NULL}; // placeholder. e.g. CANN uses aclrtEvent, CUDA uses cudaEvent_t + void* event_{NULL}; // placeholder. e.g. CANN uses aclrtEvent, CUDA uses cudaEvent_t }; From 9f41ebde9fd9e8b119d6025b48d0232ee56369a3 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:57:09 -0700 Subject: [PATCH 09/43] fix formatting --- tools/ci_build/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index 70a3762e33fee..926065ac31ea6 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -1600,7 +1600,7 @@ def dump_logs_on_failure(): "libcustom_op_get_const_input_test_library.so", ] - for file_to_copy in (shared_library_test_program_names + shared_libraries): + for file_to_copy in shared_library_test_program_names + shared_libraries: adb_push(file_to_copy, device_dir, cwd=cwd) # run test programs From f5a6655253702225d765fe9abccd442f0f521f4f Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:27:36 -0700 Subject: [PATCH 10/43] use Ort::MemoryInfo in ep_factory.cc --- onnxruntime/test/autoep/library/ep_factory.cc | 64 +++++++++---------- onnxruntime/test/autoep/library/ep_factory.h | 5 +- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/onnxruntime/test/autoep/library/ep_factory.cc b/onnxruntime/test/autoep/library/ep_factory.cc index 4da7d722a5e0b..f4f7c26f549ff 100644 --- a/onnxruntime/test/autoep/library/ep_factory.cc +++ b/onnxruntime/test/autoep/library/ep_factory.cc @@ -12,7 +12,11 @@ #include "ep_stream_support.h" ExampleEpFactory::ExampleEpFactory(const char* ep_name, ApiPtrs apis, const OrtLogger& default_logger) - : ApiPtrs(apis), default_logger_{default_logger}, ep_name_{ep_name} { + : ApiPtrs(apis), + default_logger_{default_logger}, + ep_name_{ep_name}, + default_memory_info_{nullptr}, + readonly_memory_info_{nullptr} { ort_version_supported = ORT_API_VERSION; // set to the ORT version we were compiled with. GetName = GetNameImpl; GetVendor = GetVendorImpl; @@ -34,43 +38,35 @@ ExampleEpFactory::ExampleEpFactory(const char* ep_name, ApiPtrs apis, const OrtL // setup the OrtMemoryInfo instances required by the EP. // We pretend the device the EP is running on is GPU. - OrtMemoryInfo* mem_info = nullptr; - auto* status = ort_api.CreateMemoryInfo_V2("ExampleEP GPU", OrtMemoryInfoDeviceType_GPU, - /*vendor*/ 0xBE57, /* device_id */ 0, - OrtDeviceMemoryType_DEFAULT, - /*alignment*/ 0, - // it is invalid to use OrtArenaAllocator as that is reserved for the - // internal ORT Arena implementation - OrtAllocatorType::OrtDeviceAllocator, - &mem_info); - assert(status == nullptr); // should never fail. - default_memory_info_ = MemoryInfoUniquePtr(mem_info, ort_api.ReleaseMemoryInfo); + default_memory_info_ = Ort::MemoryInfo{"ExampleEP GPU", + OrtMemoryInfoDeviceType_GPU, + /*vendor*/ 0xBE57, /* device_id */ 0, + OrtDeviceMemoryType_DEFAULT, + /*alignment*/ 0, + // it is invalid to use OrtArenaAllocator as that is reserved for the internal + // ORT Arena implementation + OrtAllocatorType::OrtDeviceAllocator}; // create data transfer for the device - const OrtMemoryDevice* device = ep_api.MemoryInfo_GetMemoryDevice(default_memory_info_.get()); + const OrtMemoryDevice* device = ep_api.MemoryInfo_GetMemoryDevice(default_memory_info_); data_transfer_impl_ = std::make_unique(apis, device); // create read-only allocator for use with initializers. same info as DEFAULT memory apart from the allocator type. - status = ort_api.CreateMemoryInfo_V2("ExampleEP GPU readonly", OrtMemoryInfoDeviceType_GPU, - /*vendor*/ 0xBE57, /* device_id */ 0, - OrtDeviceMemoryType_DEFAULT, - /*alignment*/ 0, - OrtAllocatorType::OrtReadOnlyAllocator, - &mem_info); - assert(status == nullptr); // should never fail. - - readonly_memory_info_ = MemoryInfoUniquePtr(mem_info, ort_api.ReleaseMemoryInfo); + readonly_memory_info_ = Ort::MemoryInfo{"ExampleEP GPU readonly", + OrtMemoryInfoDeviceType_GPU, + /*vendor*/ 0xBE57, /* device_id */ 0, + OrtDeviceMemoryType_DEFAULT, + /*alignment*/ 0, + OrtAllocatorType::OrtReadOnlyAllocator}; // HOST_ACCESSIBLE memory example. use the non-CPU device type so it's clear which device the memory is also // accessible from. we infer from the type of HOST_ACCESSIBLE that it's CPU accessible. - mem_info = nullptr; - status = ort_api.CreateMemoryInfo_V2("ExampleEP GPU pinned", OrtMemoryInfoDeviceType_GPU, - /*vendor*/ 0xBE57, /* device_id */ 0, - OrtDeviceMemoryType_HOST_ACCESSIBLE, - /*alignment*/ 0, - OrtAllocatorType::OrtDeviceAllocator, - &mem_info); - ort_api.ReleaseMemoryInfo(mem_info); + auto host_accessible_memory_info = Ort::MemoryInfo{"ExampleEP GPU pinned", + OrtMemoryInfoDeviceType_GPU, + /*vendor*/ 0xBE57, /* device_id */ 0, + OrtDeviceMemoryType_HOST_ACCESSIBLE, + /*alignment*/ 0, + OrtAllocatorType::OrtDeviceAllocator}; } /*static*/ @@ -136,8 +132,8 @@ OrtStatus* ORT_API_CALL ExampleEpFactory::GetSupportedDevicesImpl(OrtEpFactory* // register the allocator info required by the EP. // registering OrtMemoryInfo for host accessible memory would be done in an additional call. // OrtReadOnlyAllocator + OrtDeviceMemoryType_DEFAULT allocator for use with initializers is optional. - RETURN_IF_ERROR(factory->ep_api.EpDevice_AddAllocatorInfo(ep_device, factory->default_memory_info_.get())); - RETURN_IF_ERROR(factory->ep_api.EpDevice_AddAllocatorInfo(ep_device, factory->readonly_memory_info_.get())); + RETURN_IF_ERROR(factory->ep_api.EpDevice_AddAllocatorInfo(ep_device, factory->default_memory_info_)); + RETURN_IF_ERROR(factory->ep_api.EpDevice_AddAllocatorInfo(ep_device, factory->readonly_memory_info_)); ep_devices[num_ep_devices++] = ep_device; } @@ -216,8 +212,8 @@ OrtStatus* ORT_API_CALL ExampleEpFactory::CreateAllocatorImpl(OrtEpFactory* this auto& factory = *static_cast(this_ptr); *allocator = nullptr; - bool is_default_allocator = memory_info == factory.default_memory_info_.get(); - bool is_readonly_allocator = memory_info == factory.readonly_memory_info_.get(); + bool is_default_allocator = memory_info == factory.default_memory_info_; + bool is_readonly_allocator = memory_info == factory.readonly_memory_info_; if (!is_default_allocator && !is_readonly_allocator) { return factory.ort_api.CreateStatus(ORT_INVALID_ARGUMENT, diff --git a/onnxruntime/test/autoep/library/ep_factory.h b/onnxruntime/test/autoep/library/ep_factory.h index 088deda1fe9d2..f99dfb021cfbe 100644 --- a/onnxruntime/test/autoep/library/ep_factory.h +++ b/onnxruntime/test/autoep/library/ep_factory.h @@ -74,9 +74,8 @@ class ExampleEpFactory : public OrtEpFactory, public ApiPtrs { const std::string ep_version_{"0.1.0"}; // EP version // CPU allocator so we can control the arena behavior. optional as ORT always provides a CPU allocator if needed. - using MemoryInfoUniquePtr = std::unique_ptr>; - MemoryInfoUniquePtr default_memory_info_; - MemoryInfoUniquePtr readonly_memory_info_; // used for initializers + Ort::MemoryInfo default_memory_info_; + Ort::MemoryInfo readonly_memory_info_; // used for initializers bool arena_allocator_using_default_settings_{true}; std::unique_ptr arena_allocator_; // shared device allocator that uses an arena From 160b06e7bc0749dfe8c805a5746f3029ebaba606 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:34:34 -0700 Subject: [PATCH 11/43] fix example_plugin_ep library path on Apple platforms --- onnxruntime/test/autoep/test_autoep_utils.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/onnxruntime/test/autoep/test_autoep_utils.h b/onnxruntime/test/autoep/test_autoep_utils.h index 2dd7b5f0428e2..5c59f2b57361e 100644 --- a/onnxruntime/test/autoep/test_autoep_utils.h +++ b/onnxruntime/test/autoep/test_autoep_utils.h @@ -16,8 +16,10 @@ using RegisteredEpDeviceUniquePtr = std::unique_ptr Date: Tue, 21 Oct 2025 14:28:52 -0700 Subject: [PATCH 12/43] example_plugin_ep - derive allocators from BaseAllocator which has a virtual dtor, initialize ArenaImpl::stats_ --- onnxruntime/test/autoep/library/ep_allocator.h | 11 ++++++++++- onnxruntime/test/autoep/library/ep_arena.h | 4 ++-- onnxruntime/test/autoep/library/ep_factory.cc | 2 +- .../test/autoep/library/example_plugin_ep_utils.h | 2 -- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/onnxruntime/test/autoep/library/ep_allocator.h b/onnxruntime/test/autoep/library/ep_allocator.h index e46c03dfc8f14..d1779ac0ed2d7 100644 --- a/onnxruntime/test/autoep/library/ep_allocator.h +++ b/onnxruntime/test/autoep/library/ep_allocator.h @@ -51,7 +51,16 @@ struct AllocatorStats { } }; -struct CustomAllocator : OrtAllocator { +// `OrtAllocator` is a C struct. +// `BaseAllocator` is a minimal C++ struct which inherits from it. Notably, `BaseAllocator` has a virtual destructor to +// enable a derived class to be deleted through a `BaseAllocator` pointer. +struct BaseAllocator : OrtAllocator { + virtual ~BaseAllocator() = default; +}; + +using AllocatorUniquePtr = std::unique_ptr; + +struct CustomAllocator : BaseAllocator { CustomAllocator(const OrtMemoryInfo* mem_info, const ApiPtrs& api_ptrs_in) : memory_info{mem_info}, api_ptrs{api_ptrs_in} { version = ORT_API_VERSION; diff --git a/onnxruntime/test/autoep/library/ep_arena.h b/onnxruntime/test/autoep/library/ep_arena.h index caa2c61db835f..a370605e2249f 100644 --- a/onnxruntime/test/autoep/library/ep_arena.h +++ b/onnxruntime/test/autoep/library/ep_arena.h @@ -551,7 +551,7 @@ class ArenaImpl { // un-assign chunks when StreamImpl::OnSessionRunEnd is called. std::unordered_map impl_to_stream_; - AllocatorStats stats_; + AllocatorStats stats_{}; const OrtApi& api_; const OrtEpApi& ep_api_; @@ -563,7 +563,7 @@ class ArenaImpl { ArenaImpl& operator=(ArenaImpl&&) = delete; }; -struct ArenaAllocator : OrtAllocator { +struct ArenaAllocator : BaseAllocator { static OrtStatus* CreateOrtArenaAllocator(AllocatorUniquePtr allocator, const OrtKeyValuePairs* options, const OrtApi& api, diff --git a/onnxruntime/test/autoep/library/ep_factory.cc b/onnxruntime/test/autoep/library/ep_factory.cc index f4f7c26f549ff..a6cb7897e5d2c 100644 --- a/onnxruntime/test/autoep/library/ep_factory.cc +++ b/onnxruntime/test/autoep/library/ep_factory.cc @@ -241,7 +241,7 @@ OrtStatus* ORT_API_CALL ExampleEpFactory::CreateAllocatorImpl(OrtEpFactory* this std::lock_guard lock{factory.mutex_}; if (!factory.arena_allocator_) { - std::unique_ptr ep_allocator = std::make_unique(memory_info, factory); + AllocatorUniquePtr ep_allocator = std::make_unique(memory_info, factory); // initial shared allocator in environment does not have allocator options. // if the user calls CreateSharedAllocator they can provide options to configure the arena differently. diff --git a/onnxruntime/test/autoep/library/example_plugin_ep_utils.h b/onnxruntime/test/autoep/library/example_plugin_ep_utils.h index 7070dabc57c8d..ef7f8c0552d6f 100644 --- a/onnxruntime/test/autoep/library/example_plugin_ep_utils.h +++ b/onnxruntime/test/autoep/library/example_plugin_ep_utils.h @@ -73,8 +73,6 @@ struct ApiPtrs { const OrtModelEditorApi& model_editor_api; }; -using AllocatorUniquePtr = std::unique_ptr>; - // Helper to release Ort one or more objects obtained from the public C API at the end of their scope. template struct DeferOrtRelease { From b39b442fa17010e88b33cb2294ba6ee9efaa2533 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:38:28 -0700 Subject: [PATCH 13/43] delete ExampleNodeComputeInfo* instead of base class OrtNodeComputeInfo*. base class doesn't have a virtual dtor. --- onnxruntime/test/autoep/library/ep.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onnxruntime/test/autoep/library/ep.cc b/onnxruntime/test/autoep/library/ep.cc index 5fc7ea31b9011..bc4e5a441a49a 100644 --- a/onnxruntime/test/autoep/library/ep.cc +++ b/onnxruntime/test/autoep/library/ep.cc @@ -381,7 +381,7 @@ void ORT_API_CALL ExampleEp::ReleaseNodeComputeInfosImpl(OrtEp* this_ptr, size_t num_node_compute_infos) noexcept { (void)this_ptr; for (size_t i = 0; i < num_node_compute_infos; i++) { - delete node_compute_infos[i]; + delete static_cast(node_compute_infos[i]); } } From 7a4c849b033172a1ce11fca44b70be8b9c39cdb6 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:33:45 -0700 Subject: [PATCH 14/43] add libexample_plugin_ep.so to files copied to Android device, sort filenames --- tools/ci_build/build.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index f1228ff852024..9089f8deb85cd 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -1600,15 +1600,16 @@ def dump_logs_on_failure(): # run shared library tests if applicable if args.build_shared_lib: shared_library_test_program_names = [ - "onnxruntime_shared_lib_test", - "onnxruntime_customopregistration_test", "onnxruntime_autoep_test", + "onnxruntime_customopregistration_test", + "onnxruntime_shared_lib_test", ] shared_libraries = [ - "libonnxruntime.so", - "libcustom_op_library.so", "libcustom_op_get_const_input_test_library.so", + "libcustom_op_library.so", + "libexample_plugin_ep.so", + "libonnxruntime.so", ] for file_to_copy in shared_library_test_program_names + shared_libraries: From e3f372edbdf7b3098378e6e14c8f9917ae83ff5c Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Tue, 21 Oct 2025 18:15:40 -0700 Subject: [PATCH 15/43] add include, update comment --- onnxruntime/test/autoep/library/ep_allocator.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/onnxruntime/test/autoep/library/ep_allocator.h b/onnxruntime/test/autoep/library/ep_allocator.h index d1779ac0ed2d7..1c2f6ae377bea 100644 --- a/onnxruntime/test/autoep/library/ep_allocator.h +++ b/onnxruntime/test/autoep/library/ep_allocator.h @@ -5,6 +5,7 @@ #include "example_plugin_ep_utils.h" +#include #include // from onnxruntime/core/framework/allocator_stats.h @@ -51,9 +52,9 @@ struct AllocatorStats { } }; -// `OrtAllocator` is a C struct. -// `BaseAllocator` is a minimal C++ struct which inherits from it. Notably, `BaseAllocator` has a virtual destructor to -// enable a derived class to be deleted through a `BaseAllocator` pointer. +// `OrtAllocator` is a C API struct. `BaseAllocator` is a minimal C++ struct which inherits from `OrtAllocator`. +// Notably, `BaseAllocator` has a virtual destructor to enable a derived class to be deleted through a `BaseAllocator` +// pointer. Allocators which need to be deleted through a base class pointer should inherit from `BaseAllocator`. struct BaseAllocator : OrtAllocator { virtual ~BaseAllocator() = default; }; From c12b72249b48011b2dbe79ba1da12bba2de34364 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 24 Oct 2025 14:20:21 -0700 Subject: [PATCH 16/43] try to implement GetRuntimePath() for posix env. --- onnxruntime/core/platform/env.h | 6 +++--- onnxruntime/core/platform/posix/env.cc | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/onnxruntime/core/platform/env.h b/onnxruntime/core/platform/env.h index e100d3626f76b..a038237da03a7 100644 --- a/onnxruntime/core/platform/env.h +++ b/onnxruntime/core/platform/env.h @@ -245,9 +245,9 @@ class Env { // \brief Gets the file path of the onnx runtime code // - // Used to help load other shared libraries that live in the same folder as the core code, for example - // The DNNL provider shared library. Without this path, the module won't be found on windows in all cases. - virtual PathString GetRuntimePath() const { return PathString(); } + // Used to help load other shared libraries that live in the same folder as the core code. + // For example, the DNNL provider shared library. + virtual PathString GetRuntimePath() const = 0; // \brief Get a pointer to a symbol from a dynamic library. // diff --git a/onnxruntime/core/platform/posix/env.cc b/onnxruntime/core/platform/posix/env.cc index fed697ea962bc..f347eca67132d 100644 --- a/onnxruntime/core/platform/posix/env.cc +++ b/onnxruntime/core/platform/posix/env.cc @@ -31,6 +31,7 @@ limitations under the License. #endif #include +#include #include #include #include @@ -554,6 +555,19 @@ class PosixEnv : public Env { return common::Status::OK(); } + PathString GetRuntimePath() const override { + Dl_info dl_info{}; + const void* const address_from_this_binary = reinterpret_cast(Env::Default); + if (dladdr(address_from_this_binary, &dl_info) != 0 && + dl_info.dli_fname != nullptr) { + auto runtime_path = std::filesystem::path{dl_info.dli_fname}.remove_filename(); + runtime_path = std::filesystem::absolute(runtime_path); + return runtime_path; + } + + return PathString{}; + } + common::Status GetSymbolFromLibrary(void* handle, const std::string& symbol_name, void** symbol) const override { dlerror(); // clear any old error str From 45ef29d534eb55467c2537ec0372f823d96cd36d Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 24 Oct 2025 16:51:04 -0700 Subject: [PATCH 17/43] update posix GetRuntimePath --- onnxruntime/core/platform/posix/env.cc | 28 ++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/onnxruntime/core/platform/posix/env.cc b/onnxruntime/core/platform/posix/env.cc index f347eca67132d..8cc16066b0e61 100644 --- a/onnxruntime/core/platform/posix/env.cc +++ b/onnxruntime/core/platform/posix/env.cc @@ -556,13 +556,29 @@ class PosixEnv : public Env { } PathString GetRuntimePath() const override { - Dl_info dl_info{}; + // Use dladdr() to look up the shared object that contains a particular address. + + // `OrtGetApiBase` is exported by the onnxruntime shared library (libonnxruntime.so/dylib). + // Try to find that symbol's address first. It might be nullptr, e.g., if this code is not built as part of the + // onnxruntime shared library. + const void* const address_from_ort_library = dlsym(RTLD_DEFAULT, "OrtGetApiBase"); + + // Fall back to the address of another symbol in this binary. const void* const address_from_this_binary = reinterpret_cast(Env::Default); - if (dladdr(address_from_this_binary, &dl_info) != 0 && - dl_info.dli_fname != nullptr) { - auto runtime_path = std::filesystem::path{dl_info.dli_fname}.remove_filename(); - runtime_path = std::filesystem::absolute(runtime_path); - return runtime_path; + + const std::array addresses{address_from_ort_library, address_from_this_binary}; + + for (const void* address : addresses) { + if (Dl_info dl_info{}; + address != nullptr && + dladdr(address, &dl_info) != 0 && + dl_info.dli_fname != nullptr) { + LOGS_DEFAULT(VERBOSE) << "Getting runtime path as parent directory of binary: " << dl_info.dli_fname; + + auto runtime_path = std::filesystem::path{dl_info.dli_fname}.remove_filename(); + runtime_path = std::filesystem::absolute(runtime_path); + return runtime_path; + } } return PathString{}; From 18c062e6d106eaff359cc4999c68ec79cc6bb192 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 24 Oct 2025 16:52:09 -0700 Subject: [PATCH 18/43] update autoep cuda EP test --- onnxruntime/core/providers/cuda/version_script.lds | 2 ++ onnxruntime/test/autoep/test_selection.cc | 4 +++- onnxruntime/test/util/file_util.cc | 12 ++++++++++++ onnxruntime/test/util/include/file_util.h | 7 ++++++- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/onnxruntime/core/providers/cuda/version_script.lds b/onnxruntime/core/providers/cuda/version_script.lds index c02a8e4bcf724..7ce96e3e611c0 100644 --- a/onnxruntime/core/providers/cuda/version_script.lds +++ b/onnxruntime/core/providers/cuda/version_script.lds @@ -2,6 +2,8 @@ VERS_1.0 { global: GetProvider; + CreateEpFactories; + ReleaseEpFactory; _binary_*; # Hide everything else. diff --git a/onnxruntime/test/autoep/test_selection.cc b/onnxruntime/test/autoep/test_selection.cc index 4524f0ce50a57..fdcfa8b41365f 100644 --- a/onnxruntime/test/autoep/test_selection.cc +++ b/onnxruntime/test/autoep/test_selection.cc @@ -16,6 +16,7 @@ #include "test/shared_lib/utils.h" #include "test/util/include/api_asserts.h" #include "test/util/include/asserts.h" +#include "test/util/include/file_util.h" extern std::unique_ptr ort_env; @@ -168,7 +169,8 @@ TEST(AutoEpSelection, CpuEP) { TEST(AutoEpSelection, CudaEP) { Ort::KeyValuePairs provider_options; provider_options.Add("prefer_nhwc", "1"); - RunBasicTest(kCudaExecutionProvider, "onnxruntime_providers_cuda", provider_options); + const auto cuda_ep_lib_path = std::filesystem::path{GetSharedLibraryFileName("onnxruntime_providers_cuda")}; + RunBasicTest(kCudaExecutionProvider, cuda_ep_lib_path, provider_options); } #endif diff --git a/onnxruntime/test/util/file_util.cc b/onnxruntime/test/util/file_util.cc index a4507ac0d1db2..bb7d3a472477d 100644 --- a/onnxruntime/test/util/file_util.cc +++ b/onnxruntime/test/util/file_util.cc @@ -12,6 +12,18 @@ namespace onnxruntime { namespace test { +PathString GetSharedLibraryFileName(const PathString& base_library_name) { +#if defined(_WIN32) + constexpr auto kPrefix{ORT_TSTR("")}, kSuffix{ORT_TSTR(".dll")}; +#elif defined(__APPLE__) + constexpr auto kPrefix{ORT_TSTR("lib")}, kSuffix{ORT_TSTR(".dylib")}; +#else + constexpr auto kPrefix{ORT_TSTR("lib")}, kSuffix{ORT_TSTR(".so")}; +#endif + + return PathString{kPrefix} + base_library_name + kSuffix; +} + void DeleteFileFromDisk(const ORTCHAR_T* path) { #ifdef _WIN32 ASSERT_EQ(TRUE, DeleteFileW(path)); diff --git a/onnxruntime/test/util/include/file_util.h b/onnxruntime/test/util/include/file_util.h index 9100f2ce166a9..3c9ee5f6d3a21 100644 --- a/onnxruntime/test/util/include/file_util.h +++ b/onnxruntime/test/util/include/file_util.h @@ -8,6 +8,11 @@ namespace onnxruntime { namespace test { + +// Creates a platform-specific shared library file name from a base library name. +// E.g., "onnxruntime" -> "libonnxruntime.so". +PathString GetSharedLibraryFileName(const PathString& base_library_name); + void CreateTestFile(FILE*& out, std::basic_string& filename_template); void CreateTestFile(int& out, std::basic_string& filename_template); void DeleteFileFromDisk(const ORTCHAR_T* path); @@ -39,4 +44,4 @@ class ScopedFileDeleter { }; } // namespace test -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime From 0894421a6f3d249eda15496e511f86ffa9f4aea0 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 24 Oct 2025 18:19:54 -0700 Subject: [PATCH 19/43] only check one address from posix env GetRuntimePath --- onnxruntime/core/platform/posix/env.cc | 27 +++++++------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/onnxruntime/core/platform/posix/env.cc b/onnxruntime/core/platform/posix/env.cc index 8cc16066b0e61..2059f7a1a631d 100644 --- a/onnxruntime/core/platform/posix/env.cc +++ b/onnxruntime/core/platform/posix/env.cc @@ -556,29 +556,16 @@ class PosixEnv : public Env { } PathString GetRuntimePath() const override { - // Use dladdr() to look up the shared object that contains a particular address. - - // `OrtGetApiBase` is exported by the onnxruntime shared library (libonnxruntime.so/dylib). - // Try to find that symbol's address first. It might be nullptr, e.g., if this code is not built as part of the - // onnxruntime shared library. - const void* const address_from_ort_library = dlsym(RTLD_DEFAULT, "OrtGetApiBase"); - - // Fall back to the address of another symbol in this binary. + // Use dladdr() to look up the file that contains an address from this binary. const void* const address_from_this_binary = reinterpret_cast(Env::Default); - const std::array addresses{address_from_ort_library, address_from_this_binary}; + if (Dl_info dl_info{}; + dladdr(address_from_this_binary, &dl_info) != 0 && dl_info.dli_fname != nullptr) { + LOGS_DEFAULT(VERBOSE) << "Getting runtime path as parent directory of binary: " << dl_info.dli_fname; - for (const void* address : addresses) { - if (Dl_info dl_info{}; - address != nullptr && - dladdr(address, &dl_info) != 0 && - dl_info.dli_fname != nullptr) { - LOGS_DEFAULT(VERBOSE) << "Getting runtime path as parent directory of binary: " << dl_info.dli_fname; - - auto runtime_path = std::filesystem::path{dl_info.dli_fname}.remove_filename(); - runtime_path = std::filesystem::absolute(runtime_path); - return runtime_path; - } + auto runtime_path = std::filesystem::path{dl_info.dli_fname}.remove_filename(); + runtime_path = std::filesystem::absolute(runtime_path); + return runtime_path; } return PathString{}; From 6f0e6b0ed66292f37077289ecfd33c158f60c8c1 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 24 Oct 2025 18:50:33 -0700 Subject: [PATCH 20/43] add PlatformEnvTest.GetRuntimePath test --- onnxruntime/test/platform/env_test.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/onnxruntime/test/platform/env_test.cc b/onnxruntime/test/platform/env_test.cc index 9ea8586af693b..2ef587ef14d63 100644 --- a/onnxruntime/test/platform/env_test.cc +++ b/onnxruntime/test/platform/env_test.cc @@ -3,6 +3,7 @@ #include "core/platform/env.h" +#include #include #include "gtest/gtest.h" @@ -53,5 +54,21 @@ TEST(PlatformEnvTest, GetErrnoInfo) { #pragma warning(pop) #endif } + +TEST(PlatformEnvTest, GetRuntimePath) { + const auto runtime_path_str = Env::Default().GetRuntimePath(); + ASSERT_FALSE(runtime_path_str.empty()); + + const auto runtime_path = std::filesystem::path{runtime_path_str}; + EXPECT_TRUE(runtime_path.is_absolute()); + EXPECT_TRUE(std::filesystem::is_directory(runtime_path)); + + auto is_dir_separator = [](ORTCHAR_T c) { + constexpr std::array dir_separators{ORTCHAR_T{'/'}, std::filesystem::path::preferred_separator}; + return std::find(dir_separators.begin(), dir_separators.end(), c) != dir_separators.end(); + }; + + EXPECT_TRUE(is_dir_separator(runtime_path_str.back())); +} } // namespace test } // namespace onnxruntime From d0aae1efdf116a87ed16040147d3f248774f3a41 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 24 Oct 2025 18:51:04 -0700 Subject: [PATCH 21/43] enable QNN autoep tests --- onnxruntime/core/providers/qnn/version_script.lds | 4 +++- onnxruntime/test/providers/qnn/qnn_basic_test.cc | 12 +++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/onnxruntime/core/providers/qnn/version_script.lds b/onnxruntime/core/providers/qnn/version_script.lds index 094abb3329781..3600a4f8f4b51 100644 --- a/onnxruntime/core/providers/qnn/version_script.lds +++ b/onnxruntime/core/providers/qnn/version_script.lds @@ -1,7 +1,9 @@ #_init and _fini should be local VERS_1.0 { global: - GetProvider; + GetProvider; + CreateEpFactories; + ReleaseEpFactory; # Hide everything else. local: diff --git a/onnxruntime/test/providers/qnn/qnn_basic_test.cc b/onnxruntime/test/providers/qnn/qnn_basic_test.cc index c7b68b7f25a91..b6db4316aeabe 100644 --- a/onnxruntime/test/providers/qnn/qnn_basic_test.cc +++ b/onnxruntime/test/providers/qnn/qnn_basic_test.cc @@ -18,6 +18,7 @@ #include "test/providers/qnn/qnn_test_utils.h" #include "test/util/include/api_asserts.h" +#include "test/util/include/file_util.h" #include "gtest/gtest.h" #include "gmock/gmock.h" @@ -1420,12 +1421,12 @@ TEST_F(QnnHTPBackendTests, LoadingAndUnloadingOfQnnLibrary_FixSegFault) { } #endif // !BUILD_QNN_EP_STATIC_LIB -#if defined(WIN32) && !BUILD_QNN_EP_STATIC_LIB +#if !BUILD_QNN_EP_STATIC_LIB // Tests autoEP feature to automatically select an EP that supports the NPU. -// Currently only works on Windows. TEST_F(QnnHTPBackendTests, AutoEp_PreferNpu) { + const auto qnn_ep_lib_path = GetSharedLibraryFileName(ORT_TSTR("onnxruntime_providers_qnn")); ASSERT_ORTSTATUS_OK(Ort::GetApi().RegisterExecutionProviderLibrary(*ort_env, kQnnExecutionProvider, - ORT_TSTR("onnxruntime_providers_qnn.dll"))); + qnn_ep_lib_path.c_str())); Ort::SessionOptions so; so.SetEpSelectionPolicy(OrtExecutionProviderDevicePolicy_PREFER_NPU); @@ -1438,8 +1439,9 @@ TEST_F(QnnHTPBackendTests, AutoEp_PreferNpu) { } TEST_F(QnnGPUBackendTests, AutoEp_PreferGpu) { + const auto qnn_ep_lib_path = GetSharedLibraryFileName(ORT_TSTR("onnxruntime_providers_qnn")); ASSERT_ORTSTATUS_OK(Ort::GetApi().RegisterExecutionProviderLibrary(*ort_env, kQnnExecutionProvider, - ORT_TSTR("onnxruntime_providers_qnn.dll"))); + qnn_ep_lib_path.c_str())); Ort::SessionOptions so; so.SetEpSelectionPolicy(OrtExecutionProviderDevicePolicy_PREFER_GPU); @@ -1450,7 +1452,7 @@ TEST_F(QnnGPUBackendTests, AutoEp_PreferGpu) { ASSERT_ORTSTATUS_OK(Ort::GetApi().UnregisterExecutionProviderLibrary(*ort_env, kQnnExecutionProvider)); } -#endif // defined(WIN32) && !BUILD_QNN_EP_STATIC_LIB +#endif // !BUILD_QNN_EP_STATIC_LIB // Test whether QNN EP can handle the case where the number of graph inputs and // the number of tensor wrappers do not match. From 9f6e5bbd7ba8919abdb55586ea2c21df45ea6d83 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Mon, 27 Oct 2025 09:21:47 -0700 Subject: [PATCH 22/43] fix path arg --- onnxruntime/test/autoep/test_selection.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/onnxruntime/test/autoep/test_selection.cc b/onnxruntime/test/autoep/test_selection.cc index fdcfa8b41365f..d283d85dcb14e 100644 --- a/onnxruntime/test/autoep/test_selection.cc +++ b/onnxruntime/test/autoep/test_selection.cc @@ -169,7 +169,8 @@ TEST(AutoEpSelection, CpuEP) { TEST(AutoEpSelection, CudaEP) { Ort::KeyValuePairs provider_options; provider_options.Add("prefer_nhwc", "1"); - const auto cuda_ep_lib_path = std::filesystem::path{GetSharedLibraryFileName("onnxruntime_providers_cuda")}; + const auto cuda_ep_lib_path = + std::filesystem::path{GetSharedLibraryFileName(ORT_TSTR("onnxruntime_providers_cuda"))}; RunBasicTest(kCudaExecutionProvider, cuda_ep_lib_path, provider_options); } #endif From 59bc088dbffaf42f60b72f1ec1745470da3890dc Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Mon, 27 Oct 2025 09:22:38 -0700 Subject: [PATCH 23/43] Revert "enable QNN autoep tests" This reverts commit d0aae1efdf116a87ed16040147d3f248774f3a41. --- onnxruntime/core/providers/qnn/version_script.lds | 4 +--- onnxruntime/test/providers/qnn/qnn_basic_test.cc | 12 +++++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/onnxruntime/core/providers/qnn/version_script.lds b/onnxruntime/core/providers/qnn/version_script.lds index 3600a4f8f4b51..094abb3329781 100644 --- a/onnxruntime/core/providers/qnn/version_script.lds +++ b/onnxruntime/core/providers/qnn/version_script.lds @@ -1,9 +1,7 @@ #_init and _fini should be local VERS_1.0 { global: - GetProvider; - CreateEpFactories; - ReleaseEpFactory; + GetProvider; # Hide everything else. local: diff --git a/onnxruntime/test/providers/qnn/qnn_basic_test.cc b/onnxruntime/test/providers/qnn/qnn_basic_test.cc index b6db4316aeabe..c7b68b7f25a91 100644 --- a/onnxruntime/test/providers/qnn/qnn_basic_test.cc +++ b/onnxruntime/test/providers/qnn/qnn_basic_test.cc @@ -18,7 +18,6 @@ #include "test/providers/qnn/qnn_test_utils.h" #include "test/util/include/api_asserts.h" -#include "test/util/include/file_util.h" #include "gtest/gtest.h" #include "gmock/gmock.h" @@ -1421,12 +1420,12 @@ TEST_F(QnnHTPBackendTests, LoadingAndUnloadingOfQnnLibrary_FixSegFault) { } #endif // !BUILD_QNN_EP_STATIC_LIB -#if !BUILD_QNN_EP_STATIC_LIB +#if defined(WIN32) && !BUILD_QNN_EP_STATIC_LIB // Tests autoEP feature to automatically select an EP that supports the NPU. +// Currently only works on Windows. TEST_F(QnnHTPBackendTests, AutoEp_PreferNpu) { - const auto qnn_ep_lib_path = GetSharedLibraryFileName(ORT_TSTR("onnxruntime_providers_qnn")); ASSERT_ORTSTATUS_OK(Ort::GetApi().RegisterExecutionProviderLibrary(*ort_env, kQnnExecutionProvider, - qnn_ep_lib_path.c_str())); + ORT_TSTR("onnxruntime_providers_qnn.dll"))); Ort::SessionOptions so; so.SetEpSelectionPolicy(OrtExecutionProviderDevicePolicy_PREFER_NPU); @@ -1439,9 +1438,8 @@ TEST_F(QnnHTPBackendTests, AutoEp_PreferNpu) { } TEST_F(QnnGPUBackendTests, AutoEp_PreferGpu) { - const auto qnn_ep_lib_path = GetSharedLibraryFileName(ORT_TSTR("onnxruntime_providers_qnn")); ASSERT_ORTSTATUS_OK(Ort::GetApi().RegisterExecutionProviderLibrary(*ort_env, kQnnExecutionProvider, - qnn_ep_lib_path.c_str())); + ORT_TSTR("onnxruntime_providers_qnn.dll"))); Ort::SessionOptions so; so.SetEpSelectionPolicy(OrtExecutionProviderDevicePolicy_PREFER_GPU); @@ -1452,7 +1450,7 @@ TEST_F(QnnGPUBackendTests, AutoEp_PreferGpu) { ASSERT_ORTSTATUS_OK(Ort::GetApi().UnregisterExecutionProviderLibrary(*ort_env, kQnnExecutionProvider)); } -#endif // !BUILD_QNN_EP_STATIC_LIB +#endif // defined(WIN32) && !BUILD_QNN_EP_STATIC_LIB // Test whether QNN EP can handle the case where the number of graph inputs and // the number of tensor wrappers do not match. From b48ef8e12996b24a8bdcad1e64a24c6e7521f0da Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:06:47 -0700 Subject: [PATCH 24/43] skip PlatformEnvTest.GetRuntimePath in WebAssembly build --- onnxruntime/test/platform/env_test.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/onnxruntime/test/platform/env_test.cc b/onnxruntime/test/platform/env_test.cc index 2ef587ef14d63..b43a5835b1f58 100644 --- a/onnxruntime/test/platform/env_test.cc +++ b/onnxruntime/test/platform/env_test.cc @@ -56,6 +56,10 @@ TEST(PlatformEnvTest, GetErrnoInfo) { } TEST(PlatformEnvTest, GetRuntimePath) { +#if defined(__wasm__) + GTEST_SKIP() << "Not supported in WebAssembly build."; +#endif + const auto runtime_path_str = Env::Default().GetRuntimePath(); ASSERT_FALSE(runtime_path_str.empty()); From af3152261a3bf5e8d645b4bf890af626bd527f1c Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:49:09 -0700 Subject: [PATCH 25/43] add test for GetRuntimePath() call from shared library --- cmake/onnxruntime_unittests.cmake | 41 ++++++++++++++++++- .../runtime_path_test_shared_library.cc | 34 +++++++++++++++ .../runtime_path_test_shared_library.def | 3 ++ .../runtime_path_test_shared_library.h | 23 +++++++++++ .../runtime_path_test_shared_library.lds | 6 +++ .../test/shared_lib/test_runtime_path.cc | 28 +++++++++++++ 6 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc create mode 100644 onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.def create mode 100644 onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.h create mode 100644 onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.lds create mode 100644 onnxruntime/test/shared_lib/test_runtime_path.cc diff --git a/cmake/onnxruntime_unittests.cmake b/cmake/onnxruntime_unittests.cmake index 91375d8235d6a..42a9e96c69ef8 100644 --- a/cmake/onnxruntime_unittests.cmake +++ b/cmake/onnxruntime_unittests.cmake @@ -588,6 +588,7 @@ set (onnxruntime_shared_lib_test_SRC ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/test_nontensor_types.cc ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/test_ort_format_models.cc ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/test_run_options.cc + ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/test_runtime_path.cc ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/test_session_options.cc ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/utils.h ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/utils.cc @@ -1518,9 +1519,47 @@ endif() target_link_libraries(onnxruntime_mocked_allocator PRIVATE ${GSL_TARGET}) set_target_properties(onnxruntime_mocked_allocator PROPERTIES FOLDER "ONNXRuntimeTest") + # onnxruntime_runtime_path_test_shared_library + block() + set(onnxruntime_runtime_path_test_shared_library_src + "${TEST_SRC_DIR}/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.h" + "${TEST_SRC_DIR}/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc") + + onnxruntime_add_shared_library(onnxruntime_runtime_path_test_shared_library + ${onnxruntime_runtime_path_test_shared_library_src}) + + target_link_libraries(onnxruntime_runtime_path_test_shared_library PRIVATE onnxruntime_common cpuinfo) + target_include_directories(onnxruntime_runtime_path_test_shared_library PRIVATE ${ONNXRUNTIME_ROOT}) + + if(UNIX) + if (APPLE) + set(onnxruntime_runtime_path_test_shared_library_link_flags "-Xlinker -dead_strip") + elseif (NOT CMAKE_SYSTEM_NAME MATCHES "AIX") + string(CONCAT onnxruntime_runtime_path_test_shared_library_link_flags + "-Xlinker --version-script=${TEST_SRC_DIR}/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.lds " + "-Xlinker --no-undefined -Xlinker --gc-sections -z noexecstack") + endif() + else() + set(onnxruntime_runtime_path_test_shared_library_link_flags + "-DEF:${TEST_SRC_DIR}/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.def") + endif() + + set_property(TARGET onnxruntime_runtime_path_test_shared_library APPEND_STRING PROPERTY LINK_FLAGS + ${onnxruntime_runtime_path_test_shared_library_link_flags}) + + set_target_properties(onnxruntime_runtime_path_test_shared_library PROPERTIES FOLDER "ONNXRuntimeTest") + source_group(TREE ${TEST_SRC_DIR} FILES ${onnxruntime_runtime_path_test_shared_library_src}) + endblock() + ################################################################# # test inference using shared lib - set(onnxruntime_shared_lib_test_LIBS onnxruntime_mocked_allocator onnxruntime_test_utils onnxruntime_common onnx_proto) + set(onnxruntime_shared_lib_test_LIBS + onnxruntime_mocked_allocator + onnxruntime_test_utils + onnxruntime_common + onnx_proto + onnxruntime_runtime_path_test_shared_library) + if(NOT WIN32) if(onnxruntime_USE_SNPE) list(APPEND onnxruntime_shared_lib_test_LIBS onnxruntime_providers_snpe) diff --git a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc new file mode 100644 index 0000000000000..0391aeb14863c --- /dev/null +++ b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc @@ -0,0 +1,34 @@ +#include "runtime_path_test_shared_library.h" + +#include "core/platform/env.h" +#include "core/common/logging/logging.h" +#include "core/platform/logging/make_platform_default_log_sink.h" + +namespace { + +std::basic_string InitializeAndGetRuntimePath() { + using namespace onnxruntime; + + const bool default_filter_user_data = false; + const std::string default_logger_id = "DefaultLogger"; + auto logging_manager = logging::LoggingManager(logging::MakePlatformDefaultLogSink(), + logging::Severity::kVERBOSE, + default_filter_user_data, + logging::LoggingManager::InstanceType::Default, + &default_logger_id); + + auto runtime_path = Env::Default().GetRuntimePath(); + + return runtime_path; +} + +} // namespace + +extern "C" const PATH_CHAR_T* OrtTestGetSharedLibraryRuntimePath(void) { + try { + static const auto runtime_path = InitializeAndGetRuntimePath(); + return runtime_path.c_str(); + } catch (...) { + return nullptr; + } +} diff --git a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.def b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.def new file mode 100644 index 0000000000000..496faee610075 --- /dev/null +++ b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.def @@ -0,0 +1,3 @@ +LIBRARY "onnxruntime_runtime_path_test_shared_library.dll" +EXPORTS + OrtTestGetSharedLibraryRuntimePath @1 diff --git a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.h b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.h new file mode 100644 index 0000000000000..7e7303b530fd7 --- /dev/null +++ b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.h @@ -0,0 +1,23 @@ +#pragma once + +// To make symbols visible on macOS/iOS +#if defined(__APPLE__) +#define EXPORT_SYMBOL __attribute__((visibility("default"))) +#else +#define EXPORT_SYMBOL +#endif + +#if defined(_WIN32) +#define PATH_CHAR_T wchar_t +#else +#define PATH_CHAR_T char +#endif + +extern "C" { +// +// Public symbols +// + +// Gets the runtime path of the shared library - i.e., the shared library file's parent directory. +EXPORT_SYMBOL const PATH_CHAR_T* OrtTestGetSharedLibraryRuntimePath(void); +} diff --git a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.lds b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.lds new file mode 100644 index 0000000000000..4daec4ff8fb5a --- /dev/null +++ b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.lds @@ -0,0 +1,6 @@ +VERS_1.0.0 { + global: + OrtTestGetSharedLibraryRuntimePath; + local: + *; +}; diff --git a/onnxruntime/test/shared_lib/test_runtime_path.cc b/onnxruntime/test/shared_lib/test_runtime_path.cc new file mode 100644 index 0000000000000..70159e17e22d8 --- /dev/null +++ b/onnxruntime/test/shared_lib/test_runtime_path.cc @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#include "gtest/gtest.h" + +#include "test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.h" +#include "test/util/include/file_util.h" + +namespace onnxruntime::test { + +TEST(GetRuntimePathFromSharedLibraryTest, Basic) { + const auto* runtime_path_cstr = OrtTestGetSharedLibraryRuntimePath(); + ASSERT_NE(runtime_path_cstr, nullptr); + + const auto runtime_path = std::filesystem::path{runtime_path_cstr}; + ASSERT_FALSE(runtime_path.empty()); + + ASSERT_TRUE(runtime_path.is_absolute()); + + const auto shared_library_file_name = GetSharedLibraryFileName("onnxruntime_runtime_path_test_shared_library"); + const auto canonical_shared_library_path = std::filesystem::canonical(runtime_path / shared_library_file_name); + + ASSERT_TRUE(std::filesystem::is_regular_file(canonical_shared_library_path)); +} + +} // namespace onnxruntime::test From 2081235b58cd575a13eac64d1fcc5899582346aa Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Thu, 30 Oct 2025 14:26:50 -0700 Subject: [PATCH 26/43] add CMAKE_DL_LIBS to onnxruntime_runtime_path_test_shared_library link libraries --- cmake/onnxruntime_unittests.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/onnxruntime_unittests.cmake b/cmake/onnxruntime_unittests.cmake index 42a9e96c69ef8..6c85fca371340 100644 --- a/cmake/onnxruntime_unittests.cmake +++ b/cmake/onnxruntime_unittests.cmake @@ -1528,7 +1528,8 @@ endif() onnxruntime_add_shared_library(onnxruntime_runtime_path_test_shared_library ${onnxruntime_runtime_path_test_shared_library_src}) - target_link_libraries(onnxruntime_runtime_path_test_shared_library PRIVATE onnxruntime_common cpuinfo) + target_link_libraries(onnxruntime_runtime_path_test_shared_library PRIVATE + onnxruntime_common cpuinfo ${CMAKE_DL_LIBS}) target_include_directories(onnxruntime_runtime_path_test_shared_library PRIVATE ${ONNXRUNTIME_ROOT}) if(UNIX) From 5b395fb36ffe46d66df8513a0987910524352a29 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:24:29 -0700 Subject: [PATCH 27/43] print exception info from OrtTestGetSharedLibraryRuntimePath --- .../runtime_path_test_shared_library.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc index 0391aeb14863c..4acc6749f8779 100644 --- a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc +++ b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc @@ -1,5 +1,8 @@ #include "runtime_path_test_shared_library.h" +#include +#include + #include "core/platform/env.h" #include "core/common/logging/logging.h" #include "core/platform/logging/make_platform_default_log_sink.h" @@ -28,7 +31,8 @@ extern "C" const PATH_CHAR_T* OrtTestGetSharedLibraryRuntimePath(void) { try { static const auto runtime_path = InitializeAndGetRuntimePath(); return runtime_path.c_str(); - } catch (...) { + } catch (const std::exception& e) { + std::cerr << __FUNCTION__ " - caught exception: " << e.what() << "\n"; return nullptr; } } From 7b5e0ee7a9ae0d42b7a37ed7671e109e2a61051b Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:29:03 -0700 Subject: [PATCH 28/43] fix build issue --- .../runtime_path_test_shared_library.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc index 4acc6749f8779..05c2d3c141697 100644 --- a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc +++ b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc @@ -32,7 +32,7 @@ extern "C" const PATH_CHAR_T* OrtTestGetSharedLibraryRuntimePath(void) { static const auto runtime_path = InitializeAndGetRuntimePath(); return runtime_path.c_str(); } catch (const std::exception& e) { - std::cerr << __FUNCTION__ " - caught exception: " << e.what() << "\n"; + std::cerr << __FUNCTION__ << " - caught exception: " << e.what() << "\n"; return nullptr; } } From a382d5f0149b0e20ed274e7600166394fc3e84a6 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Thu, 30 Oct 2025 18:32:44 -0700 Subject: [PATCH 29/43] reorder path update calls - absolute(remove_filename(path)) -> remove_filename(absolute(path)) --- onnxruntime/core/platform/posix/env.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/onnxruntime/core/platform/posix/env.cc b/onnxruntime/core/platform/posix/env.cc index 2059f7a1a631d..34b6b2de64a92 100644 --- a/onnxruntime/core/platform/posix/env.cc +++ b/onnxruntime/core/platform/posix/env.cc @@ -563,8 +563,9 @@ class PosixEnv : public Env { dladdr(address_from_this_binary, &dl_info) != 0 && dl_info.dli_fname != nullptr) { LOGS_DEFAULT(VERBOSE) << "Getting runtime path as parent directory of binary: " << dl_info.dli_fname; - auto runtime_path = std::filesystem::path{dl_info.dli_fname}.remove_filename(); + auto runtime_path = std::filesystem::path{dl_info.dli_fname}; runtime_path = std::filesystem::absolute(runtime_path); + runtime_path.remove_filename(); return runtime_path; } From 348a95498af49bfa657906de8dc3819778872848 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:33:59 -0700 Subject: [PATCH 30/43] add readme --- .../runtime_path_test_shared_library/readme.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 onnxruntime/test/shared_lib/runtime_path_test_shared_library/readme.md diff --git a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/readme.md b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/readme.md new file mode 100644 index 0000000000000..d48d8531662be --- /dev/null +++ b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/readme.md @@ -0,0 +1,9 @@ +`onnxruntime_runtime_path_test_shared_library` is a minimal shared library that exposes a public function which makes a +call to `onnxruntime::Env::GetRuntimePath()` and returns the result. + +We want to ensure that `Env::GetRuntimePath()` returns the directory of the shared library it is called from, e.g., +the onnxruntime shared library. It is used to get paths to other files which may be co-located with the shared library. + +Directly calling `Env::GetRuntimePath()` from a unit test program where it is statically linked in is a slightly +different setup. We use this minimal shared library to test the `Env::GetRuntimePath()` functionality in a setup that +is closer to the real-world usage. From 21815fa51996576ba4cb5d15a5140272074fc417 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:34:37 -0700 Subject: [PATCH 31/43] add copyright comments, update shared lib test --- .../runtime_path_test_shared_library.cc | 3 ++ .../runtime_path_test_shared_library.h | 3 ++ .../test/shared_lib/test_runtime_path.cc | 30 ++++++++++++++++--- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc index 05c2d3c141697..6c831c7e3703b 100644 --- a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc +++ b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #include "runtime_path_test_shared_library.h" #include diff --git a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.h b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.h index 7e7303b530fd7..072c3e473c8ca 100644 --- a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.h +++ b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once // To make symbols visible on macOS/iOS diff --git a/onnxruntime/test/shared_lib/test_runtime_path.cc b/onnxruntime/test/shared_lib/test_runtime_path.cc index 70159e17e22d8..621d006a8659a 100644 --- a/onnxruntime/test/shared_lib/test_runtime_path.cc +++ b/onnxruntime/test/shared_lib/test_runtime_path.cc @@ -1,26 +1,48 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include #include +#include #include "gtest/gtest.h" +#include "core/common/path_string.h" + #include "test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.h" #include "test/util/include/file_util.h" namespace onnxruntime::test { +namespace { +bool IsDirectorySeparator(PathChar c) { + constexpr std::array dir_separators{ORT_TSTR('/'), std::filesystem::path::preferred_separator}; + return std::find(dir_separators.begin(), dir_separators.end(), c) != dir_separators.end(); +} +} // namespace + TEST(GetRuntimePathFromSharedLibraryTest, Basic) { const auto* runtime_path_cstr = OrtTestGetSharedLibraryRuntimePath(); ASSERT_NE(runtime_path_cstr, nullptr); - const auto runtime_path = std::filesystem::path{runtime_path_cstr}; - ASSERT_FALSE(runtime_path.empty()); + const auto runtime_path_str = std::basic_string_view{runtime_path_cstr}; + ASSERT_FALSE(runtime_path_str.empty()); + ASSERT_TRUE(IsDirectorySeparator(runtime_path_str.back())); + const auto runtime_path = std::filesystem::path{runtime_path_str}; ASSERT_TRUE(runtime_path.is_absolute()); - const auto shared_library_file_name = GetSharedLibraryFileName("onnxruntime_runtime_path_test_shared_library"); - const auto canonical_shared_library_path = std::filesystem::canonical(runtime_path / shared_library_file_name); + // Check that the runtime path contains the shared library file. + const auto shared_library_file_name = + GetSharedLibraryFileName(ORT_TSTR("onnxruntime_runtime_path_test_shared_library")); + + const auto shared_library_path = runtime_path / shared_library_file_name; + + // Get canonical path to ensure it exists and resolve any symlinks. + std::error_code ec{}; + const auto canonical_shared_library_path = std::filesystem::canonical(shared_library_path, ec); + ASSERT_FALSE(ec) << "Failed to get canonical path to shared library file '" << shared_library_path + << "'. Error: " << ec.message(); ASSERT_TRUE(std::filesystem::is_regular_file(canonical_shared_library_path)); } From 2d42cba2a1cb7e2f410872f79a7c80e90a69f062 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:35:59 -0700 Subject: [PATCH 32/43] remove GetRuntimePath test that tests statically linked function --- onnxruntime/test/platform/env_test.cc | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/onnxruntime/test/platform/env_test.cc b/onnxruntime/test/platform/env_test.cc index b43a5835b1f58..be7b0ce397c48 100644 --- a/onnxruntime/test/platform/env_test.cc +++ b/onnxruntime/test/platform/env_test.cc @@ -55,24 +55,5 @@ TEST(PlatformEnvTest, GetErrnoInfo) { #endif } -TEST(PlatformEnvTest, GetRuntimePath) { -#if defined(__wasm__) - GTEST_SKIP() << "Not supported in WebAssembly build."; -#endif - - const auto runtime_path_str = Env::Default().GetRuntimePath(); - ASSERT_FALSE(runtime_path_str.empty()); - - const auto runtime_path = std::filesystem::path{runtime_path_str}; - EXPECT_TRUE(runtime_path.is_absolute()); - EXPECT_TRUE(std::filesystem::is_directory(runtime_path)); - - auto is_dir_separator = [](ORTCHAR_T c) { - constexpr std::array dir_separators{ORTCHAR_T{'/'}, std::filesystem::path::preferred_separator}; - return std::find(dir_separators.begin(), dir_separators.end(), c) != dir_separators.end(); - }; - - EXPECT_TRUE(is_dir_separator(runtime_path_str.back())); -} } // namespace test } // namespace onnxruntime From 873bda0ff4f8654755b4001ca09697919d05f9f6 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:59:49 -0700 Subject: [PATCH 33/43] remove unused EpFactoryVirtualGpu::default_logger_ data member --- .../autoep/library/example_plugin_ep_virt_gpu/ep_factory.cc | 6 +++--- .../autoep/library/example_plugin_ep_virt_gpu/ep_factory.h | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep_factory.cc b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep_factory.cc index da8c2b3ed7c6b..d841e70187f70 100644 --- a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep_factory.cc +++ b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep_factory.cc @@ -11,13 +11,13 @@ #include "../plugin_ep_utils.h" EpFactoryVirtualGpu::EpFactoryVirtualGpu(const OrtApi& ort_api, const OrtEpApi& ep_api, - const OrtModelEditorApi& model_editor_api, const OrtLogger& default_logger) + const OrtModelEditorApi& model_editor_api, + const OrtLogger& /*default_logger*/) : OrtEpFactory{}, ort_api_(ort_api), ep_api_(ep_api), model_editor_api_(model_editor_api), - allow_virtual_devices_{false}, - default_logger_{default_logger} { + allow_virtual_devices_{false} { ort_version_supported = ORT_API_VERSION; // set to the ORT version we were compiled with. GetName = GetNameImpl; GetVendor = GetVendorImpl; diff --git a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep_factory.h b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep_factory.h index 2357b3676aa79..1d708d9b40963 100644 --- a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep_factory.h +++ b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep_factory.h @@ -73,7 +73,6 @@ class EpFactoryVirtualGpu : public OrtEpFactory { const OrtEpApi& ep_api_; const OrtModelEditorApi& model_editor_api_; bool allow_virtual_devices_{false}; - const OrtLogger& default_logger_; OrtHardwareDevice* virtual_hw_device_{}; const std::string ep_name_{"EpVirtualGpu"}; const std::string vendor_{"Contoso2"}; // EP vendor name From 7305296e645f208575f098bf56a15228096c0fb7 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 18:01:42 -0700 Subject: [PATCH 34/43] remove unused EpVirtualGpu::factory_ data member --- .../test/autoep/library/example_plugin_ep_virt_gpu/ep.cc | 4 ++-- .../test/autoep/library/example_plugin_ep_virt_gpu/ep.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc index 99a580f5577f7..6e93ef31a6fdd 100644 --- a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc +++ b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc @@ -48,9 +48,9 @@ struct AddNodeComputeInfo : OrtNodeComputeInfo { EpVirtualGpu& ep; }; -EpVirtualGpu::EpVirtualGpu(EpFactoryVirtualGpu& factory, const EpVirtualGpu::Config& config, const OrtLogger& logger) +EpVirtualGpu::EpVirtualGpu(EpFactoryVirtualGpu& /*factory*/, const EpVirtualGpu::Config& config, + const OrtLogger& logger) : OrtEp{}, // explicitly call the struct ctor to ensure all optional values are default initialized - factory_{factory}, config_{config}, ort_api_{factory.GetOrtApi()}, ep_api_{factory.GetEpApi()}, diff --git a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.h b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.h index da7bb05d79e62..1a217c6e94370 100644 --- a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.h +++ b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.h @@ -51,7 +51,6 @@ class EpVirtualGpu : public OrtEp { OrtStatus* CreateEpContextNodes(gsl::span fused_nodes, /*out*/ gsl::span ep_context_nodes); - EpFactoryVirtualGpu& factory_; Config config_{}; const OrtApi& ort_api_; const OrtEpApi& ep_api_; From 95f0d0b9517a0a5bb6fc83e0dd04e17ff63d8e89 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 18:06:06 -0700 Subject: [PATCH 35/43] use lambda capture [&] to avoid clang warning --- onnxruntime/test/autoep/test_registration.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/onnxruntime/test/autoep/test_registration.cc b/onnxruntime/test/autoep/test_registration.cc index 63f691a13a896..7415c5e138874 100644 --- a/onnxruntime/test/autoep/test_registration.cc +++ b/onnxruntime/test/autoep/test_registration.cc @@ -33,7 +33,7 @@ TEST(OrtEpLibrary, LoadUnloadPluginLibrary) { ASSERT_ORTSTATUS_OK(Ort::GetApi().GetEpDevices(*ort_env, &ep_devices, &num_devices)); // should be one device for the example EP auto num_test_ep_devices = std::count_if(ep_devices, ep_devices + num_devices, - [&ep_name, &c_api](const OrtEpDevice* device) { + [&](const OrtEpDevice* device) { return c_api->EpDevice_EpName(device) == ep_name; }); ASSERT_EQ(num_test_ep_devices, 1) << "Expected an OrtEpDevice to have been created by the test library."; @@ -55,7 +55,7 @@ TEST(OrtEpLibrary, LoadUnloadPluginLibraryCxxApi) { // should be one device for the example EP auto test_ep_device = std::find_if(ep_devices.begin(), ep_devices.end(), - [&ep_name](Ort::ConstEpDevice& device) { + [&](Ort::ConstEpDevice& device) { return device.EpName() == ep_name; }); ASSERT_NE(test_ep_device, ep_devices.end()) << "Expected an OrtEpDevice to have been created by the test library."; @@ -94,12 +94,12 @@ TEST(OrtEpLibrary, LoadUnloadPluginVirtGpuLibraryCxxApi) { const std::string& registration_name = "example_plugin_ep_virt_gpu"; const std::string& ep_name = Utils::example_ep_virt_gpu_info.ep_name; - auto get_plugin_ep_devices = [&ep_name]() -> std::vector { + auto get_plugin_ep_devices = [&]() -> std::vector { std::vector all_ep_devices = ort_env->GetEpDevices(); std::vector ep_devices; std::copy_if(all_ep_devices.begin(), all_ep_devices.end(), std::back_inserter(ep_devices), - [&ep_name](Ort::ConstEpDevice& device) { + [&](Ort::ConstEpDevice& device) { return device.EpName() == ep_name; }); From 657ddaee9da364035d28e50b38be531473eedd62 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 18:08:09 -0700 Subject: [PATCH 36/43] add libonnxruntime_runtime_path_test_shared_library.so to shared libs to copy to android emulator --- tools/ci_build/build.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index ec46281be756d..4f5ed84aaaf87 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -1609,6 +1609,7 @@ def dump_logs_on_failure(): "libcustom_op_get_const_input_test_library.so", "libcustom_op_library.so", "libexample_plugin_ep.so", + "libonnxruntime_runtime_path_test_shared_library.so", "libonnxruntime.so", ] From f889090917bd73e230ef249552da8292a8183eab Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 18:11:30 -0700 Subject: [PATCH 37/43] add GSL to example_plugin_ep_virt_gpu link libraries --- cmake/onnxruntime_unittests.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/onnxruntime_unittests.cmake b/cmake/onnxruntime_unittests.cmake index b74d050296a2d..d96ade9d32b9e 100644 --- a/cmake/onnxruntime_unittests.cmake +++ b/cmake/onnxruntime_unittests.cmake @@ -2063,7 +2063,7 @@ if (onnxruntime_BUILD_SHARED_LIB AND "${TEST_SRC_DIR}/autoep/library/example_plugin_ep_virt_gpu/ep.cc") onnxruntime_add_shared_library_module(example_plugin_ep_virt_gpu ${onnxruntime_autoep_test_example_plugin_ep_virt_gpu_src}) target_include_directories(example_plugin_ep_virt_gpu PRIVATE ${REPO_ROOT}/include/onnxruntime/core/session) - target_link_libraries(example_plugin_ep_virt_gpu PRIVATE onnxruntime) + target_link_libraries(example_plugin_ep_virt_gpu PRIVATE onnxruntime ${GSL_TARGET}) if(UNIX) if (APPLE) From c4b05b9af9d19670b75a897230808a30c644c58d Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 18:13:24 -0700 Subject: [PATCH 38/43] loop var const ref --- .../test/autoep/library/example_plugin_ep_virt_gpu/ep.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc index 6e93ef31a6fdd..037ccee130054 100644 --- a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc +++ b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc @@ -204,7 +204,7 @@ OrtStatus* EpVirtualGpu::CreateEpContextNodes(gsl::span fused_no std::vector value_names; value_names.reserve(value_infos.size()); - for (const auto vi : value_infos) { + for (const auto& vi : value_infos) { value_names.push_back(vi.GetName()); } From 88a5e1cffacc7fc72885a7ebd3634b34456014f9 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 18:19:38 -0700 Subject: [PATCH 39/43] remove .dll from base shared lib name --- onnxruntime/test/autoep/test_autoep_utils.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onnxruntime/test/autoep/test_autoep_utils.cc b/onnxruntime/test/autoep/test_autoep_utils.cc index 98fca1957eceb..07e7c12c4ad99 100644 --- a/onnxruntime/test/autoep/test_autoep_utils.cc +++ b/onnxruntime/test/autoep/test_autoep_utils.cc @@ -23,7 +23,7 @@ const Utils::ExamplePluginInfo Utils::example_ep_info( "example_ep"); const Utils::ExamplePluginInfo Utils::example_ep_virt_gpu_info( - GetSharedLibraryFileName(ORT_TSTR("example_plugin_ep_virt_gpu.dll")), + GetSharedLibraryFileName(ORT_TSTR("example_plugin_ep_virt_gpu")), "example_plugin_ep_virt_gpu.virtual", // Ends in ".virtual" to allow creation of virtual devices. // This EP's name is hardcoded to the following "EpVirtualGpu"); From 5cabd69a419b24a5cd16ba188f9650f2334ae286 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 18:52:19 -0700 Subject: [PATCH 40/43] uncomment factory parameter - oops --- .../test/autoep/library/example_plugin_ep_virt_gpu/ep.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc index 037ccee130054..97663c52cbe27 100644 --- a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc +++ b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc @@ -48,7 +48,7 @@ struct AddNodeComputeInfo : OrtNodeComputeInfo { EpVirtualGpu& ep; }; -EpVirtualGpu::EpVirtualGpu(EpFactoryVirtualGpu& /*factory*/, const EpVirtualGpu::Config& config, +EpVirtualGpu::EpVirtualGpu(EpFactoryVirtualGpu& factory, const EpVirtualGpu::Config& config, const OrtLogger& logger) : OrtEp{}, // explicitly call the struct ctor to ensure all optional values are default initialized config_{config}, From 64c2cec9e8f810fb2b2f9efda1d47a199caeb4ed Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 20:04:31 -0700 Subject: [PATCH 41/43] handle no exception build --- .../runtime_path_test_shared_library.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc index 6c831c7e3703b..f2198dd014b6e 100644 --- a/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc +++ b/onnxruntime/test/shared_lib/runtime_path_test_shared_library/runtime_path_test_shared_library.cc @@ -31,11 +31,17 @@ std::basic_string InitializeAndGetRuntimePath() { } // namespace extern "C" const PATH_CHAR_T* OrtTestGetSharedLibraryRuntimePath(void) { +#if !defined(ORT_NO_EXCEPTIONS) try { +#endif + static const auto runtime_path = InitializeAndGetRuntimePath(); return runtime_path.c_str(); + +#if !defined(ORT_NO_EXCEPTIONS) } catch (const std::exception& e) { std::cerr << __FUNCTION__ << " - caught exception: " << e.what() << "\n"; return nullptr; } +#endif } From b8368f01b4d3641ab8d38727bb4bb94ac5eb229c Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Fri, 31 Oct 2025 20:05:48 -0700 Subject: [PATCH 42/43] add example_plugin_ep_virt_gpu to shared lib list --- tools/ci_build/build.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index 4f5ed84aaaf87..5d532753d930c 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -1608,6 +1608,7 @@ def dump_logs_on_failure(): shared_libraries = [ "libcustom_op_get_const_input_test_library.so", "libcustom_op_library.so", + "libexample_plugin_ep_virt_gpu.so", "libexample_plugin_ep.so", "libonnxruntime_runtime_path_test_shared_library.so", "libonnxruntime.so", From 6d25cb11cf94f44b3fdb456c457671dc2a3d03b5 Mon Sep 17 00:00:00 2001 From: edgchen1 <18449977+edgchen1@users.noreply.github.com> Date: Mon, 3 Nov 2025 10:35:00 -0800 Subject: [PATCH 43/43] cast to AddNodeComputeInfo* before delete --- .../test/autoep/library/example_plugin_ep_virt_gpu/ep.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc index 97663c52cbe27..590e494fbd787 100644 --- a/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc +++ b/onnxruntime/test/autoep/library/example_plugin_ep_virt_gpu/ep.cc @@ -274,7 +274,7 @@ void ORT_API_CALL EpVirtualGpu::ReleaseNodeComputeInfosImpl(OrtEp* this_ptr, size_t num_node_compute_infos) noexcept { (void)this_ptr; for (size_t i = 0; i < num_node_compute_infos; i++) { - delete node_compute_infos[i]; + delete static_cast(node_compute_infos[i]); } }