mirror of
https://github.com/opencv/opencv.git
synced 2025-06-10 11:03:03 +08:00
Merge pull request #21579 from TolyaTalamanov:at/handle-errors-in-iebackend
[G-API] Handle errors in IEBackend & modeling tool * Handle errors in IEBackend & modeling tool * Handle exceptions in callback * Add const cv to exception
This commit is contained in:
parent
3eeec4faae
commit
619b6dfae3
@ -379,10 +379,15 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
// NB: Execute pipelines
|
||||
std::vector<std::exception_ptr> eptrs(pipelines.size(), nullptr);
|
||||
std::vector<std::thread> threads(pipelines.size());
|
||||
for (size_t i = 0; i < pipelines.size(); ++i) {
|
||||
threads[i] = std::thread([&, i]() {
|
||||
pipelines[i]->run(work_time_ms);
|
||||
try {
|
||||
pipelines[i]->run(work_time_ms);
|
||||
} catch (...) {
|
||||
eptrs[i] = std::current_exception();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -393,12 +398,22 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
for (size_t i = 0; i < threads.size(); ++i) {
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < threads.size(); ++i) {
|
||||
if (eptrs[i] != nullptr) {
|
||||
try {
|
||||
std::rethrow_exception(eptrs[i]);
|
||||
} catch (std::exception& e) {
|
||||
throw std::logic_error(pipelines[i]->name() + " failed: " + e.what());
|
||||
}
|
||||
}
|
||||
if (file.is_open()) {
|
||||
file << pipelines[i]->report().toStr(true) << std::endl;
|
||||
}
|
||||
std::cout << pipelines[i]->report().toStr() << std::endl;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
} catch (const std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
throw;
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ public:
|
||||
void compile();
|
||||
void run(double work_time_ms);
|
||||
const PerfReport& report() const;
|
||||
const std::string& name() const { return m_name;}
|
||||
|
||||
virtual ~Pipeline() = default;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
// Copyright (C) 2018-2022 Intel Corporation
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
@ -216,6 +216,39 @@ inline void copyFromIE(const IE::Blob::Ptr &blob, MatType &mat) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename MapT>
|
||||
void checkLayerNames(const MapT& network_map,
|
||||
const std::vector<std::string>& layer_names,
|
||||
const std::string& layer_type) {
|
||||
for (const auto& layer_name : layer_names) {
|
||||
const auto it = network_map.find(layer_name);
|
||||
if (it == network_map.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "Failed to find " << layer_type << " layer with name: "
|
||||
<< "\"" << layer_name << "\"" << std::endl;
|
||||
ss << "Network " << layer_type << " layers: " << std::endl;
|
||||
for (const auto& p : network_map) {
|
||||
const auto& desc = p.second->getTensorDesc();
|
||||
ss << p.first << " : " << desc.getPrecision()
|
||||
<< " / " << desc.getLayout() << std::endl;
|
||||
}
|
||||
throw std::logic_error(ss.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename MapT>
|
||||
void checkInputLayerNames(const MapT& network_map,
|
||||
const std::vector<std::string>& layer_names) {
|
||||
checkLayerNames(network_map, layer_names, "input");
|
||||
}
|
||||
|
||||
template <typename MapT>
|
||||
void checkOutputLayerNames(const MapT& network_map,
|
||||
const std::vector<std::string>& layer_names) {
|
||||
checkLayerNames(network_map, layer_names, "output");
|
||||
}
|
||||
|
||||
// IE-specific metadata, represents a network with its parameters
|
||||
struct IEUnit {
|
||||
static const char *name() { return "IEModelConfig"; }
|
||||
@ -293,6 +326,16 @@ struct IEUnit {
|
||||
params.num_in &&
|
||||
"Number of layers to reshape must be less than or equal to number of inputs");
|
||||
}
|
||||
|
||||
if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
|
||||
checkInputLayerNames(net.getInputsInfo(), params.input_names);
|
||||
checkOutputLayerNames(net.getOutputsInfo(), params.output_names);
|
||||
} else if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import) {
|
||||
checkInputLayerNames(this_network.GetInputsInfo(), params.input_names);
|
||||
checkOutputLayerNames(this_network.GetOutputsInfo(), params.output_names);
|
||||
} else {
|
||||
cv::util::throw_error(std::logic_error("Unsupported ParamDesc::Kind"));
|
||||
}
|
||||
}
|
||||
|
||||
// This method is [supposed to be] called at Island compilation stage
|
||||
@ -627,7 +670,10 @@ public:
|
||||
void waitAll();
|
||||
|
||||
private:
|
||||
void callback(Task task, InferenceEngine::InferRequest& request, size_t id);
|
||||
void callback(Task task,
|
||||
size_t id,
|
||||
IE::InferRequest request,
|
||||
IE::StatusCode code);
|
||||
void setup();
|
||||
|
||||
QueueClass<size_t> m_idle_ids;
|
||||
@ -652,21 +698,38 @@ void cv::gimpl::ie::RequestPool::execute(cv::gimpl::ie::RequestPool::Task&& t) {
|
||||
|
||||
auto& request = m_requests[id];
|
||||
|
||||
using namespace std::placeholders;
|
||||
using callback_t = std::function<void(IE::InferRequest, IE::StatusCode)>;
|
||||
request.SetCompletionCallback(
|
||||
std::bind(&cv::gimpl::ie::RequestPool::callback, this, t, std::ref(request), id));
|
||||
static_cast<callback_t>(
|
||||
std::bind(&cv::gimpl::ie::RequestPool::callback, this,
|
||||
t, id, _1, _2)));
|
||||
t.run(request);
|
||||
}
|
||||
|
||||
void cv::gimpl::ie::RequestPool::callback(cv::gimpl::ie::RequestPool::Task task,
|
||||
InferenceEngine::InferRequest& request,
|
||||
size_t id) {
|
||||
task.callback(request);
|
||||
// NB: IE::InferRequest keeps the callback until the new one is set.
|
||||
// Since user's callback might keep resources that should be released,
|
||||
// need to destroy its after execution.
|
||||
// Let's set the empty one to cause the destruction of a callback.
|
||||
request.SetCompletionCallback([](){});
|
||||
m_idle_ids.push(id);
|
||||
size_t id,
|
||||
IE::InferRequest request,
|
||||
IE::StatusCode code) {
|
||||
// FIXME: Any exception which is arrised here must not leave this callback,
|
||||
// because it won't be handled.
|
||||
try {
|
||||
if (code != IE::StatusCode::OK) {
|
||||
throw std::logic_error("IE::InferRequest finished with not OK status");
|
||||
}
|
||||
task.callback(request);
|
||||
// NB: IE::InferRequest keeps the callback until the new one is set.
|
||||
// Since user's callback might keep resources that should be released,
|
||||
// need to destroy its after execution.
|
||||
// Let's set the empty one to cause the destruction of a callback.
|
||||
request.SetCompletionCallback([](){});
|
||||
m_idle_ids.push(id);
|
||||
} catch (const std::exception& e) {
|
||||
GAPI_LOG_FATAL(NULL, "Callback failed with error: " << e.what());
|
||||
//FIXME: Exception CAN't be rethrown here, since this callback works
|
||||
// in separate IE thread and such scenarios aren't handled properly in
|
||||
// G-API so far.
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Not thread-safe.
|
||||
|
@ -14,10 +14,12 @@
|
||||
# define GAPI_LOG_INFO(tag, ...) CV_LOG_INFO(tag, __VA_ARGS__)
|
||||
# define GAPI_LOG_WARNING(tag, ...) CV_LOG_WARNING(tag, __VA_ARGS__)
|
||||
# define GAPI_LOG_DEBUG(tag, ...) CV_LOG_DEBUG(tag, __VA_ARGS__)
|
||||
# define GAPI_LOG_FATAL(tag, ...) CV_LOG_FATAL(tag, __VA_ARGS__)
|
||||
#else
|
||||
# define GAPI_LOG_INFO(tag, ...)
|
||||
# define GAPI_LOG_WARNING(tag, ...)
|
||||
# define GAPI_LOG_DEBUG(tag, ...)
|
||||
# define GAPI_LOG_FATAL(tag, ...)
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user