Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions include/onnxruntime/core/session/onnxruntime_c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -7005,6 +7005,77 @@ struct OrtApi {

/// @}

/// \name Model Compatibility APIs
/// @{

/** \brief Extract EP compatibility info from a precompiled model file.
*
* Parses the model file to extract the compatibility info string for a specific execution provider
* from the model's metadata properties. This is only applicable to models that have been precompiled
* for an EP (e.g., via OrtCompileApi). Standard ONNX models do not contain this information.
*
* The compatibility info string must be valid UTF-8 without embedded NUL characters.
*
* \note This API performs standalone model parsing, separate from session creation. This means
* the protobuf parsing cost is incurred here and again during session creation. It is intended
* for scenarios where applications need to check compatibility before deciding whether to proceed
* with session creation, such as providing early user feedback.
*
* \note This operation parses the full ONNX ModelProto from disk. For very large models, consider
* using GetCompatibilityInfoFromModelBytes with a pre-loaded buffer if the model is already in memory.
*
* The compatibility info can then be passed to GetModelCompatibilityForEpDevices to check if a
* precompiled model is compatible with the current system.
*
* \param[in] model_path Path to the ONNX model file.
* \param[in] ep_type The execution provider type string. Must be non-empty.
* Use OrtApi::EpDevice_EpName to get this value from an OrtEpDevice.
* \param[in] allocator Allocator to use for the output string. Use OrtApi::GetAllocatorWithDefaultOptions.
* \param[out] compatibility_info Output pointer to the compatibility info string.
* Returns nullptr if no compatibility info exists for the specified EP.
* Caller must free with OrtApi::AllocatorFree when non-null.
*
* \snippet{doc} snippets.dox OrtStatus Return Value
*
* \since Version 1.24.
*/
ORT_API2_STATUS(GetCompatibilityInfoFromModel,
_In_ const ORTCHAR_T* model_path,
_In_ const char* ep_type,
_Inout_ OrtAllocator* allocator,
_Outptr_result_maybenull_ char** compatibility_info);

/** \brief Extract EP compatibility info from precompiled model bytes in memory.
*
* Same as GetCompatibilityInfoFromModel but reads from a memory buffer instead of a file.
* Useful when precompiled models are loaded from encrypted storage, network, or other non-file sources.
*
* \note This API performs standalone model parsing, separate from session creation. This means
* the protobuf parsing cost is incurred here and again during session creation. It is intended
* for scenarios where applications need to check compatibility before deciding whether to proceed
* with session creation, such as providing early user feedback.
*
* \param[in] model_data Pointer to the model data in memory.
* \param[in] model_data_length Size of the model data in bytes.
* \param[in] ep_type The execution provider type string. Must be non-empty.
* \param[in] allocator Allocator to use for the output string. Use OrtApi::GetAllocatorWithDefaultOptions.
* \param[out] compatibility_info Output pointer to the compatibility info string.
* Returns nullptr if no compatibility info exists for the specified EP.
* Caller must free with OrtApi::AllocatorFree when non-null.
*
* \snippet{doc} snippets.dox OrtStatus Return Value
*
* \since Version 1.24.
*/
ORT_API2_STATUS(GetCompatibilityInfoFromModelBytes,
_In_reads_(model_data_length) const void* model_data,
_In_ size_t model_data_length,
_In_ const char* ep_type,
_Inout_ OrtAllocator* allocator,
_Outptr_result_maybenull_ char** compatibility_info);

/// @}

/** \brief Create an OrtEnv instance with the given options.
*
* \note Invoking this function will return the same instance of the environment as that returned by a previous call
Expand Down
33 changes: 33 additions & 0 deletions include/onnxruntime/core/session/onnxruntime_cxx_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,39 @@ OrtCompiledModelCompatibility GetModelCompatibilityForEpDevices(
const std::vector<ConstEpDevice>& ep_devices,
const char* compatibility_info);

/** \brief Extract EP compatibility info from a precompiled model file.
*
* Parses the model file to extract the compatibility info string for a specific execution provider
* from the model's metadata properties. This is only applicable to models that have been precompiled
* for an EP. Standard ONNX models do not contain this information.
*
* \note This operation parses the full ONNX ModelProto from disk.
*
* \param model_path Path to the ONNX model file.
* \param ep_type The execution provider type string. Must be non-empty.
* Use ConstEpDevice::EpName() to get this value.
* \param allocator Allocator to use for the output string.
* \return The compatibility info string, or nullptr if not found for this EP. Caller must free via allocator.
* \throws Ort::Exception on error.
*/
AllocatedStringPtr GetCompatibilityInfoFromModelAllocated(const ORTCHAR_T* model_path, const char* ep_type,
OrtAllocator* allocator);

/** \brief Extract EP compatibility info from precompiled model bytes in memory.
*
* Same as GetCompatibilityInfoFromModelAllocated but reads from a memory buffer.
* Useful when precompiled models are loaded from encrypted storage, network, or other non-file sources.
*
* \param model_data Pointer to the model data in memory.
* \param model_data_length Size of the model data in bytes.
* \param ep_type The execution provider type string. Must be non-empty.
* \param allocator Allocator to use for the output string.
* \return The compatibility info string, or nullptr if not found for this EP. Caller must free via allocator.
* \throws Ort::Exception on error.
*/
AllocatedStringPtr GetCompatibilityInfoFromModelBytesAllocated(const void* model_data, size_t model_data_length,
const char* ep_type, OrtAllocator* allocator);

namespace detail {
template <typename T>
struct EpAssignedNodeImpl : Ort::detail::Base<T> {
Expand Down
14 changes: 14 additions & 0 deletions include/onnxruntime/core/session/onnxruntime_cxx_inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,20 @@ inline OrtCompiledModelCompatibility GetModelCompatibilityForEpDevices(
return status;
}

inline AllocatedStringPtr GetCompatibilityInfoFromModelAllocated(const ORTCHAR_T* model_path, const char* ep_type,
OrtAllocator* allocator) {
char* compat_info = nullptr;
ThrowOnError(GetApi().GetCompatibilityInfoFromModel(model_path, ep_type, allocator, &compat_info));
return AllocatedStringPtr(compat_info, detail::AllocatedFree(allocator));
}

inline AllocatedStringPtr GetCompatibilityInfoFromModelBytesAllocated(const void* model_data, size_t model_data_length,
const char* ep_type, OrtAllocator* allocator) {
char* compat_info = nullptr;
ThrowOnError(GetApi().GetCompatibilityInfoFromModelBytes(model_data, model_data_length, ep_type, allocator, &compat_info));
return AllocatedStringPtr(compat_info, detail::AllocatedFree(allocator));
}

inline LoraAdapter LoraAdapter::CreateLoraAdapter(const std::basic_string<ORTCHAR_T>& adapter_path,
OrtAllocator* allocator) {
OrtLoraAdapter* p;
Expand Down
118 changes: 117 additions & 1 deletion onnxruntime/core/session/onnxruntime_c_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@

#include <algorithm>
#include <cassert>
#include <climits>
#include <cstring>
#include <functional>
#include <mutex>
#include <vector>
#include <sstream>
#include <vector>

#include "core/common/common.h"
#include "core/common/logging/logging.h"
Expand All @@ -30,8 +31,10 @@
#include "core/framework/utils.h"
#include "core/graph/constants.h"
#include "core/graph/graph.h"
#include "core/graph/model.h"
#include "core/graph/model_editor_api_types.h"
#include "core/graph/ep_api_types.h"
#include "core/graph/onnx_protobuf.h"
#include "core/providers/get_execution_providers.h"
#include "core/session/abi_devices.h"
#include "core/session/abi_session_options_impl.h"
Expand All @@ -40,6 +43,7 @@
#include "core/session/environment.h"
#include "core/session/ep_graph_assignment_info.h"
#include "core/session/interop_api.h"
#include "core/session/onnxruntime_ep_device_ep_metadata_keys.h"
#include "core/session/plugin_ep/ep_api.h"
#include "core/session/plugin_ep/ep_library_internal.h"
#include "core/session/inference_session.h"
Expand Down Expand Up @@ -3769,6 +3773,93 @@
API_IMPL_END
}

// Helper function to extract compatibility info from model metadata
static OrtStatus* ExtractCompatibilityInfoFromModelProto(
const ONNX_NAMESPACE::ModelProto& model_proto,
const char* ep_type,
OrtAllocator* allocator,
char** compatibility_info) {
// Build the key we're looking for
std::string target_key = std::string(kOrtModelMetadata_EpCompatibilityInfoPrefix) + ep_type;

Check warning on line 3783 in onnxruntime/core/session/onnxruntime_c_api.cc

View workflow job for this annotation

GitHub Actions / Optional Lint C++

[cpplint] reported by reviewdog 🐶 Add #include <string> for string [build/include_what_you_use] [4] Raw Output: onnxruntime/core/session/onnxruntime_c_api.cc:3783: Add #include <string> for string [build/include_what_you_use] [4]

// Search through metadata_props for the matching key
for (const auto& prop : model_proto.metadata_props()) {
if (prop.key() == target_key) {
// Found it - allocate and copy the value using the provided allocator
*compatibility_info = onnxruntime::StrDup(prop.value(), allocator);
if (*compatibility_info == nullptr) {
return OrtApis::CreateStatus(ORT_FAIL, "Failed to allocate memory for compatibility info.");
}
return nullptr;
}
}

// Key not found - return nullptr (not an error, just means no compat info for this EP)
*compatibility_info = nullptr;
return nullptr;
}

// Extract EP compatibility info from a model file
ORT_API_STATUS_IMPL(OrtApis::GetCompatibilityInfoFromModel,
_In_ const ORTCHAR_T* model_path,
_In_ const char* ep_type,
_Inout_ OrtAllocator* allocator,
_Outptr_result_maybenull_ char** compatibility_info) {
API_IMPL_BEGIN
if (model_path == nullptr || ep_type == nullptr || ep_type[0] == '\0' ||
allocator == nullptr || compatibility_info == nullptr) {
return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT,
"Invalid argument provided to GetCompatibilityInfoFromModel.");
}

*compatibility_info = nullptr;

// Use Model::Load for proper cross-platform path handling via file descriptor
ONNX_NAMESPACE::ModelProto model_proto;
auto status = Model::Load(PathString(model_path), model_proto);
if (!status.IsOK()) {
if (status.Code() == common::NO_SUCHFILE) {
return OrtApis::CreateStatus(ORT_NO_SUCHFILE, status.ErrorMessage().c_str());
}
return OrtApis::CreateStatus(ORT_INVALID_GRAPH, status.ErrorMessage().c_str());
}

return ExtractCompatibilityInfoFromModelProto(model_proto, ep_type, allocator, compatibility_info);
API_IMPL_END
}

// Extract EP compatibility info from model bytes in memory
ORT_API_STATUS_IMPL(OrtApis::GetCompatibilityInfoFromModelBytes,
_In_reads_(model_data_length) const void* model_data,
_In_ size_t model_data_length,
_In_ const char* ep_type,
_Inout_ OrtAllocator* allocator,
_Outptr_result_maybenull_ char** compatibility_info) {
API_IMPL_BEGIN
if (model_data == nullptr || model_data_length == 0 || ep_type == nullptr || ep_type[0] == '\0' ||
allocator == nullptr || compatibility_info == nullptr) {
return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT,
"Invalid argument provided to GetCompatibilityInfoFromModelBytes.");
}

*compatibility_info = nullptr;

// Explicit check for size limit - Model::LoadFromBytes uses int for size due to protobuf API
if (model_data_length > static_cast<size_t>(INT_MAX)) {
return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT,
"Model data size exceeds maximum supported size (2GB). Use GetCompatibilityInfoFromModel with a file path instead.");
}

ONNX_NAMESPACE::ModelProto model_proto;
auto status = Model::LoadFromBytes(static_cast<int>(model_data_length), model_data, model_proto);
if (!status.IsOK()) {
return OrtApis::CreateStatus(ORT_INVALID_GRAPH, status.ErrorMessage().c_str());
}

return ExtractCompatibilityInfoFromModelProto(model_proto, ep_type, allocator, compatibility_info);
API_IMPL_END
}

// GetInteropApi - returns the Interop API struct
ORT_API(const OrtInteropApi*, OrtApis::GetInteropApi) {
return OrtInteropAPI::GetInteropApi();
Expand Down Expand Up @@ -3807,6 +3898,29 @@
API_IMPL_END
}

// Minimal build stub for GetCompatibilityInfoFromModel
ORT_API_STATUS_IMPL(OrtApis::GetCompatibilityInfoFromModel,
_In_ const ORTCHAR_T* /*model_path*/,
_In_ const char* /*ep_type*/,
_Inout_ OrtAllocator* /*allocator*/,
_Outptr_result_maybenull_ char** /*compatibility_info*/) {
API_IMPL_BEGIN
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "GetCompatibilityInfoFromModel is not supported in a minimal build.");
API_IMPL_END
}

// Minimal build stub for GetCompatibilityInfoFromModelBytes
ORT_API_STATUS_IMPL(OrtApis::GetCompatibilityInfoFromModelBytes,
_In_reads_(model_data_length) const void* /*model_data*/,
_In_ size_t /*model_data_length*/,
_In_ const char* /*ep_type*/,
_Inout_ OrtAllocator* /*allocator*/,
_Outptr_result_maybenull_ char** /*compatibility_info*/) {
API_IMPL_BEGIN
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "GetCompatibilityInfoFromModelBytes is not supported in a minimal build.");
API_IMPL_END
}

ORT_API_STATUS_IMPL(OrtApis::SessionOptionsAppendExecutionProvider_V2, _In_ OrtSessionOptions* /*session_options*/,
_In_ OrtEnv* /*env*/,
_In_reads_(num_ep_devices) const OrtEpDevice* const* /*ep_devices*/,
Expand Down Expand Up @@ -4503,6 +4617,8 @@
&OrtApis::DeviceEpIncompatibilityDetails_GetNotes,
&OrtApis::DeviceEpIncompatibilityDetails_GetErrorCode,
&OrtApis::ReleaseDeviceEpIncompatibilityDetails,
&OrtApis::GetCompatibilityInfoFromModel,
&OrtApis::GetCompatibilityInfoFromModelBytes,

&OrtApis::CreateEnvWithOptions,
&OrtApis::Session_GetEpGraphAssignmentInfo,
Expand Down
11 changes: 11 additions & 0 deletions onnxruntime/core/session/ort_apis.h
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,17 @@ ORT_API_STATUS_IMPL(GetModelCompatibilityForEpDevices,
_In_ size_t num_ep_devices,
_In_ const char* compatibility_info,
_Out_ OrtCompiledModelCompatibility* out_status);
ORT_API_STATUS_IMPL(GetCompatibilityInfoFromModel,
_In_ const ORTCHAR_T* model_path,
_In_ const char* ep_type,
_Inout_ OrtAllocator* allocator,
_Outptr_result_maybenull_ char** compatibility_info);
ORT_API_STATUS_IMPL(GetCompatibilityInfoFromModelBytes,
_In_reads_(model_data_length) const void* model_data,
_In_ size_t model_data_length,
_In_ const char* ep_type,
_Inout_ OrtAllocator* allocator,
_Outptr_result_maybenull_ char** compatibility_info);
ORT_API_STATUS_IMPL(Graph_GetModelPath, _In_ const OrtGraph* graph, _Outptr_ const ORTCHAR_T** model_path);
ORT_API_STATUS_IMPL(Graph_GetOnnxIRVersion, _In_ const OrtGraph* graph, _Out_ int64_t* onnx_ir_version);
ORT_API_STATUS_IMPL(Graph_GetNumOperatorSets, _In_ const OrtGraph* graph, _Out_ size_t* num_operator_sets);
Expand Down
Loading
Loading