Skip to content

Commit 33161f4

Browse files
author
Gopalakrishnan Nallasamy
committed
Refactor EPContext data callbacks for EP-owned I/O
1 parent 3dde470 commit 33161f4

13 files changed

Lines changed: 382 additions & 432 deletions

File tree

VERSION_NUMBER

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.27.0
1+
1.28.0

include/onnxruntime/core/session/onnxruntime_c_api.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
*
3939
* This value is used by some API functions to behave as this version of the header expects.
4040
*/
41-
#define ORT_API_VERSION 27
41+
#define ORT_API_VERSION 28
4242

4343
#ifdef __cplusplus
4444
extern "C" {
@@ -595,9 +595,9 @@ typedef OrtStatus*(ORT_API_CALL* OrtWriteBufferFunc)(_In_ void* state,
595595

596596
/** \brief Function called to write EPContext binary data during compilation.
597597
*
598-
* This function is called synchronously by OrtEpApi::WriteEpContextData on the calling thread. ORT does not retain
599-
* buffer after the callback returns, does not reorder callback invocations, and does not serialize invocations made by
600-
* different EP instances or EP worker threads.
598+
* This function is called synchronously by the execution provider on the calling thread. ORT does not own or retain
599+
* buffer after the callback returns. ORT does not serialize invocations made by different EP instances or EP worker
600+
* threads.
601601
*
602602
* Each callback invocation represents one complete write operation for file_name. The callback signature does not
603603
* provide an offset, sequence number, or final-chunk marker, so EPs that need chunked streaming must define their own
@@ -627,8 +627,8 @@ typedef OrtStatus*(ORT_API_CALL* OrtWriteEpContextDataFunc)(_In_ void* state,
627627
*
628628
* The application reads, processes (e.g., decrypts, decompresses, downloads), and returns the EPContext binary data.
629629
* ORT provides an allocator so the application can allocate the output buffer directly. The callback is called
630-
* synchronously by OrtEpApi::ReadEpContextData on the calling thread. ORT does not serialize invocations made by
631-
* different EP instances or EP worker threads.
630+
* synchronously by the execution provider on the calling thread. ORT does not serialize invocations made by different
631+
* EP instances or EP worker threads.
632632
*
633633
* \param[in] state Opaque pointer holding the user's state. ORT does not own or manage this pointer. The application
634634
* must keep it valid while any session or EP created from the associated OrtSessionOptions may invoke
@@ -7539,8 +7539,8 @@ struct OrtApi {
75397539
75407540
/** \brief Registers a callback to provide EPContext binary data during session load.
75417541
*
7542-
* When loading a compiled model with external (non-embedded) EPContext binary data, an execution provider can use
7543-
* OrtEpApi::ReadEpContextData to call this callback instead of reading the binary data from disk.
7542+
* When loading a compiled model with external (non-embedded) EPContext binary data, an execution provider can
7543+
* retrieve this callback from OrtEpContextConfig and call it instead of reading the binary data from disk.
75447544
*
75457545
* The state pointer is stored as-is and is not owned by ORT. It must remain valid while any session or EP created
75467546
* from these options may call the callback. If the same state may be used by multiple EPs or threads, the application
@@ -7552,7 +7552,7 @@ struct OrtApi {
75527552
*
75537553
* \snippet{doc} snippets.dox OrtStatus Return Value
75547554
*
7555-
* \since Version 1.27.
7555+
* \since Version 1.28.
75567556
*/
75577557
ORT_API2_STATUS(SessionOptions_SetEpContextDataReadFunc, _Inout_ OrtSessionOptions* options,
75587558
_In_ OrtReadEpContextDataFunc read_func, _In_opt_ void* state);
@@ -8380,8 +8380,8 @@ struct OrtCompileApi {
83808380

83818381
/** \brief Sets a callback for writing EPContext binary data during compilation.
83828382
*
8383-
* When EPContext embed mode is disabled, execution providers can use OrtEpApi::WriteEpContextData to call this
8384-
* callback instead of writing EPContext binary data directly to disk.
8383+
* When EPContext embed mode is disabled, execution providers can retrieve this callback from OrtEpContextConfig and
8384+
* call it instead of writing EPContext binary data directly to disk.
83858385
*
83868386
* The state pointer is stored as-is and is not owned by ORT. It must remain valid for the duration of the compile
83878387
* operation that may call the callback. If the same state may be used by multiple EPs or threads, the application is
@@ -8393,7 +8393,7 @@ struct OrtCompileApi {
83938393
*
83948394
* \snippet{doc} snippets.dox OrtStatus Return Value
83958395
*
8396-
* \since Version 1.27.
8396+
* \since Version 1.28.
83978397
*/
83988398
ORT_API2_STATUS(ModelCompilationOptions_SetEpContextDataWriteFunc,
83998399
_In_ OrtModelCompilationOptions* model_compile_options,

include/onnxruntime/core/session/onnxruntime_cxx_api.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ ORT_DEFINE_RELEASE(Value);
658658
ORT_DEFINE_RELEASE(ValueInfo);
659659

660660
ORT_DEFINE_RELEASE_FROM_API_STRUCT(ModelCompilationOptions, GetCompileApi);
661+
ORT_DEFINE_RELEASE_FROM_API_STRUCT(EpContextConfig, GetEpApi);
661662
ORT_DEFINE_RELEASE_FROM_API_STRUCT(EpDevice, GetEpApi);
662663
ORT_DEFINE_RELEASE_FROM_API_STRUCT(KernelDef, GetEpApi);
663664
ORT_DEFINE_RELEASE_FROM_API_STRUCT(KernelDefBuilder, GetEpApi);
@@ -786,6 +787,7 @@ struct AllocatedFree {
786787

787788
struct AllocatorWithDefaultOptions;
788789
struct Env;
790+
struct EpContextConfig;
789791
struct EpDevice;
790792
struct ExternalInitializerInfo;
791793
struct Graph;
@@ -1185,6 +1187,21 @@ struct EpDevice : detail::EpDeviceImpl<OrtEpDevice> {
11851187
ConstKeyValuePairs ep_metadata = {}, ConstKeyValuePairs ep_options = {});
11861188
};
11871189

1190+
/** \brief Owning wrapper around ::OrtEpContextConfig. */
1191+
struct EpContextConfig : detail::Base<OrtEpContextConfig> {
1192+
explicit EpContextConfig(std::nullptr_t) {} ///< No instance is created
1193+
explicit EpContextConfig(OrtEpContextConfig* p) : Base<OrtEpContextConfig>{p} {} ///< Take ownership
1194+
1195+
/// \brief Wraps OrtEpApi::SessionOptions_GetEpContextConfig
1196+
explicit EpContextConfig(const OrtSessionOptions* session_options);
1197+
1198+
/// \brief Wraps OrtEpApi::EpContextConfig_GetEpContextDataReadFunc
1199+
std::pair<OrtReadEpContextDataFunc, void*> GetEpContextDataReadFunc() const;
1200+
1201+
/// \brief Wraps OrtEpApi::EpContextConfig_GetEpContextDataWriteFunc
1202+
std::pair<OrtWriteEpContextDataFunc, void*> GetEpContextDataWriteFunc() const;
1203+
};
1204+
11881205
/** \brief Validate a compiled model's compatibility for one or more EP devices.
11891206
*
11901207
* Throws on error. Returns the resulting compatibility status.

include/onnxruntime/core/session/onnxruntime_cxx_inline.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,24 @@ inline EpDevice::EpDevice(OrtEpFactory& ep_factory, ConstHardwareDevice& hardwar
769769
ThrowOnError(GetEpApi().CreateEpDevice(&ep_factory, hardware_device, ep_metadata, ep_options, &p_));
770770
}
771771

772+
inline EpContextConfig::EpContextConfig(const OrtSessionOptions* session_options) {
773+
ThrowOnError(GetEpApi().SessionOptions_GetEpContextConfig(session_options, &p_));
774+
}
775+
776+
inline std::pair<OrtReadEpContextDataFunc, void*> EpContextConfig::GetEpContextDataReadFunc() const {
777+
OrtReadEpContextDataFunc read_func = nullptr;
778+
void* state = nullptr;
779+
ThrowOnError(GetEpApi().EpContextConfig_GetEpContextDataReadFunc(this->p_, &read_func, &state));
780+
return {read_func, state};
781+
}
782+
783+
inline std::pair<OrtWriteEpContextDataFunc, void*> EpContextConfig::GetEpContextDataWriteFunc() const {
784+
OrtWriteEpContextDataFunc write_func = nullptr;
785+
void* state = nullptr;
786+
ThrowOnError(GetEpApi().EpContextConfig_GetEpContextDataWriteFunc(this->p_, &write_func, &state));
787+
return {write_func, state};
788+
}
789+
772790
namespace detail {
773791
template <typename T>
774792
inline std::string EpAssignedSubgraphImpl<T>::GetEpName() const {

include/onnxruntime/core/session/onnxruntime_ep_c_api.h

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2087,14 +2087,14 @@ struct OrtEpApi {
20872087
*
20882088
* The returned handle owns only ORT's copy of callback function pointers and opaque state pointer values. It does not
20892089
* own the application-provided state. The application is responsible for keeping callback state valid and
2090-
* synchronized while an EP may call ReadEpContextData or WriteEpContextData with this config.
2090+
* synchronized while an EP may call callbacks retrieved from this config.
20912091
*
20922092
* \param[in] session_options The OrtSessionOptions instance.
20932093
* \param[out] config The extracted OrtEpContextConfig.
20942094
*
20952095
* \snippet{doc} snippets.dox OrtStatus Return Value
20962096
*
2097-
* \since Version 1.27.
2097+
* \since Version 1.28.
20982098
*/
20992099
ORT_API2_STATUS(SessionOptions_GetEpContextConfig,
21002100
_In_ const OrtSessionOptions* session_options,
@@ -2104,66 +2104,49 @@ struct OrtEpApi {
21042104
*
21052105
* \param[in] input The OrtEpContextConfig instance to release. May be NULL.
21062106
*
2107-
* \since Version 1.27.
2107+
* \since Version 1.28.
21082108
*/
21092109
ORT_CLASS_RELEASE(EpContextConfig);
21102110

2111-
/** \brief Read EPContext binary data, using an application read callback or falling back to disk.
2111+
/** \brief Get the application-provided EPContext data read callback.
21122112
*
2113-
* If config contains a read callback, the callback is invoked with the provided allocator. Otherwise, ORT reads the
2114-
* file from disk. The disk fallback derives the base directory from the graph's model path.
2113+
* Returns the OrtReadEpContextDataFunc and opaque state pointer registered via
2114+
* OrtApi::SessionOptions_SetEpContextDataReadFunc. If no callback was registered, *read_func and *state are set to
2115+
* NULL. The EP is responsible for calling the callback when present and for using its own normal read path when no
2116+
* callback is present.
21152117
*
2116-
* This function is synchronous. If a callback is present, it is invoked on the calling thread and its OrtStatus is
2117-
* returned to the caller. ORT does not serialize concurrent calls across EP instances or EP worker threads.
2118-
*
2119-
* \param[in] config The OrtEpContextConfig from SessionOptions_GetEpContextConfig. May be NULL for disk fallback.
2120-
* \param[in] file_name EPContext file name as a null-terminated UTF-8 string.
2121-
* \param[in] graph The OrtGraph from which ORT derives the model path for disk fallback. May be NULL.
2122-
* \param[in] allocator Allocator for the output buffer.
2123-
* \param[out] buffer Output buffer containing the EPContext binary data.
2124-
* \param[out] buffer_size Size of the output buffer in bytes.
2118+
* \param[in] config The OrtEpContextConfig from SessionOptions_GetEpContextConfig.
2119+
* \param[out] read_func The registered read callback, or NULL if none was registered.
2120+
* \param[out] state Opaque state pointer passed to read_func, or NULL if none was registered.
21252121
*
21262122
* \snippet{doc} snippets.dox OrtStatus Return Value
21272123
*
2128-
* \since Version 1.27.
2124+
* \since Version 1.28.
21292125
*/
2130-
ORT_API2_STATUS(ReadEpContextData,
2131-
_In_opt_ const OrtEpContextConfig* config,
2132-
_In_ const char* file_name,
2133-
_In_opt_ const OrtGraph* graph,
2134-
_Inout_ OrtAllocator* allocator,
2135-
_Outptr_ void** buffer,
2136-
_Out_ size_t* buffer_size);
2126+
ORT_API2_STATUS(EpContextConfig_GetEpContextDataReadFunc,
2127+
_In_ const OrtEpContextConfig* config,
2128+
_Out_ OrtReadEpContextDataFunc* read_func,
2129+
_Out_ void** state);
21372130

2138-
/** \brief Write EPContext binary data, using an application write callback or falling back to disk.
2131+
/** \brief Get the application-provided EPContext data write callback.
21392132
*
2140-
* If config contains a write callback, the data is forwarded to the application's callback. Otherwise, ORT writes the
2141-
* data to disk. The disk fallback derives the base directory from the graph's model path.
2133+
* Returns the OrtWriteEpContextDataFunc and opaque state pointer registered via
2134+
* OrtCompileApi::ModelCompilationOptions_SetEpContextDataWriteFunc. If no callback was registered, *write_func and
2135+
* *state are set to NULL. The EP is responsible for calling the callback when present and for using its own normal
2136+
* write path when no callback is present.
21422137
*
2143-
* This function is synchronous. If a callback is present, it is invoked on the calling thread and its OrtStatus is
2144-
* returned to the caller. ORT does not retain buffer after the callback returns, reorder callback invocations, or
2145-
* serialize concurrent calls across EP instances or EP worker threads.
2146-
*
2147-
* Each call is one complete write operation for file_name. The API does not provide an offset, sequence number, or
2148-
* final-chunk marker. EPs should prefer one call per EPContext binary, or document EP-specific chunk ordering and
2149-
* completion semantics if multiple calls are made for the same file_name.
2150-
*
2151-
* \param[in] config The OrtEpContextConfig from SessionOptions_GetEpContextConfig. May be NULL for disk fallback.
2152-
* \param[in] file_name EPContext file name as a null-terminated UTF-8 string.
2153-
* \param[in] graph The OrtGraph from which ORT derives the model path for disk fallback. May be NULL.
2154-
* \param[in] buffer The buffer containing EPContext binary data to write.
2155-
* \param[in] buffer_size Size of the buffer in bytes.
2138+
* \param[in] config The OrtEpContextConfig from SessionOptions_GetEpContextConfig.
2139+
* \param[out] write_func The registered write callback, or NULL if none was registered.
2140+
* \param[out] state Opaque state pointer passed to write_func, or NULL if none was registered.
21562141
*
21572142
* \snippet{doc} snippets.dox OrtStatus Return Value
21582143
*
2159-
* \since Version 1.27.
2144+
* \since Version 1.28.
21602145
*/
2161-
ORT_API2_STATUS(WriteEpContextData,
2162-
_In_opt_ const OrtEpContextConfig* config,
2163-
_In_ const char* file_name,
2164-
_In_opt_ const OrtGraph* graph,
2165-
_In_ const void* buffer,
2166-
_In_ size_t buffer_size);
2146+
ORT_API2_STATUS(EpContextConfig_GetEpContextDataWriteFunc,
2147+
_In_ const OrtEpContextConfig* config,
2148+
_Out_ OrtWriteEpContextDataFunc* write_func,
2149+
_Out_ void** state);
21672150
};
21682151

21692152
/**

onnxruntime/core/session/compile_api.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,9 @@ static constexpr OrtCompileApi ort_compile_api = {
393393

394394
&OrtCompileAPI::ModelCompilationOptions_SetInputModel,
395395
// End of Version 24 - DO NOT MODIFY ABOVE
396+
// End of Version 25 - DO NOT MODIFY ABOVE
397+
// End of Version 26 - DO NOT MODIFY ABOVE
398+
// End of Version 27 - DO NOT MODIFY ABOVE
396399

397400
&OrtCompileAPI::ModelCompilationOptions_SetEpContextDataWriteFunc,
398401
};
@@ -404,6 +407,8 @@ static_assert(offsetof(OrtCompileApi, ModelCompilationOptions_SetOutputModelGetI
404407
"Size of version 23 of Api cannot change");
405408
static_assert(offsetof(OrtCompileApi, ModelCompilationOptions_SetInputModel) / sizeof(void*) == 14,
406409
"Size of version 24 of Api cannot change");
410+
static_assert(offsetof(OrtCompileApi, ModelCompilationOptions_SetInputModel) / sizeof(void*) == 14,
411+
"Size of version 27 of Api cannot change");
407412

408413
ORT_API(const OrtCompileApi*, OrtCompileAPI::GetCompileApi) {
409414
return &ort_compile_api;

onnxruntime/core/session/onnxruntime_c_api.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4415,7 +4415,7 @@ Second example, if we wanted to add and remove some members, we'd do this:
44154415
In GetApi we now make it return ort_api_3 for version 3.
44164416
*/
44174417

4418-
static constexpr OrtApi ort_api_1_to_27 = {
4418+
static constexpr OrtApi ort_api_1_to_28 = {
44194419
// NOTE: The ordering of these fields MUST not change after that version has shipped since existing binaries depend on this ordering.
44204420

44214421
// Shipped as version 1 - DO NOT MODIFY (see above text for more information)
@@ -4926,6 +4926,8 @@ static constexpr OrtApi ort_api_1_to_27 = {
49264926
&OrtApis::GetMemPatternEnabled,
49274927
&OrtApis::GetSessionExecutionMode,
49284928
&OrtApis::SessionReleaseCapturedGraph,
4929+
// End of Version 27 - DO NOT MODIFY ABOVE (see above text for more information)
4930+
49294931
&OrtApis::SessionOptions_SetEpContextDataReadFunc,
49304932
};
49314933

@@ -4966,9 +4968,10 @@ static_assert(offsetof(OrtApi, CreateExternalInitializerInfo) / sizeof(void*) ==
49664968
static_assert(offsetof(OrtApi, GetTensorElementTypeAndShapeDataReference) / sizeof(void*) == 414, "Size of version 24 API cannot change");
49674969
static_assert(offsetof(OrtApi, SetPerSessionThreadPoolCallbacks) / sizeof(void*) == 418, "Size of version 25 API cannot change");
49684970
// no additions in version 26
4971+
static_assert(offsetof(OrtApi, GetSessionExecutionMode) / sizeof(void*) == 420, "Size of version 27 API cannot change");
49694972

49704973
// So that nobody forgets to finish an API version, this check will serve as a reminder:
4971-
static_assert(std::string_view(ORT_VERSION) == "1.27.0",
4974+
static_assert(std::string_view(ORT_VERSION) == "1.28.0",
49724975
"ORT_Version change detected, please follow below steps to ensure OrtApi is updated properly");
49734976
// 1. Update the hardcoded version string in above static_assert to silence it
49744977
//
@@ -4984,7 +4987,7 @@ static_assert(std::string_view(ORT_VERSION) == "1.27.0",
49844987

49854988
ORT_API(const OrtApi*, OrtApis::GetApi, uint32_t version) {
49864989
if (version >= 1 && version <= ORT_API_VERSION)
4987-
return &ort_api_1_to_27;
4990+
return &ort_api_1_to_28;
49884991

49894992
fprintf(stderr,
49904993
"The requested API version [%u] is not available, only API versions [1, %u] are supported in this build."

0 commit comments

Comments
 (0)