Commit db6d83b
[EP ABI] Initial support for kernel-based EPs (microsoft#26206)
### Description
This PR adds an initial set of C APIs necessary to support kernel
registration for plugin EPs.
### Example use
The example plugin EP implementation now registers `MemcpyFromHost` and
`MemcpyToHost` operator kernels using the new APIs. New utilities in the
example implementation make the process of defining operator kernels
very similar to the existing process used by provider-bridge EPs.
First, the operator kernel class is defined:
```c++
// File: onnxruntime/test/autoep/library/kernels/memcpy.h
struct Memcpy : public OrtKernelImpl {
static OrtStatus* Create(const OrtKernelInfo* info, void* state, /*out*/ std::unique_ptr<Memcpy>& kernel);
Memcpy(const OrtKernelInfo* info, void* state);
static OrtStatus* ORT_API_CALL ComputeImpl(OrtKernelImpl* this_ptr, OrtKernelContext* kernel_ctx) noexcept;
static void ORT_API_CALL ReleaseImpl(OrtKernelImpl* this_ptr) noexcept;
OrtStatus* DoCompute(OrtKernelContext* kernel_ctx) noexcept;
private:
const OrtKernelInfo* info_;
void* state_; // Custom state passed from OrtEp
};
```
Then, a macro defines a function that can be called to register the
operator with the EP's kernel registry:
```c++
// File: onnxruntime/test/autoep/library/kernels/memcpy.cc
ONNX_OPERATOR_KERNEL_EX(
MemcpyFromHost,
kOnnxDomain,
1,
(Ort::KernelDefBuilder()
.SetInputMemType(0, OrtMemType::OrtMemTypeCPUInput)
.AddTypeConstraint("T", MLDataTypes::GetTensorType(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT))),
Memcpy)
ONNX_OPERATOR_KERNEL_EX(
MemcpyToHost,
kOnnxDomain,
1,
(Ort::KernelDefBuilder()
.SetOutputMemType(0, OrtMemType::OrtMemTypeCPUOutput)
.AddTypeConstraint("T", MLDataTypes::GetTensorType(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT))),
Memcpy)
```
Lastly, the functions defined by the above macro are entered into a
table:
```c++
// File: onnxruntime/test/autoep/library/ep_kernel_registration.cc
// Include kernel files:
#include "kernels/memcpy.h"
// Forward declarations of kernel classes used as template args for BuildKernelCreateInfo
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kOnnxDomain, 1, MemcpyFromHost);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kOnnxDomain, 1, MemcpyToHost);
// Table of BuildKernelCreateInfo functions for each operator
static const BuildKernelCreateInfoFn build_kernel_create_info_funcs[] = {
BuildKernelCreateInfo<void>, // Dummy to avoid table becoming empty.
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kOnnxDomain, 1, MemcpyFromHost)>,
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kOnnxDomain, 1, MemcpyToHost)>,
};
```
The [example EP processes the entries in the above
table](https://github.com/microsoft/onnxruntime/blob/adrianl/ep-abi-kernel-based-eps/onnxruntime/test/autoep/library/ep_kernel_registration.cc)
to add information about the supported operator kernels to the EP's
kernel registry (`OrtKernelRegistry`).
Additionally, during the call to `OrtEp::GetCapability`, an EP can now
lookup registered kernel definitions via the new API
`EpGraphSupportInfo_LookUpKernel`. Note that an EP would not normally
lookup kernels for `Memcpy**Host`, which are inserted by ORT. Instead,
it would be used to look up other registered operator kernels like
`Conv`, for example.
```c++
static OrtStatus* ORT_API_CALL GetCapabilityImpl(OrtEp* this_ptr, const OrtGraph* graph,
OrtEpGraphSupportInfo* graph_support_info) noexcept {
// ...
for (const OrtNode* node : nodes) {
const OrtKernelDef* kernel_def = nullptr;
OrtStatus* status = this_ep->ep_api->EpGraphSupportInfo_LookUpKernel(graph_support_info, node, &kernel_def);
if (status != nullptr) {
return status;
}
if (kernel_def != nullptr) { // Take node if this EP has a registered kernel for it.
if (OrtStatus* st = this_ep->ep_api->EpGraphSupportInfo_AddSingleNode(graph_support_info, node);
st != nullptr) {
return st;
}
}
}
return nullptr;
}
```
### EP implementation details
An EP instance (i.e., `OrtEp`) that needs to register operator kernels
with ONNX Runtime must implement the following
`OrtEp::GetKernelRegistry()` function:
| Function Signature | Description |
|--------------------|-------------|
|**GetKernelRegistry**<br/><br/>**Returns**:`OrtStatus*`<br/><br/>**Parameters:**<br/><ul><li>`OrtEp*
this_ptr`: The OrtEp instance.</li><li>`const OrtKernelRegistry**
kernel_registry`: Output parameter set to the EP's kernel registry,
which must remain valid throughout the lifetime of the EP.</li></ul>|
Gets the execution provider's kernel registry, if
any.<br/><br/>**Remarks:** A kernel registry contains kernel creation
information for operator kernels supported by an EP.<br/><br/>**Note:**
Implementation of this function is optional. If set to NULL, ORT assumes
the EP compiles nodes. |
If defined by the EP, the `OrtEp::GetKernelRegistry()` function is
[called by ONNX
Runtime](https://github.com/microsoft/onnxruntime/blob/0f7145f3809103c123de2d281a6b310677e6d56c/onnxruntime/core/session/plugin_ep/ep_plugin_provider_interfaces.cc#L146-L147)
after creating an instance of the `OrtEp` in order to retrieve the EP's
kernel registry.
#### APIs used by EP to add entries to kernel registry
An EP's kernel registry (`OrtKernelRegistry`) contains **information**
necessary for the (later) creation of operator kernels supported by an
EP. Conceptually, a kernel registry contains an array of "kernel
creation information" elements, one per operator. Each such element
consists of:
- A kernel **definition** (`OrtKernelDef`), which specifies operator
type, supported versions, type constraints, I/O memory types, etc.
- A function of type `OrtKernelCreateFunc` that ORT calls to create an
instance of the kernel (`OrtKernelImpl`).
- Custom opaque state (provided by the `OrtEp`) that is passed to the
`OrtKernelCreateFunc`.
An EP uses the following `OrtEpApi::KernelRegistry_AddKernel()` function
to add an entry for one supported operator.
| Function Signature | Description |
|--------------------|-------------|
|**KernelRegistry_AddKernel**<br/><br/>**Returns**:`OrtStatus*`<br/><br/>**Parameters:**<br/><ul><li>`OrtKernelRegistry*
kernel_registry`: The OrtKernelRegistry instance.</li><li>`const
OrtKernelDef* kernel_def`: The kernel definition, which includes
operator type, version, EP name, type constraints,
etc.</li><li>`OrtKernelCreateFunc kernel_create_func`: Function that
creates an instance of the operator kernel as a OrtKernelImpl
instance.</li><li>`void* kernel_create_func_state`: Custom state passed
to the kernel creation function. Can be null.</li></ul>| Adds kernel
creation information for a supported operator kernel to the given kernel
registry.<br/><br/>**Remarks:** Refer to OrtEp::GetKernelRegistry, which
returns an EP's kernel registry to ORT. |
##### Building a kernel definition
An EP uses a kernel definition builder (`OrtKernelDefBuilder`) to create
a kernel definition (`OrtKernelDef`). The following table lists **some**
of the C APIs related to building a kernel definition. The above
`ONNX_OPERATOR_KERNEL_EX` macro [uses these
APIs](https://github.com/microsoft/onnxruntime/blob/adrianl/ep-abi-kernel-based-eps/onnxruntime/test/autoep/library/kernels/utils.h#L42).
| Function Signature | Description |
|--------------------|-------------|
|**KernelDefBuilder_SetOperatorType**<br/><br/>**Returns**:`OrtStatus*`<br/><br/>**Parameters:**<br/><ul><li>`OrtKernelDefBuilder*
kernel_def_builder`: The OrtKernelDefBuilder instance.</li><li>`const
char* op_type`: A null-terminated string representing the operator
type.</li></ul>| Sets the kernel's operator type. |
|**KernelDefBuilder_SetDomain**<br/><br/>**Returns**:`OrtStatus*`<br/><br/>**Parameters:**<br/><ul><li>`OrtKernelDefBuilder*
kernel_def_builder`: The OrtKernelDefBuilder instance.</li><li>`const
char* domain`: A null-terminated string representing the operator's
domain.</li></ul>| Sets the kernel's domain. |
| ... | ... |
|**KernelDefBuilder_Build**<br/><br/>**Returns**:`OrtStatus*`<br/><br/>**Parameters:**<br/><ul><li>`OrtKernelDefBuilder*
kernel_def_builder`: The OrtKernelDefBuilder
instance.</li><li>`OrtKernelDef** kernel_def_out`: The new OrtKernelDef
instance.</li></ul>| Creates a OrtKernelDef instance from the given
kernel definition builder. |
##### Defining a kernel implementation
An EP defines a kernel implementation by initializing an instance of
`OrtKernelImpl` (shown below) with function pointers for computation,
release, etc.
```c++
struct OrtKernelImpl {
uint32_t ort_version_supported; ///< Must be initialized to ORT_API_VERSION
/** \brief Computation function called to execute the kernel on an EP.
*
* \param[in] this_ptr The OrtKernelImpl instance.
* \param[in] context The OrtKernelContext instance that provides access to the inputs and outputs.
*
* \snippet{doc} snippets.dox OrtStatus Return Value
*
* \since Version 1.24.
*/
ORT_API2_STATUS(Compute, _In_ OrtKernelImpl* this_ptr, _In_ OrtKernelContext* context);
/** \brief Called by ORT to release the OrtKernelImpl instance and its resources.
*
* \param[in] this_ptr The OrtKernelImpl instance.
*
* \since Version 1.24.
*/
ORT_API_T(void, Release, _In_ OrtKernelImpl* this_ptr);
};
```
As shown previously, the example EP creates a `Memcpy` class that
inherits from `OrtKernelImpl` and [implements the above
functions](https://github.com/microsoft/onnxruntime/blob/adrianl/ep-abi-kernel-based-eps/onnxruntime/test/autoep/library/kernels/memcpy.cc).
##### Defining a kernel creation function
An EP must provide a function of type `OrtKernelCreateFunc` that ORT can
later call to create an instance of a kernel (`OrtKernelImpl`). The
signature of the `OrtKernelCreateFunc` is shown below.
```c++
/** \brief Type definition for a function that creates an OrtKernelImpl instance for an operator kernel.
*
* \param[in] ctx Unused/reserved for future use.
* \param[in] kernel_create_func_state Opaque state initially provided by the EP that registered the kernel.
* Refer to OrtEpApi::KernelRegistry_AddKernel(). May be null.
* \param[in] info The OrtKernelInfo instance that provides access to the kernel's input and output characteristics.
* \param[out] kernel_out Output parameter set to the new OrtKernelImpl instance.
*
* \snippet{doc} snippets.dox OrtStatus Return Value
*
* \since Version 1.24.
*/
typedef OrtStatus*(ORT_API_CALL* OrtKernelCreateFunc)(_In_ OrtKernelCreateContext* ctx, // unused/reserved as of 1.24
_In_ void* kernel_create_func_state,
_In_ const OrtKernelInfo* info,
_Outptr_result_maybenull_ OrtKernelImpl** kernel_out);
```
The example EP declares kernel creation functions via use of the
previously mentioned `ONNX_OPERATOR_KERNEL_EX`
[macro](https://github.com/microsoft/onnxruntime/blob/adrianl/ep-abi-kernel-based-eps/onnxruntime/test/autoep/library/kernels/utils.h#L56-L64).
If one were to expand the macro call, the kernel creation function for
`MemcpyFromHost` would look similar to the following snippet:
```c++
OrtStatus* ORT_API_CALL CreateMemcpyKernel(OrtKernelCreateContext* /*ctx*/, void* kernel_create_func_state,
const OrtKernelInfo* info, OrtKernelImpl** kernel_out) {
*kernel_out = nullptr;
std::unique_ptr<Memcpy> kernel;
RETURN_IF_ERROR(Memcpy::Create(info, kernel_create_func_state, kernel));
*kernel_out = kernel.release();
return nullptr;
}
```
### 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. -->
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Edward Chen <18449977+edgchen1@users.noreply.github.com>1 parent 8a433fb commit db6d83b
42 files changed
Lines changed: 2741 additions & 64 deletions
File tree
- cmake
- include/onnxruntime/core/session
- onnxruntime
- core/session
- plugin_ep
- test
- autoep
- library
- example_plugin_ep_kernel_registry
- kernels
- example_plugin_ep_virt_gpu
- example_plugin_ep
- framework
- testdata
- tools/ci_build
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2094 | 2094 | | |
2095 | 2095 | | |
2096 | 2096 | | |
| 2097 | + | |
| 2098 | + | |
| 2099 | + | |
| 2100 | + | |
| 2101 | + | |
| 2102 | + | |
| 2103 | + | |
| 2104 | + | |
| 2105 | + | |
| 2106 | + | |
| 2107 | + | |
| 2108 | + | |
| 2109 | + | |
| 2110 | + | |
| 2111 | + | |
| 2112 | + | |
| 2113 | + | |
| 2114 | + | |
| 2115 | + | |
| 2116 | + | |
| 2117 | + | |
| 2118 | + | |
| 2119 | + | |
| 2120 | + | |
| 2121 | + | |
| 2122 | + | |
| 2123 | + | |
| 2124 | + | |
| 2125 | + | |
| 2126 | + | |
| 2127 | + | |
| 2128 | + | |
| 2129 | + | |
| 2130 | + | |
| 2131 | + | |
| 2132 | + | |
| 2133 | + | |
| 2134 | + | |
| 2135 | + | |
| 2136 | + | |
| 2137 | + | |
| 2138 | + | |
| 2139 | + | |
| 2140 | + | |
2097 | 2141 | | |
2098 | 2142 | | |
2099 | 2143 | | |
| |||
2129 | 2173 | | |
2130 | 2174 | | |
2131 | 2175 | | |
2132 | | - | |
| 2176 | + | |
2133 | 2177 | | |
2134 | 2178 | | |
2135 | 2179 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
644 | 644 | | |
645 | 645 | | |
646 | 646 | | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
647 | 650 | | |
648 | 651 | | |
649 | 652 | | |
| |||
3292 | 3295 | | |
3293 | 3296 | | |
3294 | 3297 | | |
| 3298 | + | |
| 3299 | + | |
| 3300 | + | |
| 3301 | + | |
| 3302 | + | |
| 3303 | + | |
| 3304 | + | |
| 3305 | + | |
| 3306 | + | |
| 3307 | + | |
| 3308 | + | |
| 3309 | + | |
| 3310 | + | |
| 3311 | + | |
| 3312 | + | |
| 3313 | + | |
| 3314 | + | |
| 3315 | + | |
| 3316 | + | |
| 3317 | + | |
| 3318 | + | |
| 3319 | + | |
| 3320 | + | |
| 3321 | + | |
| 3322 | + | |
| 3323 | + | |
| 3324 | + | |
| 3325 | + | |
| 3326 | + | |
| 3327 | + | |
| 3328 | + | |
| 3329 | + | |
| 3330 | + | |
| 3331 | + | |
| 3332 | + | |
| 3333 | + | |
| 3334 | + | |
| 3335 | + | |
| 3336 | + | |
| 3337 | + | |
| 3338 | + | |
| 3339 | + | |
| 3340 | + | |
| 3341 | + | |
| 3342 | + | |
| 3343 | + | |
| 3344 | + | |
| 3345 | + | |
| 3346 | + | |
| 3347 | + | |
| 3348 | + | |
| 3349 | + | |
| 3350 | + | |
| 3351 | + | |
| 3352 | + | |
| 3353 | + | |
| 3354 | + | |
| 3355 | + | |
| 3356 | + | |
| 3357 | + | |
| 3358 | + | |
| 3359 | + | |
| 3360 | + | |
| 3361 | + | |
| 3362 | + | |
| 3363 | + | |
| 3364 | + | |
| 3365 | + | |
| 3366 | + | |
| 3367 | + | |
| 3368 | + | |
| 3369 | + | |
| 3370 | + | |
| 3371 | + | |
| 3372 | + | |
| 3373 | + | |
| 3374 | + | |
| 3375 | + | |
| 3376 | + | |
| 3377 | + | |
| 3378 | + | |
| 3379 | + | |
| 3380 | + | |
| 3381 | + | |
3295 | 3382 | | |
3296 | 3383 | | |
Lines changed: 141 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
3572 | 3573 | | |
3573 | 3574 | | |
3574 | 3575 | | |
| 3576 | + | |
| 3577 | + | |
| 3578 | + | |
| 3579 | + | |
| 3580 | + | |
| 3581 | + | |
| 3582 | + | |
| 3583 | + | |
| 3584 | + | |
| 3585 | + | |
| 3586 | + | |
| 3587 | + | |
| 3588 | + | |
| 3589 | + | |
| 3590 | + | |
| 3591 | + | |
| 3592 | + | |
| 3593 | + | |
| 3594 | + | |
| 3595 | + | |
| 3596 | + | |
| 3597 | + | |
| 3598 | + | |
| 3599 | + | |
| 3600 | + | |
| 3601 | + | |
| 3602 | + | |
| 3603 | + | |
| 3604 | + | |
| 3605 | + | |
| 3606 | + | |
| 3607 | + | |
| 3608 | + | |
| 3609 | + | |
| 3610 | + | |
| 3611 | + | |
| 3612 | + | |
| 3613 | + | |
| 3614 | + | |
| 3615 | + | |
| 3616 | + | |
| 3617 | + | |
| 3618 | + | |
| 3619 | + | |
| 3620 | + | |
| 3621 | + | |
| 3622 | + | |
| 3623 | + | |
| 3624 | + | |
| 3625 | + | |
| 3626 | + | |
| 3627 | + | |
| 3628 | + | |
| 3629 | + | |
| 3630 | + | |
| 3631 | + | |
| 3632 | + | |
| 3633 | + | |
| 3634 | + | |
| 3635 | + | |
| 3636 | + | |
| 3637 | + | |
| 3638 | + | |
| 3639 | + | |
| 3640 | + | |
| 3641 | + | |
| 3642 | + | |
| 3643 | + | |
| 3644 | + | |
| 3645 | + | |
| 3646 | + | |
| 3647 | + | |
| 3648 | + | |
| 3649 | + | |
| 3650 | + | |
| 3651 | + | |
| 3652 | + | |
| 3653 | + | |
| 3654 | + | |
| 3655 | + | |
| 3656 | + | |
| 3657 | + | |
| 3658 | + | |
| 3659 | + | |
| 3660 | + | |
| 3661 | + | |
| 3662 | + | |
| 3663 | + | |
| 3664 | + | |
| 3665 | + | |
| 3666 | + | |
| 3667 | + | |
| 3668 | + | |
| 3669 | + | |
| 3670 | + | |
| 3671 | + | |
| 3672 | + | |
| 3673 | + | |
| 3674 | + | |
| 3675 | + | |
| 3676 | + | |
| 3677 | + | |
| 3678 | + | |
| 3679 | + | |
| 3680 | + | |
| 3681 | + | |
| 3682 | + | |
| 3683 | + | |
| 3684 | + | |
| 3685 | + | |
| 3686 | + | |
| 3687 | + | |
| 3688 | + | |
| 3689 | + | |
| 3690 | + | |
| 3691 | + | |
| 3692 | + | |
| 3693 | + | |
| 3694 | + | |
| 3695 | + | |
| 3696 | + | |
| 3697 | + | |
| 3698 | + | |
| 3699 | + | |
| 3700 | + | |
| 3701 | + | |
| 3702 | + | |
| 3703 | + | |
| 3704 | + | |
| 3705 | + | |
| 3706 | + | |
| 3707 | + | |
| 3708 | + | |
| 3709 | + | |
| 3710 | + | |
| 3711 | + | |
| 3712 | + | |
| 3713 | + | |
| 3714 | + | |
| 3715 | + | |
3575 | 3716 | | |
0 commit comments