Skip to content
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
61af6c8
OrtGraph: use pre-allocated buffers for array apis
adrianlizarraga Jul 1, 2025
f51a3a2
Merge branch 'main' into adrianl/ep-abi-revert-ort-array-of-pointers
adrianlizarraga Jul 1, 2025
d7265d3
Fix tests to use new Graph_GetInputs
adrianlizarraga Jul 1, 2025
101265a
Remove OrtArrayOfConstObjects
adrianlizarraga Jul 1, 2025
3184633
Try to fix c++ doc gen (broken in main too)
adrianlizarraga Jul 2, 2025
e155494
fix c api doc
adrianlizarraga Jul 2, 2025
0759d62
More c doc gen fixes
adrianlizarraga Jul 2, 2025
005ea7f
Fix c doc gen: qnn option mistaken as html tag
adrianlizarraga Jul 2, 2025
3f51dd4
Refactor function that checks validity of the user-provided destinati…
adrianlizarraga Jul 2, 2025
3fe0520
Merge main and fix conflicts
adrianlizarraga Jul 2, 2025
deeb7e1
Rename result to dst
adrianlizarraga Jul 2, 2025
757e427
Commit example code that converts OrtGraph to GraphProto
adrianlizarraga Jul 2, 2025
b3f4473
Add value_infos to GraphProto
adrianlizarraga Jul 4, 2025
4dc5d24
Merge main and fix conflicts
adrianlizarraga Jul 4, 2025
ff3c94c
Handle initializers
adrianlizarraga Jul 5, 2025
caca22c
Handle serializing attributes and subgraphs. Update Node_GetSubgraph …
adrianlizarraga Jul 5, 2025
6378c78
Working with mnist, 3nested_subgraphs. Can use external data.
adrianlizarraga Jul 5, 2025
08a1d95
Rename file to ort_graph_to_proto.h/cc
adrianlizarraga Jul 5, 2025
28bf2df
Add static_cast
adrianlizarraga Jul 5, 2025
64cabdc
Simplify
adrianlizarraga Jul 5, 2025
c4cbebe
Clarify OrtValueInfo tracking
adrianlizarraga Jul 5, 2025
52340f7
Undo change to cmake file
adrianlizarraga Jul 5, 2025
6c1929f
Merge branch 'main' into adrianl/ep-abi-ort-graph-to-onnx-protobuf
adrianlizarraga Jul 5, 2025
caa4366
Keep small initializers inline
adrianlizarraga Jul 5, 2025
721d8f6
Change signature of function that handles weight data
adrianlizarraga Jul 5, 2025
21ee863
Simplify more: remove class that collected and sorted value infos
adrianlizarraga Jul 6, 2025
b5c7942
Early out when collecting OrtValueInfos
adrianlizarraga Jul 6, 2025
2a1da5e
Make unit tests compare the output of the serialized model to that of…
adrianlizarraga Jul 6, 2025
a4bb7de
Check that output files were actually generated
adrianlizarraga Jul 6, 2025
35cfc92
Add API function: Graph_GetOperatorSets
adrianlizarraga Jul 6, 2025
94611e3
Merge branch 'main' into adrianl/ep-abi-ort-graph-to-onnx-protobuf
adrianlizarraga Jul 7, 2025
1d9bb12
Move header-only utility and add usage documentation
adrianlizarraga Jul 8, 2025
6db79b9
Make example code easier to copy-and-paste by putting it inside /**/ …
adrianlizarraga Jul 8, 2025
753ebd8
Fix typo in example code in documentation
adrianlizarraga Jul 8, 2025
fb5a7e4
Update include/onnxruntime/core/providers/utils/ort_graph_to_proto.h
adrianlizarraga Jul 8, 2025
c90f9d9
Change include guard name to appease optional linter
adrianlizarraga Jul 8, 2025
ce4dd96
Remove 'experimental'
adrianlizarraga Jul 8, 2025
60766e1
Make attribute_names optional
adrianlizarraga Jul 9, 2025
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
718 changes: 718 additions & 0 deletions include/onnxruntime/core/providers/utils/ort_graph_to_proto.h

Large diffs are not rendered by default.

49 changes: 47 additions & 2 deletions include/onnxruntime/core/session/onnxruntime_c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -4749,6 +4749,8 @@ struct OrtApi {
* \param[in] len Number of bytes allowed to store in data
* \param[out] out Number of bytes required to save the data when the call failed, or the real number of bytes saved to data on success
*
* \note Does not support reading graph attributes. Refer to Node_GetSubgraphs.
*
* \since Version 1.17.
*/
ORT_API2_STATUS(ReadOpAttr, _In_ const OrtOpAttr* op_attr, _In_ OrtOpAttrType type, _Inout_ void* data, _In_ size_t len, _Out_ size_t* out);
Expand Down Expand Up @@ -5568,6 +5570,45 @@ struct OrtApi {
*/
ORT_API2_STATUS(Graph_GetOnnxIRVersion, _In_ const OrtGraph* graph, _Out_ int64_t* onnx_ir_version);

/** \brief Returns the number of operator sets that the graph's model uses.
*
* \note An operator set is uniquely identified by the (domain, opset_version) pair. All models must have at
* least one entry that specifies which entry of the ONNX operator set is used. The ONNX domain is represented by
* an empty string.
*
* \param[in] graph The OrtGraph instance.
* \param[out] num_operator_sets Output parameter set to the number of operator sets that the graph's model uses.
*
* \snippet{doc} snippets.dox OrtStatus Return Value
*
* \since Version 1.23.
*/
ORT_API2_STATUS(Graph_GetNumOperatorSets, _In_ const OrtGraph* graph, _Out_ size_t* num_operator_sets);
Comment thread
adrianlizarraga marked this conversation as resolved.

/** \brief Returns the operator sets that the graph's model uses.
*
* \note An operator set is uniquely identified by the (domain, opset_version) pair. All models must have at
* least one entry that specifies which entry of the ONNX operator set is used. The ONNX domain is represented by
* an empty string.
*
* \param[in] graph The OrtGraph instance.
* \param[out] domains Pre-allocated array of `num_operator_sets` elements that is filled with
* null-terminated domain names.
* \param[out] opset_versions Pre-allocated array of `num_operator_sets` elements that is filled with
* the opset version of the corresponding domain in the `domains` array.
* \param[in] num_operator_sets The size of the `domains` and `opset_versions` arrays.
* Typical usage sets this to the result of Graph_GetNumOperatorSets().
* An error status is returned if `num_operator_sets` is less than the actual number
* of operator sets.
*
* \snippet{doc} snippets.dox OrtStatus Return Value
*
* \since Version 1.23.
*/
ORT_API2_STATUS(Graph_GetOperatorSets, _In_ const OrtGraph* graph,
_Out_writes_(num_operator_sets) const char** domains,
_Out_writes_(num_operator_sets) int64_t* opset_versions, _In_ size_t num_operator_sets);

/** \brief Returns the number of graph inputs.
*
* \note The count includes initializers that are included in the list of graph inputs.
Expand Down Expand Up @@ -5933,20 +5974,24 @@ struct OrtApi {

/** \brief Get the subgraphs, as OrtGraph instances, contained by the given node.
*
* \note Only certain operator types (e.g., If and Loop) contain nested subgraphs.
* \note Only certain operator types (e.g., If and Loop) contain nested subgraphs. ONNX nodes store subgraphs in
* their attributes, however, this function must be used to obtain subgraphs from an OrtNode.
*
* \param[in] node The OrtNode instance.
* \param[out] subgraphs Pre-allocated array of `num_subgraphs` elements that is filled with the node's subgraphs.
* \param[in] num_subgraphs The size of the `num_subgraphs` array.
* Typical usage sets this to the result of Node_GetNumSubgraphs(). An error status is
* returned if `num_subgraphs` is less than the number of node subgraphs.
* \param[out] attribute_names Pre-allocated array of `num_subgraphs` elements that is filled with the
* attribute names that correspond to the subgraphs.
*
* \snippet{doc} snippets.dox OrtStatus Return Value
*
* \since Version 1.23.
*/
ORT_API2_STATUS(Node_GetSubgraphs, _In_ const OrtNode* node,
_Out_writes_(num_subgraphs) const OrtGraph** subgraphs, _In_ size_t num_subgraphs);
_Out_writes_(num_subgraphs) const OrtGraph** subgraphs, _In_ size_t num_subgraphs,
_Out_writes_(num_subgraphs) const char** attribute_names);
Comment thread
adrianlizarraga marked this conversation as resolved.
Outdated

/** \brief Get the node's parent OrtGraph instance.
*
Expand Down
21 changes: 20 additions & 1 deletion onnxruntime/core/graph/abi_graph_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,10 @@ struct OrtNode {
/// Gets the node's subgraphs (e.g., subgraphs contained by an If or Loop node).
/// </summary>
/// <param name="subgraphs">Buffer into which to copy the subgraphs.</param>
/// <param name="attribute_names">Buffer into which to copy the attribute name for each subgraph.</param>
/// <returns>A status indicating success or an error.</returns>
virtual onnxruntime::Status GetSubgraphs(gsl::span<const OrtGraph*> subgraphs) const = 0;
virtual onnxruntime::Status GetSubgraphs(gsl::span<const OrtGraph*> subgraphs,
gsl::span<const char*> attribute_names) const = 0;

/// <summary>
/// Gets the node's parent graph, which is the graph that contains this node.
Expand Down Expand Up @@ -280,6 +282,23 @@ struct OrtGraph {
/// <returns>The model's ONNX IR version.</returns>
virtual int64_t GetOnnxIRVersion() const = 0;

/// <summary>
/// Gets the number of operator sets (domain, opset version) the graph's model relies on.
/// </summary>
/// <param name="num_operator_sets">Output parameter set to the number of operator sets.</param>
/// <returns>A status indicating success or an error.</returns>
virtual onnxruntime::Status GetNumOperatorSets(size_t& num_operator_sets) const = 0;

/// <summary>
/// Gets the operator sets the graph's model relies on. An operator set is uniquely identified by a
/// (domain, opset version) pair.
/// </summary>
/// <param name="domains">Buffer into which to copy the domains.</param>
/// <param name="opset_versions">Buffer into which to copy the opset version for each domain.</param>
/// <returns>A status indicating success or an error.</returns>
virtual onnxruntime::Status GetOperatorSets(gsl::span<const char*> domains,
gsl::span<int64_t> opset_versions) const = 0;

/// <summary>
/// Returns the number of graph inputs, including initializers that appear in the list of graph inputs.
/// </summary>
Expand Down
52 changes: 46 additions & 6 deletions onnxruntime/core/graph/ep_api_types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,12 @@ Status EpNode::Create(const Node& node, const EpGraph* ep_graph,

ConvertNodeArgsToValueInfos(ep_graph, value_infos_map, node_implicit_inputs, ep_node_implicit_inputs);

std::vector<gsl::not_null<const Graph*>> node_subgraphs = node.GetSubgraphs();
ep_node_subgraphs.reserve(node_subgraphs.size());
std::unordered_map<std::string, gsl::not_null<const Graph*>> subgraphs_map = node.GetAttributeNameToSubgraphMap();
ep_node_subgraphs.reserve(subgraphs_map.size());

for (gsl::not_null<const Graph*> subgraph : node_subgraphs) {
for (const auto& [attr_name, subgraph] : subgraphs_map) {
SubgraphState subgraph_state;
subgraph_state.attribute_name = attr_name;
subgraph_state.subgraph_viewer = std::make_unique<GraphViewer>(*subgraph);
ORT_RETURN_IF_ERROR(EpGraph::Create(*subgraph_state.subgraph_viewer, subgraph_state.ep_subgraph));
subgraph_state.ep_subgraph->SetParentNode(ep_node.get());
Expand Down Expand Up @@ -233,12 +234,14 @@ Status EpNode::GetNumSubgraphs(size_t& num_subgraphs) const {
return Status::OK();
}

Status EpNode::GetSubgraphs(gsl::span<const OrtGraph*> dst) const {
Status EpNode::GetSubgraphs(gsl::span<const OrtGraph*> subgraphs, gsl::span<const char*> attribute_names) const {
const size_t num_subgraphs = subgraphs_.size();
ORT_RETURN_IF_ERROR((CheckCopyDestination<const OrtGraph*>("node attributes", num_subgraphs, dst)));
ORT_RETURN_IF_ERROR((CheckCopyDestination<const OrtGraph*>("node subgraphs", num_subgraphs, subgraphs)));
ORT_RETURN_IF_ERROR((CheckCopyDestination<const char*>("node subgraph attributes", num_subgraphs, attribute_names)));

for (size_t i = 0; i < num_subgraphs; ++i) {
dst[i] = subgraphs_[i].ep_subgraph.get();
subgraphs[i] = subgraphs_[i].ep_subgraph.get();
attribute_names[i] = subgraphs_[i].attribute_name.c_str();
}

return Status::OK();
Expand Down Expand Up @@ -660,6 +663,43 @@ const std::string& EpGraph::GetName() const { return graph_viewer_.Name(); }

int64_t EpGraph::GetOnnxIRVersion() const { return graph_viewer_.GetOnnxIRVersion(); }

Status EpGraph::GetNumOperatorSets(size_t& num_operator_sets) const {
num_operator_sets = graph_viewer_.DomainToVersionMap().size();
return Status::OK();
}

Status EpGraph::GetOperatorSets(gsl::span<const char*> domains,
gsl::span<int64_t> opset_versions) const {
const std::unordered_map<std::string, int>& domain_to_version = graph_viewer_.DomainToVersionMap();
size_t num_operator_sets = domain_to_version.size();

ORT_RETURN_IF_ERROR((CheckCopyDestination<const char*>("operator set domains", num_operator_sets, domains)));
ORT_RETURN_IF_ERROR((CheckCopyDestination<int64_t>("operator set versions", num_operator_sets, opset_versions)));

// Collect (domain, version) pairs and sort them by domain to ensure user always gets a stable ordering.
std::vector<std::pair<const char*, int>> pairs;
pairs.reserve(num_operator_sets);

for (const auto& [domain, version] : domain_to_version) {
pairs.emplace_back(domain.c_str(), version);
}

std::sort(pairs.begin(), pairs.end(),
[](const std::pair<const char*, int>& a, const std::pair<const char*, int>& b) -> bool {
return std::strcmp(a.first, b.first) < 0;
});

// Copy sorted (domain, version) pairs into the destination buffers.
size_t index = 0;
for (const auto& [domain_c_str, version] : pairs) {
domains[index] = domain_c_str;
opset_versions[index] = version;
index++;
}

return Status::OK();
}

size_t EpGraph::GetNumInputs() const {
return inputs_.size();
}
Expand Down
11 changes: 10 additions & 1 deletion onnxruntime/core/graph/ep_api_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ struct EpNode : public OrtNode {
struct SubgraphState {
SubgraphState() = default;
SubgraphState(SubgraphState&& other) = default;
std::string attribute_name;
std::unique_ptr<GraphViewer> subgraph_viewer; // The graph_viewer wrapped by EpGraph below.
std::unique_ptr<EpGraph> ep_subgraph;
};
Expand Down Expand Up @@ -182,7 +183,7 @@ struct EpNode : public OrtNode {
Status GetNumSubgraphs(size_t& num_subgraphs) const override;

// Gets the subgraphs contained by this node.
Status GetSubgraphs(gsl::span<const OrtGraph*> subgraphs) const override;
Status GetSubgraphs(gsl::span<const OrtGraph*> subgraphs, gsl::span<const char*> attribute_names) const override;

// Gets this node's parent graph, which is the graph that directly contains this node.
Status GetGraph(const OrtGraph*& parent_graph) const override;
Expand Down Expand Up @@ -271,6 +272,14 @@ struct EpGraph : public OrtGraph {
// Returns the model's ONNX IR version.
int64_t GetOnnxIRVersion() const override;

// Gets the number of operator sets that the graph's model uses.
Status GetNumOperatorSets(size_t& num_operator_sets) const override;

// Gets the operator sets that the graph's model uses. An operator set is uniquely identified by a
// (domain, opset version) pair.
Status GetOperatorSets(gsl::span<const char*> domains,
gsl::span<int64_t> opset_versions) const override;

// Get the number of graph inputs, including initializers that are listed as graph inputs.
size_t GetNumInputs() const override;

Expand Down
14 changes: 13 additions & 1 deletion onnxruntime/core/graph/model_editor_api_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ struct ModelEditorNode : public OrtNode {
"OrtModelEditorApi does not support getting the subgraphs for OrtNode");
}

Status GetSubgraphs(gsl::span<const OrtGraph*> /*subgraphs*/) const override {
Status GetSubgraphs(gsl::span<const OrtGraph*> /*subgraphs*/,
gsl::span<const char*> /*attribute_names*/) const override {
return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED,
"OrtModelEditorApi does not support getting the subgraphs for OrtNode");
}
Expand Down Expand Up @@ -176,6 +177,17 @@ struct ModelEditorGraph : public OrtGraph {
return ONNX_NAMESPACE::Version::IR_VERSION;
}

Status GetNumOperatorSets(size_t& /*num_operator_sets*/) const override {
return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED,
"OrtModelEditorApi does not support getting the graph's operator sets.");
}

Status GetOperatorSets(gsl::span<const char*> /*domains*/,
gsl::span<int64_t> /*opset_versions*/) const override {
return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED,
"OrtModelEditorApi does not support getting the graph's operator sets.");
}

size_t GetNumInputs() const override { return inputs.size(); }

Status GetInputs(gsl::span<const OrtValueInfo*> /*result*/) const override {
Expand Down
31 changes: 29 additions & 2 deletions onnxruntime/core/session/onnxruntime_c_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2591,6 +2591,29 @@ ORT_API_STATUS_IMPL(OrtApis::Graph_GetOnnxIRVersion, _In_ const OrtGraph* graph,
API_IMPL_END
}

ORT_API_STATUS_IMPL(OrtApis::Graph_GetNumOperatorSets, _In_ const OrtGraph* graph, _Out_ size_t* num_operator_sets) {
API_IMPL_BEGIN
if (num_operator_sets == nullptr) {
return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "'num_operator_sets' argument is NULL");
}

ORT_API_RETURN_IF_STATUS_NOT_OK(graph->GetNumOperatorSets(*num_operator_sets));
return nullptr;
API_IMPL_END
}

ORT_API_STATUS_IMPL(OrtApis::Graph_GetOperatorSets, _In_ const OrtGraph* graph,
_Out_writes_(num_operator_sets) const char** domains,
_Out_writes_(num_operator_sets) int64_t* opset_versions, _In_ size_t num_operator_sets) {
API_IMPL_BEGIN
gsl::span<const char*> domains_span(domains, num_operator_sets);
gsl::span<int64_t> versions_span(opset_versions, num_operator_sets);
ORT_API_RETURN_IF_STATUS_NOT_OK(graph->GetOperatorSets(domains_span, versions_span));

return nullptr;
API_IMPL_END
}

ORT_API_STATUS_IMPL(OrtApis::Graph_GetNumInputs, _In_ const OrtGraph* graph, _Out_ size_t* num_inputs) {
API_IMPL_BEGIN
if (num_inputs == nullptr) {
Expand Down Expand Up @@ -2922,10 +2945,12 @@ ORT_API_STATUS_IMPL(OrtApis::Node_GetNumSubgraphs, _In_ const OrtNode* node, _Ou
}

ORT_API_STATUS_IMPL(OrtApis::Node_GetSubgraphs, _In_ const OrtNode* node,
_Out_writes_(num_subgraphs) const OrtGraph** subgraphs, _In_ size_t num_subgraphs) {
_Out_writes_(num_subgraphs) const OrtGraph** subgraphs, _In_ size_t num_subgraphs,
_Out_writes_(num_subgraphs) const char** attribute_names) {
API_IMPL_BEGIN
gsl::span<const OrtGraph*> graphs_span(subgraphs, num_subgraphs);
ORT_API_RETURN_IF_STATUS_NOT_OK(node->GetSubgraphs(graphs_span));
gsl::span<const char*> attr_names_span(attribute_names, num_subgraphs);
ORT_API_RETURN_IF_STATUS_NOT_OK(node->GetSubgraphs(graphs_span, attr_names_span));
return nullptr;
API_IMPL_END
}
Expand Down Expand Up @@ -3594,6 +3619,8 @@ static constexpr OrtApi ort_api_1_to_23 = {
&OrtApis::ValueInfo_IsFromOuterScope,
&OrtApis::Graph_GetName,
&OrtApis::Graph_GetOnnxIRVersion,
&OrtApis::Graph_GetNumOperatorSets,
&OrtApis::Graph_GetOperatorSets,
&OrtApis::Graph_GetNumInputs,
&OrtApis::Graph_GetInputs,
&OrtApis::Graph_GetNumOutputs,
Expand Down
7 changes: 6 additions & 1 deletion onnxruntime/core/session/ort_apis.h
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,10 @@ ORT_API_STATUS_IMPL(ValueInfo_IsFromOuterScope, _In_ const OrtValueInfo* value_i
// OrtGraph
ORT_API_STATUS_IMPL(Graph_GetName, _In_ const OrtGraph* graph, _Outptr_ const char** graph_name);
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);
ORT_API_STATUS_IMPL(Graph_GetOperatorSets, _In_ const OrtGraph* graph,
_Out_writes_(num_operator_sets) const char** domains,
_Out_writes_(num_operator_sets) int64_t* opset_versions, _In_ size_t num_operator_sets);
ORT_API_STATUS_IMPL(Graph_GetNumInputs, _In_ const OrtGraph* graph, _Out_ size_t* num_inputs);
ORT_API_STATUS_IMPL(Graph_GetInputs, _In_ const OrtGraph* graph,
_Out_writes_(num_inputs) const OrtValueInfo** inputs, _In_ size_t num_inputs);
Expand Down Expand Up @@ -671,7 +675,8 @@ ORT_API_STATUS_IMPL(OpAttr_GetType, _In_ const OrtOpAttr* attribute, _Out_ OrtOp
ORT_API_STATUS_IMPL(OpAttr_GetName, _In_ const OrtOpAttr* attribute, _Outptr_ const char** name);
ORT_API_STATUS_IMPL(Node_GetNumSubgraphs, _In_ const OrtNode* node, _Out_ size_t* num_subgraphs);
ORT_API_STATUS_IMPL(Node_GetSubgraphs, _In_ const OrtNode* node,
_Out_writes_(num_subgraphs) const OrtGraph** subgraphs, _In_ size_t num_subgraphs);
_Out_writes_(num_subgraphs) const OrtGraph** subgraphs, _In_ size_t num_subgraphs,
_Out_writes_(num_subgraphs) const char** attribute_names);
ORT_API_STATUS_IMPL(Node_GetGraph, _In_ const OrtNode* node, _Outptr_result_maybenull_ const OrtGraph** graph);

ORT_API_STATUS_IMPL(GetRunConfigEntry, _In_ const OrtRunOptions* options,
Expand Down
Loading
Loading