Skip to content

Commit 3cadbdb

Browse files
adrastogiAditya Rastogi
andauthored
Add API for precompiled model compatibility check using just the compat info (microsoft#25841)
### Description This PR adds a new API that applications can use to verify compatibility of a precompiled model with the underlying system, using only the compatibility info string from the model's metadata. ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. --> - This is a feature to enable apps to check compatibility of a precompiled model without necessarily having the model locally on the device. This enables precompiled models to be stored remotely and downloaded once the application has been able to confirm the validity of a given model with EPs on the device. ### Testing - New unit tests pass - For regression testing, built a private version of WinML + AMD NPU EP with these changes. Ran the Cpp Selfcontained Desktop sample successfully; ran with compilation and also re-ran using the already-compiled model to verify that session initialization continued to work as expected. --------- Co-authored-by: Aditya Rastogi <adityar@ntdev.microsoft.com>
1 parent 0ba4d29 commit 3cadbdb

File tree

9 files changed

+231
-30
lines changed

9 files changed

+231
-30
lines changed

include/onnxruntime/core/session/onnxruntime_c_api.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,16 @@ typedef void (*RunAsyncCallbackFn)(void* user_data, OrtValue** outputs, size_t n
902902
*
903903
* \nosubgrouping
904904
*/
905+
/*
906+
* Public enum for compiled model compatibility across EPs.
907+
*/
908+
typedef enum OrtCompiledModelCompatibility {
909+
OrtCompiledModelCompatibility_EP_NOT_APPLICABLE = 0,
910+
OrtCompiledModelCompatibility_EP_SUPPORTED_OPTIMAL,
911+
OrtCompiledModelCompatibility_EP_SUPPORTED_PREFER_RECOMPILATION,
912+
OrtCompiledModelCompatibility_EP_UNSUPPORTED,
913+
} OrtCompiledModelCompatibility;
914+
905915
struct OrtApi {
906916
/// \name OrtStatus
907917
/// @{
@@ -6480,6 +6490,24 @@ struct OrtApi {
64806490
* \since Version 1.23.
64816491
*/
64826492
ORT_API2_STATUS(Graph_GetModelMetadata, _In_ const OrtGraph* graph, _Outptr_ OrtModelMetadata** out);
6493+
6494+
/** \brief Validate a compiled model's compatibility information for one or more EP devices.
6495+
*
6496+
* \param[in] ep_devices The EP devices to validate against (e.g., from GetEpDevices).
6497+
* All devices must belong to the same execution provider.
6498+
* \param[in] num_ep_devices The number of EP devices provided.
6499+
* \param[in] compatibility_info The compatibility info string produced when the model was compiled.
6500+
* \param[out] out_status The resulting compatibility status for the EP devices.
6501+
*
6502+
* \snippet{doc} snippets.dox OrtStatus Return Value
6503+
*
6504+
* \since Version 1.23.
6505+
*/
6506+
ORT_API2_STATUS(GetModelCompatibilityForEpDevices,
6507+
_In_reads_(num_ep_devices) const OrtEpDevice* const* ep_devices,
6508+
_In_ size_t num_ep_devices,
6509+
_In_ const char* compatibility_info,
6510+
_Out_ OrtCompiledModelCompatibility* out_status);
64836511
};
64846512

64856513
/*

include/onnxruntime/core/session/onnxruntime_ep_c_api.h

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -482,18 +482,6 @@ typedef enum OrtEpDataLayout {
482482
OrtEpDataLayout_Default = OrtEpDataLayout_NCHW,
483483
} OrtEpDataLayout;
484484

485-
/**
486-
* \brief Enumeration describing the compatibility state of a compiled model relative to an execution provider.
487-
*
488-
* \since Version 1.23.
489-
*/
490-
typedef enum OrtCompiledModelCompatibility {
491-
OrtCompiledModelCompatibility_EP_NOT_APPLICABLE = 0,
492-
OrtCompiledModelCompatibility_EP_SUPPORTED_OPTIMAL,
493-
OrtCompiledModelCompatibility_EP_SUPPORTED_PREFER_RECOMPILATION,
494-
OrtCompiledModelCompatibility_EP_UNSUPPORTED,
495-
} OrtCompiledModelCompatibility;
496-
497485
/**
498486
* \brief The OrtEp struct provides functions to implement for an execution provider.
499487
* \since Version 1.22.
@@ -901,20 +889,28 @@ struct OrtEpFactory {
901889
*/
902890
ORT_API_T(const char*, GetVersion, _In_ const OrtEpFactory* this_ptr);
903891

904-
/** \brief Validate the compatibility of a compiled model with the execution provider.
892+
/** \brief Validate the compatibility of a compiled model with the execution provider factory for one or more devices.
893+
*
894+
* Given a compatibility info string produced during model compilation, the EP factory should determine whether the
895+
* compiled model is compatible with the EP factory when targeting the provided hardware devices. All devices provided
896+
* must belong to the same execution provider instance that this factory creates.
905897
*
906-
* This function validates if a model produced with the supplied compatibility info string is supported by the underlying EP.
907-
* The EP should check if a compiled model is compatible with the EP and set the model_compatibility parameter accordingly.
898+
* The EP factory implementation should consider the set of devices (e.g., multi-adapter or multi-GPU scenarios) when
899+
* evaluating compatibility and set `model_compatibility` accordingly.
908900
*
909901
* \param[in] this_ptr The OrtEpFactory instance.
910-
* \param[in] compatibility_info The compatibility information string that will be used
911-
* \param[out] model_compatibility OrtCompiledModelCompatibility enum value describing the compatibility of the model with the EP.
902+
* \param[in] devices Array of OrtHardwareDevice pointers that the EP would run on. All must map to this EP.
903+
* \param[in] num_devices Number of entries in `devices`.
904+
* \param[in] compatibility_info The compatibility information string produced when the model was compiled.
905+
* \param[out] model_compatibility OrtCompiledModelCompatibility value describing the compatibility of the model with the EP.
912906
*
913907
* \snippet{doc} snippets.dox OrtStatus Return Value
914908
*
915909
* \since Version 1.23.
916910
*/
917911
ORT_API2_STATUS(ValidateCompiledModelCompatibilityInfo, _In_ OrtEpFactory* this_ptr,
912+
_In_reads_(num_devices) const OrtHardwareDevice* const* devices,
913+
_In_ size_t num_devices,
918914
_In_ const char* compatibility_info,
919915
_Out_ OrtCompiledModelCompatibility* model_compatibility);
920916

onnxruntime/core/session/onnxruntime_c_api.cc

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3423,25 +3423,86 @@ ORT_API_STATUS_IMPL(OrtApis::CopyTensors, _In_ const OrtEnv* env,
34233423
API_IMPL_END
34243424
}
34253425

3426+
// Validate compiled model compatibility info for specific EP device(s)
3427+
ORT_API_STATUS_IMPL(OrtApis::GetModelCompatibilityForEpDevices,
3428+
_In_reads_(num_ep_devices) const OrtEpDevice* const* ep_devices,
3429+
_In_ size_t num_ep_devices,
3430+
_In_ const char* compatibility_info,
3431+
_Out_ OrtCompiledModelCompatibility* out_status) {
3432+
API_IMPL_BEGIN
3433+
if (ep_devices == nullptr || num_ep_devices == 0 || compatibility_info == nullptr || out_status == nullptr) {
3434+
return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "Invalid argument provided to GetModelCompatibilityForEpDevices.");
3435+
}
3436+
3437+
// Validate inputs and ensure all devices belong to the same EP/factory
3438+
const OrtEpFactory* first_factory = nullptr;
3439+
for (size_t i = 0; i < num_ep_devices; ++i) {
3440+
if (ep_devices[i] == nullptr) {
3441+
return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "ep_devices contains a null entry.");
3442+
}
3443+
const OrtEpFactory* f = ep_devices[i]->GetMutableFactory();
3444+
if (i == 0) {
3445+
first_factory = f;
3446+
} else if (f != first_factory) {
3447+
return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "All ep_devices must be from the same execution provider.");
3448+
}
3449+
}
3450+
3451+
OrtCompiledModelCompatibility status = OrtCompiledModelCompatibility_EP_NOT_APPLICABLE;
3452+
OrtStatus* ort_status = nullptr;
3453+
OrtEpFactory* factory = ep_devices[0]->GetMutableFactory();
3454+
if (factory && factory->ValidateCompiledModelCompatibilityInfo) {
3455+
// collect hardware devices corresponding to the ep_devices
3456+
InlinedVector<const OrtHardwareDevice*> hardware_devices;
3457+
hardware_devices.reserve(num_ep_devices);
3458+
for (size_t i = 0; i < num_ep_devices; ++i) {
3459+
hardware_devices.push_back(ep_devices[i]->device);
3460+
}
3461+
ort_status = factory->ValidateCompiledModelCompatibilityInfo(factory,
3462+
hardware_devices.data(),
3463+
hardware_devices.size(),
3464+
compatibility_info,
3465+
&status);
3466+
}
3467+
if (ort_status != nullptr) {
3468+
return ToOrtStatus(ToStatusAndRelease(ort_status));
3469+
}
3470+
3471+
*out_status = status;
3472+
return nullptr;
3473+
API_IMPL_END
3474+
}
3475+
34263476
#else // defined(ORT_MINIMAL_BUILD)
34273477
ORT_API_STATUS_IMPL(OrtApis::RegisterExecutionProviderLibrary, _In_ OrtEnv* /*env*/, _In_ const char* /*registration_name*/,
34283478
const ORTCHAR_T* /*path*/) {
34293479
API_IMPL_BEGIN
3430-
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "This API in not supported in a minimal build.");
3480+
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "RegisterExecutionProviderLibrary is not supported in a minimal build.");
34313481
API_IMPL_END
34323482
}
34333483

34343484
ORT_API_STATUS_IMPL(OrtApis::UnregisterExecutionProviderLibrary, _In_ OrtEnv* /*env*/,
34353485
_In_ const char* /*registration_name*/) {
34363486
API_IMPL_BEGIN
3437-
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "This API in not supported in a minimal build.");
3487+
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "UnregisterExecutionProviderLibrary is not supported in a minimal build.");
34383488
API_IMPL_END
34393489
}
34403490

34413491
ORT_API_STATUS_IMPL(OrtApis::GetEpDevices, _In_ const OrtEnv* /*env*/,
34423492
_Outptr_ const OrtEpDevice* const** /*ep_devices*/, _Out_ size_t* /*num_ep_devices*/) {
34433493
API_IMPL_BEGIN
3444-
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "This API in not supported in a minimal build.");
3494+
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "GetEpDevices is not supported in a minimal build.");
3495+
API_IMPL_END
3496+
}
3497+
3498+
// Minimal build stub for GetModelCompatibilityForEpDevices to satisfy symbol references from the API table
3499+
ORT_API_STATUS_IMPL(OrtApis::GetModelCompatibilityForEpDevices,
3500+
_In_reads_(num_ep_devices) const OrtEpDevice* const* /*ep_devices*/,
3501+
_In_ size_t /*num_ep_devices*/,
3502+
_In_ const char* /*compatibility_info*/,
3503+
_Out_ OrtCompiledModelCompatibility* /*out_status*/) {
3504+
API_IMPL_BEGIN
3505+
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "GetModelCompatibilityForEpDevices is not supported in a minimal build.");
34453506
API_IMPL_END
34463507
}
34473508

@@ -3453,7 +3514,7 @@ ORT_API_STATUS_IMPL(OrtApis::SessionOptionsAppendExecutionProvider_V2, _In_ OrtS
34533514
_In_reads_(num_op_options) const char* const* /*ep_option_vals*/,
34543515
size_t /*num_ep_options*/) {
34553516
API_IMPL_BEGIN
3456-
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "This API in not supported in a minimal build.");
3517+
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "SessionOptionsAppendExecutionProvider_V2 is not supported in a minimal build.");
34573518
API_IMPL_END
34583519
}
34593520

@@ -3466,15 +3527,15 @@ ORT_API_STATUS_IMPL(OrtApis::SessionGetEpDeviceForInputs, _In_ const OrtSession*
34663527
_Out_writes_(num_values) const OrtEpDevice** /*inputs_ep_devices*/,
34673528
_In_ size_t /*num_values*/) {
34683529
API_IMPL_BEGIN
3469-
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "This API in not supported in a minimal build.");
3530+
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "SessionGetEpDeviceForInputs is not supported in a minimal build.");
34703531
API_IMPL_END
34713532
}
34723533

34733534
ORT_API_STATUS_IMPL(OrtApis::CreateSyncStreamForEpDevice, _In_ const OrtEpDevice* /*ep_device*/,
34743535
_In_opt_ const OrtKeyValuePairs* /*stream_options*/,
34753536
_Outptr_ OrtSyncStream** /*ort_stream*/) {
34763537
API_IMPL_BEGIN
3477-
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "This API in not supported in a minimal build.");
3538+
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "CreateSyncStreamForEpDevice is not supported in a minimal build.");
34783539
API_IMPL_END
34793540
}
34803541

@@ -3493,7 +3554,7 @@ ORT_API_STATUS_IMPL(OrtApis::CopyTensors, _In_ const OrtEnv* /*env*/,
34933554
_In_opt_ OrtSyncStream* /*stream*/,
34943555
_In_ size_t /*num_tensors*/) {
34953556
API_IMPL_BEGIN
3496-
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "This API in not supported in a minimal build.");
3557+
return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "CopyTensors is not supported in a minimal build.");
34973558
API_IMPL_END
34983559
}
34993560

@@ -4108,6 +4169,7 @@ static constexpr OrtApi ort_api_1_to_23 = {
41084169
&OrtApis::CopyTensors,
41094170

41104171
&OrtApis::Graph_GetModelMetadata,
4172+
&OrtApis::GetModelCompatibilityForEpDevices,
41114173
};
41124174

41134175
// OrtApiBase can never change as there is no way to know what version of OrtApiBase is returned by OrtGetApiBase.

onnxruntime/core/session/ort_apis.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,13 @@ ORT_API_STATUS_IMPL(ValueInfo_IsFromOuterScope, _In_ const OrtValueInfo* value_i
636636
// OrtGraph
637637
ORT_API_STATUS_IMPL(Graph_GetName, _In_ const OrtGraph* graph, _Outptr_ const char** graph_name);
638638
ORT_API_STATUS_IMPL(Graph_GetModelMetadata, _In_ const OrtGraph* graph, _Outptr_ OrtModelMetadata** out);
639+
640+
// EP Compatibility Info APIs
641+
ORT_API_STATUS_IMPL(GetModelCompatibilityForEpDevices,
642+
_In_reads_(num_ep_devices) const OrtEpDevice* const* ep_devices,
643+
_In_ size_t num_ep_devices,
644+
_In_ const char* compatibility_info,
645+
_Out_ OrtCompiledModelCompatibility* out_status);
639646
ORT_API_STATUS_IMPL(Graph_GetModelPath, _In_ const OrtGraph* graph, _Outptr_ const ORTCHAR_T** model_path);
640647
ORT_API_STATUS_IMPL(Graph_GetOnnxIRVersion, _In_ const OrtGraph* graph, _Out_ int64_t* onnx_ir_version);
641648
ORT_API_STATUS_IMPL(Graph_GetNumOperatorSets, _In_ const OrtGraph* graph, _Out_ size_t* num_operator_sets);

onnxruntime/core/session/plugin_ep/ep_factory_internal.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,11 @@ class EpFactoryInternal : public OrtEpFactory {
8080
return impl_->CreateSyncStreamForDevice(memory_device, stream_options, stream);
8181
}
8282

83-
OrtStatus* ValidateCompiledModelCompatibilityInfo(_In_ const char* compatibility_info,
83+
OrtStatus* ValidateCompiledModelCompatibilityInfo(_In_reads_(num_devices) const OrtHardwareDevice* const* devices,
84+
_In_ size_t num_devices,
85+
_In_ const char* compatibility_info,
8486
_Out_ OrtCompiledModelCompatibility* model_compatibility) noexcept {
85-
return impl_->ValidateCompiledModelCompatibilityInfo(compatibility_info, model_compatibility);
87+
return impl_->ValidateCompiledModelCompatibilityInfo(devices, num_devices, compatibility_info, model_compatibility);
8688
}
8789

8890
// Function ORT calls to release an EP instance.

onnxruntime/core/session/plugin_ep/ep_factory_internal_impl.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,13 @@ class EpFactoryInternalImpl {
6262
return false;
6363
}
6464

65-
virtual OrtStatus* ValidateCompiledModelCompatibilityInfo(_In_ const char* compatibility_info,
66-
_Out_ OrtCompiledModelCompatibility* model_compatibility) noexcept {
65+
virtual OrtStatus* ValidateCompiledModelCompatibilityInfo(
66+
_In_reads_(num_devices) const OrtHardwareDevice* const* devices,
67+
_In_ size_t num_devices,
68+
_In_ const char* compatibility_info,
69+
_Out_ OrtCompiledModelCompatibility* model_compatibility) noexcept {
70+
ORT_UNUSED_PARAMETER(devices);
71+
ORT_UNUSED_PARAMETER(num_devices);
6772
ORT_UNUSED_PARAMETER(compatibility_info);
6873
// Default implementation: mark as not applicable
6974
*model_compatibility = OrtCompiledModelCompatibility_EP_NOT_APPLICABLE;

onnxruntime/core/session/plugin_ep/ep_plugin_provider_interfaces.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,8 +668,15 @@ Status PluginExecutionProvider::ValidateCompiledModelCompatibilityInfo(const std
668668
// Plugin EP did not provide an implementation of this function, so we call a default implementation.
669669
return Base::ValidateCompiledModelCompatibilityInfo(compatibility_info, model_compatibility);
670670
}
671-
// Delegate to the EP factory's validation method
671+
// Delegate to the EP factory's validation method, passing hardware devices derived from our ep_devices_
672+
std::vector<const OrtHardwareDevice*> hardware_devices;
673+
hardware_devices.reserve(ep_devices_.size());
674+
for (const auto* ep_device : ep_devices_) {
675+
hardware_devices.push_back(ep_device->device);
676+
}
672677
ORT_RETURN_IF_ERROR(ToStatusAndRelease(ep_factory_.ValidateCompiledModelCompatibilityInfo(&ep_factory_,
678+
hardware_devices.data(),
679+
hardware_devices.size(),
673680
compatibility_info.c_str(),
674681
&model_compatibility)));
675682
return Status::OK();

onnxruntime/core/session/plugin_ep/forward_to_factory_impl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,12 @@ struct ForwardToFactoryImpl {
4646
}
4747

4848
static OrtStatus* ORT_API_CALL ValidateCompiledModelCompatibilityInfo(OrtEpFactory* this_ptr,
49+
_In_reads_(num_devices) const OrtHardwareDevice* const* devices,
50+
size_t num_devices,
4951
const char* compatibility_info,
5052
OrtCompiledModelCompatibility* model_compatibility) noexcept {
51-
return static_cast<TFactory*>(this_ptr)->ValidateCompiledModelCompatibilityInfo(compatibility_info, model_compatibility);
53+
return static_cast<TFactory*>(this_ptr)->ValidateCompiledModelCompatibilityInfo(devices, num_devices,
54+
compatibility_info, model_compatibility);
5255
}
5356

5457
static OrtStatus* ORT_API_CALL CreateAllocator(_In_ OrtEpFactory* this_ptr,

onnxruntime/test/framework/ep_compatibility_test.cc

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,3 +408,94 @@ TEST_F(EpCompatibilityTest, TestSessionOptionConfiguration) {
408408
EXPECT_TRUE(has_config);
409409
EXPECT_EQ(config_value, "0");
410410
}
411+
412+
// -----------------------------
413+
// C API unit tests
414+
// -----------------------------
415+
416+
namespace {
417+
418+
// Helper to create an OrtEnv and fetch a CPU EP device pointer via the C API.
419+
// Returns a pair of (env, cpu_device). Caller releases env via api->ReleaseEnv.
420+
static std::pair<OrtEnv*, const OrtEpDevice*> CreateEnvAndGetCpuEpDevice(const OrtApi* api) {
421+
OrtEnv* env = nullptr;
422+
EXPECT_EQ(nullptr, api->CreateEnv(ORT_LOGGING_LEVEL_WARNING, "EpCompatCapiTest", &env));
423+
EXPECT_NE(env, nullptr);
424+
425+
const OrtEpDevice* const* devices = nullptr;
426+
size_t num_devices = 0;
427+
EXPECT_EQ(nullptr, api->GetEpDevices(env, &devices, &num_devices));
428+
EXPECT_GT(num_devices, 0u);
429+
430+
const OrtEpDevice* cpu_device = nullptr;
431+
for (size_t i = 0; i < num_devices; ++i) {
432+
const char* name = api->EpDevice_EpName(devices[i]);
433+
if (name && std::string(name) == "CPUExecutionProvider") {
434+
cpu_device = devices[i];
435+
break;
436+
}
437+
}
438+
439+
// Fallback: just pick the first device if CPU wasn't found (environment-dependent builds).
440+
if (!cpu_device && num_devices > 0) {
441+
cpu_device = devices[0];
442+
}
443+
444+
EXPECT_NE(cpu_device, nullptr);
445+
return {env, cpu_device};
446+
}
447+
448+
} // namespace
449+
450+
TEST(EpCompatibilityCapiTest, InvalidArguments) {
451+
const OrtApi* api = OrtGetApiBase()->GetApi(ORT_API_VERSION);
452+
ASSERT_NE(api, nullptr);
453+
454+
OrtCompiledModelCompatibility out_status = OrtCompiledModelCompatibility_EP_NOT_APPLICABLE;
455+
456+
// ep_devices == nullptr
457+
OrtStatus* st = api->GetModelCompatibilityForEpDevices(nullptr, 0, "info", &out_status);
458+
ASSERT_NE(st, nullptr);
459+
EXPECT_EQ(api->GetErrorCode(st), ORT_INVALID_ARGUMENT);
460+
api->ReleaseStatus(st);
461+
462+
// Prepare a valid device
463+
auto [env, device] = CreateEnvAndGetCpuEpDevice(api);
464+
ASSERT_NE(env, nullptr);
465+
ASSERT_NE(device, nullptr);
466+
467+
// compatibility_info == nullptr
468+
const OrtEpDevice* devices1[] = {device};
469+
st = api->GetModelCompatibilityForEpDevices(devices1, 1, nullptr, &out_status);
470+
ASSERT_NE(st, nullptr);
471+
EXPECT_EQ(api->GetErrorCode(st), ORT_INVALID_ARGUMENT);
472+
api->ReleaseStatus(st);
473+
474+
// out_status == nullptr
475+
st = api->GetModelCompatibilityForEpDevices(devices1, 1, "some-info", nullptr);
476+
ASSERT_NE(st, nullptr);
477+
EXPECT_EQ(api->GetErrorCode(st), ORT_INVALID_ARGUMENT);
478+
api->ReleaseStatus(st);
479+
480+
api->ReleaseEnv(env);
481+
}
482+
483+
TEST(EpCompatibilityCapiTest, CpuEpReturnsNotApplicableIfNoValidation) {
484+
const OrtApi* api = OrtGetApiBase()->GetApi(ORT_API_VERSION);
485+
ASSERT_NE(api, nullptr);
486+
487+
auto [env, device] = CreateEnvAndGetCpuEpDevice(api);
488+
ASSERT_NE(env, nullptr);
489+
ASSERT_NE(device, nullptr);
490+
491+
OrtCompiledModelCompatibility out_status = static_cast<OrtCompiledModelCompatibility>(-1);
492+
const OrtEpDevice* devices2[] = {device};
493+
OrtStatus* st = api->GetModelCompatibilityForEpDevices(devices2, 1, "arbitrary-compat-string", &out_status);
494+
ASSERT_EQ(st, nullptr) << (st ? api->GetErrorMessage(st) : "");
495+
496+
// For providers that don't implement validation, API should return EP_NOT_APPLICABLE.
497+
EXPECT_EQ(out_status, OrtCompiledModelCompatibility_EP_NOT_APPLICABLE);
498+
api->ReleaseStatus(st);
499+
500+
api->ReleaseEnv(env);
501+
}

0 commit comments

Comments
 (0)