From 9e97d7ef1ad30200c5ca404697a081e4d413a65e Mon Sep 17 00:00:00 2001 From: River Li Date: Tue, 31 Oct 2023 13:53:47 +0800 Subject: [PATCH] [C-API] add ov_get_last_error_msg() API (#20643) --- src/bindings/c/include/openvino/c/ov_common.h | 7 ++++ src/bindings/c/src/common.h | 12 ++++--- src/bindings/c/src/ov_core.cpp | 20 +++++++++++ src/bindings/c/tests/ov_core_test.cpp | 34 +++++++++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/bindings/c/include/openvino/c/ov_common.h b/src/bindings/c/include/openvino/c/ov_common.h index faf9369050c839..bbbf3dd35c2db1 100644 --- a/src/bindings/c/include/openvino/c/ov_common.h +++ b/src/bindings/c/include/openvino/c/ov_common.h @@ -204,3 +204,10 @@ ov_get_error_info(ov_status_e status); */ OPENVINO_C_API(void) ov_free(const char* content); + +/** + * @brief Get the last error msg. + * @ingroup ov_base_c_api + */ +OPENVINO_C_API(const char*) +ov_get_last_err_msg(); \ No newline at end of file diff --git a/src/bindings/c/src/common.h b/src/bindings/c/src/common.h index ff2e0bcac07312..50784981d1c430 100644 --- a/src/bindings/c/src/common.h +++ b/src/bindings/c/src/common.h @@ -14,13 +14,15 @@ #include "openvino/core/except.hpp" #include "openvino/openvino.hpp" -#define CATCH_IE_EXCEPTION(StatusCode, ExceptionType) \ - catch (const InferenceEngine::ExceptionType&) { \ - return ov_status_e::StatusCode; \ +#define CATCH_IE_EXCEPTION(StatusCode, ExceptionType) \ + catch (const InferenceEngine::ExceptionType& ex) { \ + dup_last_err_msg(ex.what()); \ + return ov_status_e::StatusCode; \ } #define CATCH_OV_EXCEPTION(StatusCode, ExceptionType) \ - catch (const ov::ExceptionType&) { \ + catch (const ov::ExceptionType& ex) { \ + dup_last_err_msg(ex.what()); \ return ov_status_e::StatusCode; \ } @@ -41,6 +43,7 @@ CATCH_IE_EXCEPTION(NETWORK_NOT_READ, NetworkNotRead) \ CATCH_IE_EXCEPTION(INFER_CANCELLED, InferCancelled) \ catch (...) { \ + dup_last_err_msg("An unknown exception occurred"); \ return ov_status_e::UNKNOW_EXCEPTION; \ } @@ -224,3 +227,4 @@ struct mem_istream : virtual mem_stringbuf, std::istream { char* str_to_char_array(const std::string& str); ov::element::Type get_element_type(ov_element_type_e type); +void dup_last_err_msg(const char* msg); diff --git a/src/bindings/c/src/ov_core.cpp b/src/bindings/c/src/ov_core.cpp index 6e292dc7abf331..2624b93d8d0b28 100644 --- a/src/bindings/c/src/ov_core.cpp +++ b/src/bindings/c/src/ov_core.cpp @@ -17,6 +17,22 @@ char* str_to_char_array(const std::string& str) { return char_array; } +static std::string last_err_msg; +static std::mutex last_msg_mutex; +void dup_last_err_msg(const char* msg) { + std::lock_guard lock(last_msg_mutex); + last_err_msg = std::string(msg); +} + +const char* ov_get_last_err_msg() { + std::lock_guard lock(last_msg_mutex); + char* res = nullptr; + if (!last_err_msg.empty()) { + res = str_to_char_array(last_err_msg); + } + return res; +} + ov_status_e ov_get_openvino_version(ov_version_t* version) { if (!version) { return ov_status_e::INVALID_C_PARAM; @@ -66,6 +82,10 @@ ov_status_e ov_core_create(ov_core_t** core) { void ov_core_free(ov_core_t* core) { if (core) delete core; + + // release err msg buffer, there will be no err msg after core is freed. + std::lock_guard lock(last_msg_mutex); + last_err_msg.clear(); } ov_status_e ov_core_read_model(const ov_core_t* core, diff --git a/src/bindings/c/tests/ov_core_test.cpp b/src/bindings/c/tests/ov_core_test.cpp index 5e116e7326d34e..90ed036cec32b4 100644 --- a/src/bindings/c/tests/ov_core_test.cpp +++ b/src/bindings/c/tests/ov_core_test.cpp @@ -33,6 +33,7 @@ class ov_core_test : public ov_capi_test_base { ov_capi_test_base::TearDown(); } }; + INSTANTIATE_TEST_SUITE_P(ov_core, ov_core_test, ::testing::Values("CPU")); TEST_P(ov_core_test, ov_core_create_with_config) { @@ -699,4 +700,37 @@ TEST_P(ov_core_test, ov_core_compile_model_from_file_unicode) { } #endif +using ov_util_test = ov_core_test; +INSTANTIATE_TEST_SUITE_P(ov_capi_test, ov_util_test, ::testing::Values("CPU")); + +TEST_P(ov_util_test, ov_get_last_err_msg_check) { + auto device_name = GetParam(); + ov_core_t* core = nullptr; + OV_EXPECT_OK(ov_core_create(&core)); + EXPECT_NE(nullptr, core); + + const char* key = ov_property_key_inference_num_threads; + OV_EXPECT_OK(ov_core_set_property(core, device_name.c_str(), key, "abc")); + + char* ret = nullptr; + OV_EXPECT_NOT_OK(ov_core_get_property(core, device_name.c_str(), key, &ret)); + + auto err_msg = ov_get_last_err_msg(); + EXPECT_NE(nullptr, err_msg); + ov_free(err_msg); + ov_free(ret); + ov_core_free(core); +} + +TEST_P(ov_util_test, ov_get_last_err_msg_check_empty_msg) { + auto device_name = GetParam(); + ov_core_t* core = nullptr; + OV_EXPECT_OK(ov_core_create(&core)); + EXPECT_NE(nullptr, core); + + auto err_msg = ov_get_last_err_msg(); + EXPECT_EQ(nullptr, err_msg); + ov_core_free(core); +} + } // namespace