From 7904e6bbf125718de6c5419401b7b4c0b6e15784 Mon Sep 17 00:00:00 2001 From: Stephan Seitz Date: Fri, 22 Aug 2025 10:35:06 +0200 Subject: [PATCH 1/6] [EP ABI]: add bus_id to GPU metadata on Linux --- onnxruntime/core/platform/linux/device_discovery.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/onnxruntime/core/platform/linux/device_discovery.cc b/onnxruntime/core/platform/linux/device_discovery.cc index e9c45a6966ef8..8a0093ef7b28f 100644 --- a/onnxruntime/core/platform/linux/device_discovery.cc +++ b/onnxruntime/core/platform/linux/device_discovery.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "core/common/common.h" @@ -125,6 +126,7 @@ Status GetGpuDeviceFromSysfs(const GpuSysfsPathInfo& path_info, OrtHardwareDevic gpu_device.vendor_id = vendor_id; // TODO vendor name + gpu_device.vendor = OrtDevice::VendorIdToString(gpu_device.vendor_id); // device id uint16_t device_id{}; @@ -139,6 +141,7 @@ Status GetGpuDeviceFromSysfs(const GpuSysfsPathInfo& path_info, OrtHardwareDevic is_gpu_discrete.has_value()) { gpu_device.metadata.Add("Discrete", (*is_gpu_discrete ? "1" : "0")); } + gpu_device.metadata.Add("bus_id", std::filesystem::read_symlink(sysfs_path / "device").filename().string()); // e.g. 0000:65:00.0 gpu_device.type = OrtHardwareDeviceType_GPU; From 33de4ed4daf41dabf037ad8ed7a3fdc793249be5 Mon Sep 17 00:00:00 2001 From: Stephan Seitz Date: Fri, 22 Aug 2025 13:12:30 +0200 Subject: [PATCH 2/6] [EP ABI]: set GPU vendor on Linux --- .../onnxruntime/core/framework/ortdevice.h | 21 +++++++++++++++++++ .../core/platform/linux/device_discovery.cc | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/include/onnxruntime/core/framework/ortdevice.h b/include/onnxruntime/core/framework/ortdevice.h index 935be9c3f00c7..2d8c020f21714 100644 --- a/include/onnxruntime/core/framework/ortdevice.h +++ b/include/onnxruntime/core/framework/ortdevice.h @@ -65,6 +65,27 @@ struct OrtDevice { INTEL = 0x8086, // OpenVINO }; + constexpr static const char* VendorIdToString(OrtDevice::VendorId vendorId) { + switch (vendorId) { + case OrtDevice::VendorIds::AMD: + return "AMD"; + case OrtDevice::VendorIds::NVIDIA: + return "NVIDIA"; + case OrtDevice::VendorIds::ARM: + return "ARM"; + case OrtDevice::VendorIds::MICROSOFT: + return "MICROSOFT"; + case OrtDevice::VendorIds::HUAWEI: + return "HUAWEI"; + case OrtDevice::VendorIds::QUALCOMM: + return "QUALCOMM"; + case OrtDevice::VendorIds::INTEL: + return "INTEL"; + default: + return ""; + } + } + constexpr OrtDevice(DeviceType device_type_, MemoryType memory_type_, VendorId vendor_id_, DeviceId device_id_, Alignment alignment) /*noexcept*/ : device_type(device_type_), diff --git a/onnxruntime/core/platform/linux/device_discovery.cc b/onnxruntime/core/platform/linux/device_discovery.cc index 8a0093ef7b28f..80b7603969b9d 100644 --- a/onnxruntime/core/platform/linux/device_discovery.cc +++ b/onnxruntime/core/platform/linux/device_discovery.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "core/platform/device_discovery.h" +#include "core/framework/ortdevice.h" #include #include @@ -125,7 +126,6 @@ Status GetGpuDeviceFromSysfs(const GpuSysfsPathInfo& path_info, OrtHardwareDevic ORT_RETURN_IF_ERROR(ReadValueFromFile(vendor_id_path, vendor_id)); gpu_device.vendor_id = vendor_id; - // TODO vendor name gpu_device.vendor = OrtDevice::VendorIdToString(gpu_device.vendor_id); // device id From 8752206e3ab993ac643667e8d87117df08ba87ce Mon Sep 17 00:00:00 2001 From: Stephan Seitz Date: Thu, 21 Aug 2025 19:33:31 +0200 Subject: [PATCH 3/6] [NV TRT RTX EP]: expose same symbols under Linux as under Windows --- onnxruntime/core/providers/nv_tensorrt_rtx/version_script.lds | 2 ++ 1 file changed, 2 insertions(+) diff --git a/onnxruntime/core/providers/nv_tensorrt_rtx/version_script.lds b/onnxruntime/core/providers/nv_tensorrt_rtx/version_script.lds index 094abb3329781..251e39e089275 100644 --- a/onnxruntime/core/providers/nv_tensorrt_rtx/version_script.lds +++ b/onnxruntime/core/providers/nv_tensorrt_rtx/version_script.lds @@ -2,6 +2,8 @@ VERS_1.0 { global: GetProvider; + CreateEpFactories; + ReleaseEpFactory; # Hide everything else. local: From b2734d96b10a680072b85a80addb92fc49a43407 Mon Sep 17 00:00:00 2001 From: Stephan Seitz Date: Thu, 21 Aug 2025 19:36:26 +0200 Subject: [PATCH 4/6] [NV TRT RTX EP]: add support for OrtHardwareDevice on Linux --- .../nv_tensorrt_rtx/nv_provider_factory.cc | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/onnxruntime/core/providers/nv_tensorrt_rtx/nv_provider_factory.cc b/onnxruntime/core/providers/nv_tensorrt_rtx/nv_provider_factory.cc index c3fbccef84883..74a36a73f12e3 100644 --- a/onnxruntime/core/providers/nv_tensorrt_rtx/nv_provider_factory.cc +++ b/onnxruntime/core/providers/nv_tensorrt_rtx/nv_provider_factory.cc @@ -5,6 +5,7 @@ #include "core/providers/shared_library/provider_api.h" #include "nv_provider_factory.h" #include +#include #include "nv_execution_provider.h" #include "nv_provider_factory_creator.h" #include "nv_data_transfer.h" @@ -575,6 +576,7 @@ struct NvTensorRtRtxEpFactory : OrtEpFactory { * @return True if the device is a supported NVIDIA GPU, false otherwise. */ bool IsOrtHardwareDeviceSupported(const OrtHardwareDevice& device) { +#if _WIN32 const auto& metadata_entries = device.metadata.Entries(); const auto it = metadata_entries.find("LUID"); if (it == metadata_entries.end()) { @@ -616,6 +618,25 @@ struct NvTensorRtRtxEpFactory : OrtEpFactory { } return false; +#else + const auto& metadata_entries = device.metadata.Entries(); + const auto it = metadata_entries.find("bus_id"); + if (it == metadata_entries.end()) { + return false; + } + auto& target_id = it->second; + int cuda_device_idx = 0; + if (cudaSuccess != cudaDeviceGetByPCIBusId(&cuda_device_idx, target_id.c_str())) { + return false; + } + + cudaDeviceProp prop; + if (cudaGetDeviceProperties(&prop, cuda_device_idx) != cudaSuccess) { + return false; + } + // Ampere architecture or newer is required. + return prop.major >= 8; +#endif } // Creates and returns OrtEpDevice instances for all OrtHardwareDevices that this factory supports. From 7d1c75f48d935039c0ca8293f4ea897eefee237e Mon Sep 17 00:00:00 2001 From: Stephan Seitz Date: Fri, 29 Aug 2025 12:14:47 +0200 Subject: [PATCH 5/6] [NV TRT RTX EP]: enable Windows-only tests on Linux --- .../test/providers/nv_tensorrt_rtx/nv_basic_test.cc | 8 ++++---- .../test/providers/nv_tensorrt_rtx/nv_ep_context_test.cc | 4 ---- .../providers/nv_tensorrt_rtx/test_nv_trt_rtx_ep_util.cc | 2 -- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/onnxruntime/test/providers/nv_tensorrt_rtx/nv_basic_test.cc b/onnxruntime/test/providers/nv_tensorrt_rtx/nv_basic_test.cc index d8cc56d738175..d267fcb9adf27 100644 --- a/onnxruntime/test/providers/nv_tensorrt_rtx/nv_basic_test.cc +++ b/onnxruntime/test/providers/nv_tensorrt_rtx/nv_basic_test.cc @@ -216,7 +216,6 @@ INSTANTIATE_TEST_SUITE_P(NvExecutionProviderTest, TypeTests, ), [](const testing::TestParamInfo& info) { return getTypeAsName(info.param); }); -#ifdef _WIN32 static bool SessionHasEp(Ort::Session& session, const char* ep_name) { // Access the underlying InferenceSession. const OrtSession* ort_session = session; @@ -233,7 +232,6 @@ static bool SessionHasEp(Ort::Session& session, const char* ep_name) { } // Tests autoEP feature to automatically select an EP that supports the GPU. -// Currently only works on Windows. TEST(NvExecutionProviderTest, AutoEp_PreferGpu) { PathString model_name = ORT_TSTR("nv_execution_provider_auto_ep.onnx"); std::string graph_name = "test"; @@ -243,7 +241,11 @@ TEST(NvExecutionProviderTest, AutoEp_PreferGpu) { CreateBaseModel(model_name, graph_name, dims); { +#if _WIN32 ort_env->RegisterExecutionProviderLibrary(kNvTensorRTRTXExecutionProvider, ORT_TSTR("onnxruntime_providers_nv_tensorrt_rtx.dll")); +#else + ort_env->RegisterExecutionProviderLibrary(kNvTensorRTRTXExecutionProvider, ORT_TSTR("libonnxruntime_providers_nv_tensorrt_rtx.so")); +#endif Ort::SessionOptions so; so.SetEpSelectionPolicy(OrtExecutionProviderDevicePolicy_PREFER_GPU); @@ -398,7 +400,5 @@ TEST(NvExecutionProviderTest, DataTransfer) { device_tensor = Ort::Value(); } -#endif - } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/providers/nv_tensorrt_rtx/nv_ep_context_test.cc b/onnxruntime/test/providers/nv_tensorrt_rtx/nv_ep_context_test.cc index ac24dcb70c1dd..bcdfd18407ca8 100644 --- a/onnxruntime/test/providers/nv_tensorrt_rtx/nv_ep_context_test.cc +++ b/onnxruntime/test/providers/nv_tensorrt_rtx/nv_ep_context_test.cc @@ -14,7 +14,6 @@ namespace test { RegisteredEpDeviceUniquePtr AppendTrtEtxEP(Ort::SessionOptions& session_options, std::unordered_map& option_map) { RegisteredEpDeviceUniquePtr nv_tensorrt_rtx_ep; -#ifdef _WIN32 /// Since this test runs after other tests that use registration interface this test has to use it as well /// windows as otherwise the kernel registry inside the EP will not be populated. The legacy APis ony call the initialize once. Utils::RegisterAndGetNvTensorRtRtxEp(*ort_env, nv_tensorrt_rtx_ep); @@ -26,9 +25,6 @@ RegisteredEpDeviceUniquePtr AppendTrtEtxEP(Ort::SessionOptions& session_options, } } session_options.AppendExecutionProvider_V2(*ort_env, {selected_device}, option_map); -#else - session_options.AppendExecutionProvider(onnxruntime::kNvTensorRTRTXExecutionProvider, option_map); -#endif return nv_tensorrt_rtx_ep; } diff --git a/onnxruntime/test/providers/nv_tensorrt_rtx/test_nv_trt_rtx_ep_util.cc b/onnxruntime/test/providers/nv_tensorrt_rtx/test_nv_trt_rtx_ep_util.cc index 3a91fc1ba09bb..2132b08533c11 100644 --- a/onnxruntime/test/providers/nv_tensorrt_rtx/test_nv_trt_rtx_ep_util.cc +++ b/onnxruntime/test/providers/nv_tensorrt_rtx/test_nv_trt_rtx_ep_util.cc @@ -22,7 +22,6 @@ namespace onnxruntime { namespace test { -#ifdef _WIN32 Utils::NvTensorRtRtxEpInfo Utils::nv_tensorrt_rtx_ep_info; @@ -59,7 +58,6 @@ void Utils::RegisterAndGetNvTensorRtRtxEp(Ort::Env& env, RegisteredEpDeviceUniqu c_api.UnregisterExecutionProviderLibrary(env, nv_tensorrt_rtx_ep_info.registration_name.c_str()); }); } -#endif // _WIN32 void CreateBaseModel(const PathString& model_name, std::string graph_name, From b4a38fcb8c875f091979dc2ed6e5c7185b0e5306 Mon Sep 17 00:00:00 2001 From: Stephan Seitz Date: Tue, 14 Oct 2025 17:26:15 +0200 Subject: [PATCH 6/6] [CORE]: Implement PosixEnv::GetRuntimePath We try to follow the implementation of WindowsEnv which resolves the runtime directory as the directory of the current DLL (onnxruntime) or executable for static linkage. --- onnxruntime/core/platform/posix/env.cc | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/onnxruntime/core/platform/posix/env.cc b/onnxruntime/core/platform/posix/env.cc index fed697ea962bc..5c3e46db5253e 100644 --- a/onnxruntime/core/platform/posix/env.cc +++ b/onnxruntime/core/platform/posix/env.cc @@ -26,6 +26,7 @@ limitations under the License. #include #include #include +#include #if !defined(_AIX) #include #endif @@ -591,6 +592,46 @@ class PosixEnv : public Env { char* val = getenv(var_name.c_str()); return val == NULL ? std::string() : std::string(val); } + // Return the path of the executable/shared library for the current running code. This is to make it + // possible to load other shared libraries installed next to our core runtime code. + PathString GetRuntimePath() const override { + Dl_info dl_info{}; + // Must be one of the symbols exported in libonnxruntime.{so,dynlib}. + void* symbol_from_this_library = dlsym(RTLD_DEFAULT, "OrtGetApiBase"); + // We will find OrtGetApiBase if onnxruntime is loaded as a shared library + if (dladdr(symbol_from_this_library, &dl_info) && dl_info.dli_fname) { + return PathString(dl_info.dli_fname) + "/"; + } else { + // else use path of current executable to mirror Windows behavior +#if __linux__ + return PathString(std::filesystem::read_symlink(std::filesystem::path("/proc/self/exe")).parent_path()) + "/"; +#else + // TODO: MacOS could use _NSGetExecutablePath, but this needs to be tested! + return PathString(); +#endif + } + } + + + // Return the path of the executable/shared library for the current running code. This is to make it + // possible to load other shared libraries installed next to our core runtime code. + PathString GetRuntimePath() const override { + Dl_info dl_info{}; + // Must be one of the symbols exported in libonnxruntime.{so,dynlib}. + void* symbol_from_this_library = dlsym(RTLD_DEFAULT, "OrtGetApiBase"); + // We will find OrtGetApiBase if onnxruntime is loaded as a shared library + if (dladdr(symbol_from_this_library, &dl_info) && dl_info.dli_fname) { + return PathString(dl_info.dli_fname) + "/"; + } else { + // else use path of current executable to mirror Windows behavior +#if __linux__ + return PathString(std::filesystem::read_symlink(std::filesystem::path("/proc/self/exe")).parent_path()) + "/"; +#else + // TODO: MacOS could use _NSGetExecutablePath, but this needs to be tested! + return PathString(); +#endif + } + } private: Telemetry telemetry_provider_;