From aae35f27598a62670399d6d8802d6841bb3afdc6 Mon Sep 17 00:00:00 2001 From: Edward Chen <18449977+edgchen1@users.noreply.github.com> Date: Fri, 30 Sep 2022 13:50:39 -0700 Subject: [PATCH] Binary size reduction in KernelTypeStrResolver and GraphPartitioner (#13172) Reduce binary size for minimal Android builds. - reduce places where Status objects are created in KernelTypeStrResolver::LoadFromOrtFormat() - remove some unused parameters (in a base minimal build) and code in graph_partitioner.cc --- .../core/framework/graph_partitioner.cc | 70 +++++++++++++------ .../framework/kernel_type_str_resolver.cc | 63 ++++++++++++----- 2 files changed, 96 insertions(+), 37 deletions(-) diff --git a/onnxruntime/core/framework/graph_partitioner.cc b/onnxruntime/core/framework/graph_partitioner.cc index 9749dc5676..fda3c19164 100644 --- a/onnxruntime/core/framework/graph_partitioner.cc +++ b/onnxruntime/core/framework/graph_partitioner.cc @@ -3,6 +3,7 @@ #include "core/framework/graph_partitioner.h" +#include #include #include "core/framework/compute_capability.h" @@ -44,7 +45,6 @@ NonCudaOps non_cuda; namespace onnxruntime { namespace { - // contains some common parameters used by the partitioning helper functions struct PartitionParams { std::reference_wrapper graph; @@ -103,7 +103,7 @@ static bool TryAssignSingleNode(Graph& graph, const std::string& provider_type) { // The provider can run a single node in the if not using meta-defs. // A fused kernel is not supported in this case. - ORT_ENFORCE(1 == indexed_sub_graph.nodes.size()); + assert(indexed_sub_graph.GetMetaDef() == nullptr && indexed_sub_graph.nodes.size() == 1); auto* node = graph.GetNode(indexed_sub_graph.nodes[0]); if (nullptr != node && node->GetExecutionProviderType().empty()) { @@ -115,17 +115,31 @@ static bool TryAssignSingleNode(Graph& graph, return false; } -static Status GetCapabilityForEP(Graph& graph, KernelRegistryManager& kernel_registry_mgr, - IExecutionProvider& current_ep, GraphPartitioner::Mode mode, - std::vector>& capabilities, - TransformLayoutFunction transform_layout) { +namespace { +struct GetCapabilityForEPParams { + std::reference_wrapper graph; + std::reference_wrapper kernel_registry_mgr; + std::reference_wrapper current_ep; + std::reference_wrapper>> capabilities; + +#if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) + GraphPartitioner::Mode mode; + TransformLayoutFunction transform_layout; +#endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) +}; +} // namespace + +static Status GetCapabilityForEP(const GetCapabilityForEPParams& params) { + auto& current_ep = params.current_ep.get(); const auto& ep_type = current_ep.Type(); - if (current_ep.GetPreferredLayout() == DataLayout::NHWC && !transform_layout) { +#if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) + if (current_ep.GetPreferredLayout() == DataLayout::NHWC && !params.transform_layout) { LOGS_DEFAULT(WARNING) << ep_type << " cannot be used with this model due to its ONNX opset not being supported by " "the layout transformer."; return Status::OK(); } +#endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) auto get_capabilities = [](const IExecutionProvider& ep, const GraphViewer& graph_viewer, @@ -142,11 +156,15 @@ static Status GetCapabilityForEP(Graph& graph, KernelRegistryManager& kernel_reg return capabilities; }; + const auto& kernel_registry_mgr = params.kernel_registry_mgr.get(); const auto kernel_registries_for_ep = kernel_registry_mgr.GetKernelRegistriesByProviderType(ep_type); const KernelLookup kernel_lookup{ep_type, kernel_registries_for_ep, kernel_registry_mgr.GetKernelTypeStrResolver()}; + auto& graph = params.graph.get(); + auto& capabilities = params.capabilities.get(); + { const GraphViewer graph_viewer(graph); capabilities = get_capabilities(current_ep, graph_viewer, kernel_lookup); @@ -159,7 +177,7 @@ static Status GetCapabilityForEP(Graph& graph, KernelRegistryManager& kernel_reg #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) // Run layout transformer only for EPs other than CPU EP and provided the preferred layout is NHWC // CPU EP layout transformation happens later when level 3 transformers are run. - if (mode != GraphPartitioner::Mode::kAssignOnly && + if (params.mode != GraphPartitioner::Mode::kAssignOnly && current_ep.GetPreferredLayout() == DataLayout::NHWC) { for (auto& capability : capabilities) { TryAssignNodes(graph, *capability->sub_graph, ep_type); @@ -169,7 +187,7 @@ static Status GetCapabilityForEP(Graph& graph, KernelRegistryManager& kernel_reg // Perform layout transformation on the specific EP assigned graph bool modified = false; - ORT_RETURN_IF_ERROR(transform_layout(graph, modified, current_ep)); + ORT_RETURN_IF_ERROR(params.transform_layout(graph, modified, current_ep)); // It is possible some new nodes are introduced during transformation. These nodes can be either existing nodes // which are reconstructed to update domain or completely new nodes which are necessary for layout transformation. @@ -213,8 +231,6 @@ static Status GetCapabilityForEP(Graph& graph, KernelRegistryManager& kernel_reg } } } -#else // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) - ORT_UNUSED_PARAMETER(mode); #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) return Status::OK(); @@ -354,8 +370,15 @@ static Status PartitionOnnxFormatModelImpl(Graph& graph, FuncManager& func_mgr, // run the function by SessionOption, we should create a function kernel for it and // delegate the compute to the functions inside the dlls. std::vector> capabilities; - ORT_RETURN_IF_ERROR(GetCapabilityForEP(graph, kernel_registry_mgr, current_ep, mode, capabilities, - transform_layout_function)); + const auto get_capability_params = GetCapabilityForEPParams{ + std::ref(graph), + std::cref(kernel_registry_mgr), + std::ref(current_ep), + std::ref(capabilities), + mode, + transform_layout_function, + }; + ORT_RETURN_IF_ERROR(GetCapabilityForEP(get_capability_params)); if (capabilities.empty()) { return Status::OK(); } @@ -570,16 +593,20 @@ static Status PartitionOrtFormatModelImpl(const PartitionParams& partition_param } } - const std::string& type = current_ep.Type(); std::vector> capabilities; + // clang-format off + const auto get_capability_params = GetCapabilityForEPParams{ + std::ref(graph), + std::cref(kernel_registry_mgr), + std::ref(current_ep), + std::ref(capabilities), #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) - TransformLayoutFunction transform_layout_function = partition_params.transform_layout_function; -#else - TransformLayoutFunction transform_layout_function{}; -#endif - ORT_RETURN_IF_ERROR(GetCapabilityForEP(graph, kernel_registry_mgr, current_ep, - GraphPartitioner::Mode::kOrtFormatLoad, capabilities, - transform_layout_function)); + GraphPartitioner::Mode::kOrtFormatLoad, + partition_params.transform_layout_function, +#endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) + }; + // clang-format on + ORT_RETURN_IF_ERROR(GetCapabilityForEP(get_capability_params)); if (capabilities.empty()) { return Status::OK(); } @@ -594,6 +621,7 @@ static Status PartitionOrtFormatModelImpl(const PartitionParams& partition_param compilation_entries.reserve(capabilities.size()); #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) + const std::string& type = current_ep.Type(); for (const auto& capability : capabilities) { const IndexedSubGraph& indexed_sub_graph = *capability->sub_graph; const IndexedSubGraph::MetaDef* metadef = indexed_sub_graph.GetMetaDef(); diff --git a/onnxruntime/core/framework/kernel_type_str_resolver.cc b/onnxruntime/core/framework/kernel_type_str_resolver.cc index 1d87a77fe4..1923534750 100644 --- a/onnxruntime/core/framework/kernel_type_str_resolver.cc +++ b/onnxruntime/core/framework/kernel_type_str_resolver.cc @@ -171,56 +171,87 @@ Status KernelTypeStrResolver::SaveToOrtFormat( } #endif // !defined(ORT_MINIMAL_BUILD) -Status KernelTypeStrResolver::LoadFromOrtFormat(const fbs::KernelTypeStrResolver& fbs_kernel_type_str_resolver) { +// returns an error message string which is empty if successful +static std::string LoadFromOrtFormatImpl(const fbs::KernelTypeStrResolver& fbs_kernel_type_str_resolver, + OpKernelTypeStrMap& op_kernel_type_str_map_out) { const auto* fbs_op_kernel_type_str_args = fbs_kernel_type_str_resolver.op_kernel_type_str_args(); - ORT_FORMAT_RETURN_IF_NULL(fbs_op_kernel_type_str_args, "op_kernel_type_str_args"); + if (!fbs_op_kernel_type_str_args) { + return "op_kernel_type_str_args is null."; + } OpKernelTypeStrMap op_kernel_type_str_map{}; op_kernel_type_str_map.reserve(fbs_op_kernel_type_str_args->size()); for (const auto* fbs_op_kernel_type_str_args_entry : *fbs_op_kernel_type_str_args) { - ORT_FORMAT_RETURN_IF_NULL(fbs_op_kernel_type_str_args_entry, "op_kernel_type_str_args entry"); + if (!fbs_op_kernel_type_str_args_entry) { + return "op_kernel_type_str_args entry is null."; + } const auto* fbs_op_id = fbs_op_kernel_type_str_args_entry->op_id(); - ORT_FORMAT_RETURN_IF_NULL(fbs_op_id, "op_id"); + if (!fbs_op_id) { + return "op_id is null."; + } const auto* fbs_kernel_type_str_args = fbs_op_kernel_type_str_args_entry->kernel_type_str_args(); - ORT_FORMAT_RETURN_IF_NULL(fbs_kernel_type_str_args, "kernel_type_str_args"); + if (!fbs_kernel_type_str_args) { + return "kernel_type_str_args is null."; + } KernelTypeStrToArgsMap kernel_type_str_map{}; kernel_type_str_map.reserve(fbs_kernel_type_str_args->size()); for (const auto* fbs_kernel_type_str_args_entry : *fbs_kernel_type_str_args) { - ORT_FORMAT_RETURN_IF_NULL(fbs_kernel_type_str_args_entry, "kernel_type_str_args entry"); + if (!fbs_kernel_type_str_args_entry) { + return "kernel_type_str_args entry is null."; + } const auto* fbs_kernel_type_str = fbs_kernel_type_str_args_entry->kernel_type_str(); - ORT_FORMAT_RETURN_IF_NULL(fbs_kernel_type_str, "kernel_type_str"); + if (!fbs_kernel_type_str) { + return "kernel_type_str is null."; + } const auto* fbs_args = fbs_kernel_type_str_args_entry->args(); - ORT_FORMAT_RETURN_IF_NULL(fbs_args, "args"); + if (!fbs_args) { + return "args is null."; + } InlinedVector args{}; args.reserve(fbs_args->size()); for (const auto* fbs_arg : *fbs_args) { - ORT_FORMAT_RETURN_IF_NULL(fbs_arg, "args entry"); + if (!fbs_arg) { + return "args entry is null."; + } args.push_back(ArgTypeAndIndex{ fbs_arg->arg_type() == fbs::ArgType::INPUT ? ArgType::kInput : ArgType::kOutput, fbs_arg->index()}); } const auto [it, inserted] = kernel_type_str_map.try_emplace(fbs_kernel_type_str->str(), std::move(args)); - ORT_RETURN_IF_NOT(inserted, "Duplicate entry for kernel type str: ", it->first, ". ", - fbs::utils::kInvalidOrtFormatModelMessage); + if (!inserted) { + return MakeString("Duplicate entry for kernel type str: ", it->first, "."); + } } OpIdentifier op_id; - ORT_RETURN_IF_ERROR(fbs::utils::LoadOpIdentifierOrtFormat(*fbs_op_id, op_id)); + const auto load_op_id_status = fbs::utils::LoadOpIdentifierOrtFormat(*fbs_op_id, op_id); + if (!load_op_id_status.IsOK()) { + return load_op_id_status.ErrorMessage(); + } + const auto [it, inserted] = op_kernel_type_str_map.try_emplace(std::move(op_id), std::move(kernel_type_str_map)); - ORT_RETURN_IF_NOT(inserted, "Duplicate entry for op id: ", it->first, ". ", - fbs::utils::kInvalidOrtFormatModelMessage); + if (!inserted) { + return MakeString("Duplicate entry for op id: ", it->first, "."); + } } - op_kernel_type_str_map_ = std::move(op_kernel_type_str_map); - return Status::OK(); + op_kernel_type_str_map_out = std::move(op_kernel_type_str_map); + return ""; +} + +Status KernelTypeStrResolver::LoadFromOrtFormat(const fbs::KernelTypeStrResolver& fbs_kernel_type_str_resolver) { + const auto error_message = LoadFromOrtFormatImpl(fbs_kernel_type_str_resolver, op_kernel_type_str_map_); + return error_message.empty() ? Status::OK() + : ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, error_message, " ", + fbs::utils::kInvalidOrtFormatModelMessage); } void KernelTypeStrResolver::Merge(KernelTypeStrResolver src) {