Skip to content

Report import failure error code #715

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: ovep-develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 7 additions & 29 deletions onnxruntime/core/providers/openvino/backend_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "core/providers/openvino/ov_interface.h"
#include "core/providers/openvino/ov_versions/capability.h"
#include "core/providers/openvino/qdq_transformations/qdq_stripping.h"
#include "core/providers/openvino/exceptions.h"

namespace onnxruntime {
namespace openvino_ep {
Expand Down Expand Up @@ -144,15 +145,13 @@
subgraph_context_,
shared_context_,
model_stream);
} catch (const OnnxRuntimeException& ex) {
std::string exception_str = ex.what();
} catch (const ovep_exception& ex) {
#ifndef OPENVINO_DISABLE_NPU_FALLBACK
bool eligible_for_cpu_fallback = device_type.find("NPU") != std::string::npos &&
!session_context_.so_disable_cpu_ep_fallback &&
!subgraph_context_.is_ep_ctx_graph;
#if defined(OPENVINO_DISABLE_NPU_FALLBACK)
eligible_for_cpu_fallback = false;
#else
if (eligible_for_cpu_fallback) {
std::string exception_str = ex.what();
LOGS_DEFAULT(VERBOSE) << exception_str;
LOGS_DEFAULT(WARNING) << "Model compilation failed at OV NPU."
<< "Falling back to OV CPU for execution";
Expand All @@ -167,31 +166,10 @@
} catch (std::string const& msg) {
ORT_THROW(msg);
}
}
} else

Check notice on line 169 in onnxruntime/core/providers/openvino/backend_manager.cc

View workflow job for this annotation

GitHub Actions / cpplint

[cpplint] onnxruntime/core/providers/openvino/backend_manager.cc#L169

If an else has a brace on one side, it should have it on both [readability/braces] [5]
Raw output
onnxruntime/core/providers/openvino/backend_manager.cc:169:  If an else has a brace on one side, it should have it on both  [readability/braces] [5]
#endif
if (!eligible_for_cpu_fallback) {
if (device_type.find("NPU") != std::string::npos &&
exception_str.find("intel_npu") != std::string::npos) {
// Handle NPU device related errors
#ifndef NDEBUG
ORT_THROW(exception_str + "\nModel needs to be recompiled\n");
#else
std::string error_message = "UNKNOWN NPU ERROR";
std::string error_code = "code 0x0";
std::regex error_message_pattern(R"(\bZE_\w*\b)");
std::regex error_code_pattern("code 0x[0-9a-fA-F]+");
std::smatch matches;
if (std::regex_search(exception_str, matches, error_message_pattern)) {
error_message = matches[0];
}
if (std::regex_search(exception_str, matches, error_code_pattern)) {
error_code = matches[0];
}
throw std::runtime_error(error_message + ", " + error_code + "\nModel needs to be recompiled\n");
#endif
} else {
ORT_THROW(exception_str);
}
{
throw ex;
}
}
}
Expand Down
82 changes: 82 additions & 0 deletions onnxruntime/core/providers/openvino/exceptions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (C) Intel Corporation
// Licensed under the MIT License

#pragma once

#include <exception>
#include <regex>
#include <string>

#include "core/common/status.h"

namespace onnxruntime {
namespace openvino_ep {

struct ovep_exception : public std::exception {
enum class type {
compile_model,
import_model,
query_prop,
read_model,
unknown,
};

ovep_exception(const std::string& message,
enum class type type) : message_{message},
type_{type},
error_code_{ze_result_code_from_string(message)},
error_name_{ze_result_name_from_string(message)} {}

const char* what() const noexcept override {
return message_.data();
}

uint32_t get_code() const { return error_code_; }

operator common::Status() const {
common::StatusCategory category_ort{common::ONNXRUNTIME};

if (type_ == type::unknown) {
return {category_ort, common::FAIL, message_};
}

// Newer drivers
if ((type_ == type::import_model) &&
(error_code_ == 0x7800000f /* ZE_RESULT_ERROR_INVALID_NATIVE_BINARY */)) {
std::string message{error_name_ + ", code 0x" + std::to_string(error_code_) + "\nModel needs to be recompiled\n"};
return {category_ort, common::INVALID_GRAPH, message};
}

std::string error_message = "Unhandled exception type: " + std::to_string(static_cast<int>(type_));
return {category_ort, common::FAIL, error_message};
}

protected:
std::string message_;
type type_{type::unknown};
uint32_t error_code_{0};
std::string error_name_;

private:
uint32_t ze_result_code_from_string(const std::string& ov_exception_string) {
uint32_t error_code{0};
std::regex error_code_pattern("code 0x([0-9a-fA-F]+)");
std::smatch matches;
if (std::regex_search(ov_exception_string, matches, error_code_pattern)) {
std::from_chars(&(*matches[1].first), &(*matches[1].second), error_code, 16);
}
return error_code;
}
std::string ze_result_name_from_string(const std::string& ov_exception_string) {
std::string error_message = "UNKNOWN NPU ERROR";
std::regex error_message_pattern(R"(\bZE_\w*\b)");
std::smatch matches;
if (std::regex_search(ov_exception_string, matches, error_message_pattern)) {
error_message = matches[0];
}
return error_message;
}
};

} // namespace openvino_ep
} // namespace onnxruntime
173 changes: 89 additions & 84 deletions onnxruntime/core/providers/openvino/openvino_execution_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "core/providers/openvino/onnx_ctx_model_helper.h"
#include "core/providers/openvino/ov_versions/capability.h"
#include "core/providers/openvino/qdq_transformations/qdq_stripping.h"
#include "core/providers/openvino/exceptions.h"
#include "core/session/onnxruntime_session_options_config_keys.h"
#include "openvino/core/version.hpp"
#ifdef USE_OVEP_NPU_MEMORY
Expand Down Expand Up @@ -94,101 +95,105 @@ common::Status OpenVINOExecutionProvider::Compile(
auto& logger = *GetLogger();
Status status = Status::OK();

if (!fused_nodes.empty()) {
// Assume these properties are constant for all the model subgraphs, otherwise move to SubGraphContext
const auto& graph_body_viewer_0 = fused_nodes[0].filtered_graph.get();
session_context_.onnx_model_path_name = graph_body_viewer_0.ModelPath().string();
session_context_.onnx_opset_version =
graph_body_viewer_0.DomainToVersionMap().at(kOnnxDomain);
}

// Temporary code to read metadata before it moves to the .bin
auto& metadata = shared_context_->shared_weights.metadata;
if (session_context_.so_share_ep_contexts && metadata.empty()) {
// Metadata is always read from model location, this could be a source or epctx model
fs::path metadata_filename = session_context_.onnx_model_path_name.parent_path() / "metadata.bin";
std::ifstream file(metadata_filename, std::ios::binary);
if (file) {
file >> metadata;
try {
if (!fused_nodes.empty()) {
// Assume these properties are constant for all the model subgraphs, otherwise move to SubGraphContext
const auto& graph_body_viewer_0 = fused_nodes[0].filtered_graph.get();
session_context_.onnx_model_path_name = graph_body_viewer_0.ModelPath().string();
session_context_.onnx_opset_version =
graph_body_viewer_0.DomainToVersionMap().at(kOnnxDomain);
}
}

struct OpenVINOEPFunctionState {
AllocateFunc allocate_func = nullptr;
DestroyFunc destroy_func = nullptr;
AllocatorHandle allocator_handle = nullptr;
BackendManager& backend_manager;
};

for (const FusedNodeAndGraph& fused_node_graph : fused_nodes) {
const GraphViewer& graph_body_viewer = fused_node_graph.filtered_graph;
const Node& fused_node = fused_node_graph.fused_node;

NodeComputeInfo compute_info;

// During backend creation, we check if user wants to use precompiled blob onnx model or the original model
// For precompiled blob, directly load the model instead of compiling the model
// For original model, check if the user wants to export a model with pre-compiled blob

auto& backend_manager = backend_managers_.emplace_back(session_context_,
*shared_context_,
fused_node,
graph_body_viewer,
logger,
ep_ctx_handle_);

compute_info.create_state_func =
[&backend_manager](ComputeContext* context, FunctionState* state) {
OpenVINOEPFunctionState* p = new OpenVINOEPFunctionState{
.allocate_func = context->allocate_func,
.destroy_func = context->release_func,
.allocator_handle = context->allocator_handle,
.backend_manager = backend_manager};
*state = static_cast<FunctionState>(p);
return 0;
};

compute_info.compute_func = [](FunctionState state, const OrtApi* /* api */, OrtKernelContext* context) {
auto function_state = static_cast<OpenVINOEPFunctionState*>(state);
try {
function_state->backend_manager.Compute(context);
} catch (const std::exception& ex) {
return common::Status(common::ONNXRUNTIME, common::FAIL, ex.what());
// Temporary code to read metadata before it moves to the .bin
auto& metadata = shared_context_->shared_weights.metadata;
if (session_context_.so_share_ep_contexts && metadata.empty()) {
// Metadata is always read from model location, this could be a source or epctx model
fs::path metadata_filename = session_context_.onnx_model_path_name.parent_path() / "metadata.bin";
std::ifstream file(metadata_filename, std::ios::binary);
if (file) {
file >> metadata;
}
return Status::OK();
}

struct OpenVINOEPFunctionState {
AllocateFunc allocate_func = nullptr;
DestroyFunc destroy_func = nullptr;
AllocatorHandle allocator_handle = nullptr;
BackendManager& backend_manager;
};

compute_info.release_state_func =
[](FunctionState state) {
if (state) {
OpenVINOEPFunctionState* function_state = static_cast<OpenVINOEPFunctionState*>(state);
delete function_state;
}
};
for (const FusedNodeAndGraph& fused_node_graph : fused_nodes) {
const GraphViewer& graph_body_viewer = fused_node_graph.filtered_graph;
const Node& fused_node = fused_node_graph.fused_node;

NodeComputeInfo compute_info;

// During backend creation, we check if user wants to use precompiled blob onnx model or the original model
// For precompiled blob, directly load the model instead of compiling the model
// For original model, check if the user wants to export a model with pre-compiled blob

auto& backend_manager = backend_managers_.emplace_back(session_context_,
*shared_context_,
fused_node,
graph_body_viewer,
logger,
ep_ctx_handle_);

compute_info.create_state_func =
[&backend_manager](ComputeContext* context, FunctionState* state) {
OpenVINOEPFunctionState* p = new OpenVINOEPFunctionState{
.allocate_func = context->allocate_func,
.destroy_func = context->release_func,
.allocator_handle = context->allocator_handle,
.backend_manager = backend_manager};
*state = static_cast<FunctionState>(p);
return 0;
};

compute_info.compute_func = [](FunctionState state, const OrtApi* /* api */, OrtKernelContext* context) {
auto function_state = static_cast<OpenVINOEPFunctionState*>(state);
try {
function_state->backend_manager.Compute(context);
} catch (const std::exception& ex) {
return common::Status(common::ONNXRUNTIME, common::FAIL, ex.what());
}
return Status::OK();
};

node_compute_funcs.push_back(std::move(compute_info));
compute_info.release_state_func =
[](FunctionState state) {
if (state) {
OpenVINOEPFunctionState* function_state = static_cast<OpenVINOEPFunctionState*>(state);
delete function_state;
}
};

if (!status.IsOK()) {
break;
}
}
node_compute_funcs.push_back(std::move(compute_info));

if (session_context_.so_share_ep_contexts) {
fs::path metadata_filename;
if (session_context_.so_context_file_path.empty()) {
metadata_filename = session_context_.onnx_model_path_name.parent_path() / "metadata.bin";
} else {
metadata_filename = session_context_.so_context_file_path.parent_path() / "metadata.bin";
if (!status.IsOK()) {
break;
}
}

// Metadata is generated only for shared contexts
// If saving metadata then save it to the provided path or ose the original model path
// Multiple calls to Compile() will update the metadata and for the last call
// the resulting file will contain the aggregated content
std::ofstream file(metadata_filename, std::ios::binary);
if (file) {
file << metadata;
if (session_context_.so_share_ep_contexts) {
fs::path metadata_filename;
if (session_context_.so_context_file_path.empty()) {
metadata_filename = session_context_.onnx_model_path_name.parent_path() / "metadata.bin";
} else {
metadata_filename = session_context_.so_context_file_path.parent_path() / "metadata.bin";
}

// Metadata is generated only for shared contexts
// If saving metadata then save it to the provided path or ose the original model path
// Multiple calls to Compile() will update the metadata and for the last call
// the resulting file will contain the aggregated content
std::ofstream file(metadata_filename, std::ios::binary);
if (file) {
file << metadata;
}
}
} catch (const ovep_exception& ex) {
status = ex;
}

return status;
Expand Down
Loading
Loading